如何使用泛型类型的构造函数/铸造

时间:2018-10-04 05:09:00

标签: java generics inheritance constructor casting

我有一个父类Parent和两个子类AB。我还有另一个类Wrapper<Type1,Type2>,它包含一个接口Function<Type1,Type2>,该接口应该将A转换为B或将B转换为A。

如果我定义

new Wrapper<A,B>(new Function<A,B>(){public B transform(A a){return new B(a);}});

Wrapper类之外,则可以正常工作。

当我想为Function类本身内的默认构造函数public Wrapper()定义默认Wrapper<Type1,Type2>时,遇到了无法实例化泛型的问题。

Eclipse建议从Type1强制转换为Type2,但是问题是A无法转换为B,因为它们是同级类。我确实有Parent(Parent)A(B)B(A)的构造函数,所以如果我能以某种方式实现泛型构造函数,那就太好了。我该如何解决?

public class Parent {
    protected int value = 0;
    public void setValue(int x){ value = x; }
    public int getValue(){ return value; }
    public Parent(){}
    public Parent(A a){setValue(a.getValue());}
    public Parent(B b){setValue(b.getValue());}
    public Parent(Parent p){setValue(p.getValue());}
}


public class A extends Parent{
    public A(){ setValue(1); }
    public A(B b){ setValue( b.getValue()); }
}

public class B extends Parent{
    public B(){ setValue(2); }
    public B(A a){ setValue(a.getValue()); }
}


public interface Function <Type1 extends Parent, Type2 extends Parent> {
    public Type2 transform(Type1 t);
}


public class Wrapper<Type1 extends Parent, Type2 extends Parent> {

    Function<Type1,Type2> function;
    public Wrapper(Function<Type1,Type2> x){ function = x; }
    public Wrapper(){
        function = new Function<Type1,Type2>(){
            public Type2 transform(Type1 t){
            ///I want to use constructor Type2(t), given that they both extend Parent
                //return new Type2( t);
                return (Type2) t; ///causes an error because can't cast from A to B
            }

        };
    }
    public Type2 transform(Type1 t){
        return function.transform(t);
    }
}


public class Main {
    public static void main(String[] args){
        ///Start with custom function. This part works.
        Wrapper<A,B> wrapper = new Wrapper<A,B>(
            new Function<A,B>(){
                public B transform(A a){
                    ///Want to use constructor B(a)
                    ///Can't cast A to B
                    return new B(a);
                }
            }
        );
        A a = new A();
        B b = wrapper.transform(a);

        ///This part works
        System.out.println(b.getValue());

        ///Next try the default Function
        wrapper = new Wrapper<A,B>();
        b = wrapper.transform(a); ///This part causes the error, as wrapper attempts to cast from A to B
        System.out.println(b.getValue());


    }
}

编辑:

我的问题在建议重复项的范围和实施方面是独一无二的。例如,我的代码结构是具有两个兄弟子类的简单父级。可能的重复项中的结构更加复杂,涉及多个世代和以混乱方式分散的子类。我不确定该代码正在尝试做什么,答案似乎丝毫不影响其他问题的独特结构,因此答案丝毫没有帮助我理解我自己的问题。

2 个答案:

答案 0 :(得分:2)

无法创建“通用”构造函数。该解决方案最接近您当前的实现,是实例化function中的对象。无论如何,这都是调用方的责任(在您的设计中),因此很容易:

Wrapper<A, B> wrapper = new Wrapper<A, B>((a) -> new B(a));

但是在调用默认Wrapper()构造函数的地方,您可以使调用者发送type1和type2的Class对象:

public Wrapper(Class<Type1> type1Class, Class<Type2> type2Class) {
    this.function = (object1) -> {
        try {
            return type2Class.getConstructor(type1Class).newInstance(object1);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    };
}

使用以上两种方法,您的主要方法将如下所示:

public static void main(String... args) {
    Wrapper<A, B> wrapper = new Wrapper<A, B>((a) -> new B(a));

    A a = new A();
    B b = wrapper.transform(a);

    System.out.println(b.getValue());

    wrapper = new Wrapper<A, B>(A.class, B.class);
    b = wrapper.transform(a);
    System.out.println(b.getValue());
}

并且此命令运行时没有任何类型转换错误。


上述lambda表达式的java1.7版本:

Wrapper<A, B> wrapper = new Wrapper<A, B>(new Function<A, B>() {
    @Override
    public B transform(A a) {
        return new B(a);
    }
});

并且:

this.function = new Function<Type1, Type2>() {

    @Override
    public Type2 transform(Type1 object1) {
        try {
            return type2Class.getConstructor(type1Class).newInstance(object1);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
};

答案 1 :(得分:1)

由于不可能使用泛型类型参数创建实例,因此我们必须解决该问题。从您正在使用的注释中读取内容时,我将答案限于Java 7。这是我的建议:

public interface Transform<P extends Parent> {

    P with(int value);

}

public static void main(String[] args) {
    Transform<B> transformToB = new Transform<B>() {

        @Override
        public B with(int value) {
            return new B(value);
        }

    };

    A a = new A();
    B b = transformToB.with(a.getValue());
    System.out.println(b.getValue());
}

它如何工作?
我们有一个接口Transform<P extends Parent>定义了方法with。此方法有一个参数。这是您定义的类的唯一字段。使用此值,方法必须返回扩展了P的某个Parent的实例。查看transformToB的实现,它通过调用构造函数B(由我添加)创建了一个B(int value)实例。

为什么要使用另一个构造函数?
声明B(A a)A(B b)之类的构造函数会导致这些类之间的循环依赖。 AB不是loosely coupled。声明仅使用value的构造函数,我们实例化状态,而不必知道此value的来源。

还要声明诸如Parent(A a)Parent(B b)之类的构造函数,从而将Parent的依赖项引入其子类。按照这种方法,Parent需要为每个子类提供一个构造函数。

可能的扩展名:
如果value只是许多其他字段的示例,我们不想定义像A(int value1, int value2, String value3, ...)这样的具有很多参数的构造函数。代替我们可以使用默认构造函数A()并进行如下转换:

interface Transform<From extends Parent, To extends Parent> {

    To from(From f);

}

public static void main(String[] args) {
    Transform<A, B> transformToB = new Transform<A, B>() {

        @Override
        public B from(A a) {
            B b = new B();
            b.setValue(a.getValue());
            b.setValue2(a.getValue2());
            b.setValue3(a.getValue3());

            return b;
        }

    };

    A a = new A();
    B b = transformToB.from(a);

    System.out.println(b.getValue());
}

如果AB具有不同的字段,则最后一种方法也适用。如果B有一个字段String value4,我们可以像transformToB一样向b.setValue4(a.getValue3()+"#"+a.getValue2());添加一行。