我有一个父类Parent
和两个子类A
和B
。我还有另一个类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());
}
}
编辑:
我的问题在建议重复项的范围和实施方面是独一无二的。例如,我的代码结构是具有两个兄弟子类的简单父级。可能的重复项中的结构更加复杂,涉及多个世代和以混乱方式分散的子类。我不确定该代码正在尝试做什么,答案似乎丝毫不影响其他问题的独特结构,因此答案丝毫没有帮助我理解我自己的问题。
答案 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)
之类的构造函数会导致这些类之间的循环依赖。 A
和B
不是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());
}
如果A
和B
具有不同的字段,则最后一种方法也适用。如果B
有一个字段String value4
,我们可以像transformToB
一样向b.setValue4(a.getValue3()+"#"+a.getValue2());
添加一行。