我有一个给出编译时错误的方法。
class Parent {
public abstract <T extends Parent> T copy();
}
和Child class
class Child extends parent{
public <T extends Parent> T copy() {
return new Child();
}
}
通过泛型我告诉类型橡皮擦我会返回子对象仍然不让我这样做。 有人对此有意见/解决方案吗?
我可以用下面给出的新方法解决我的问题。
class Parent {
public Parent copy(){
//some stuff
}
}
class Child extends Parent{
@Override
public Child copy(){
Child c = (Child) super.copy();//I want to avoid this type casting here.
}
}
所以上面的方法解决了我的问题,但如果我想使用父类复制方法并且想在Child类中做更多的东西,我必须在子进程中使用TYPE CAST。
所以考虑到两者,你有更好的解决问题的方法吗?
答案 0 :(得分:2)
问题在于,当您以这种方式声明方法时,您的泛型参数不会绑定到任何内容。编译器绑定T类型的唯一方法是在您调用方法的行中。例如,它将在以下调用中假定类型为Child:
Child c = copy();
现在,如果您的代码被编译器认为是合法的,并且您执行了类似以下的操作,会发生什么?
GrandChild g = copy();
在这种情况下,您将在运行时获得意外的ClassCastException,这正是泛型试图避免的。
请注意,即使您像其他人建议的那样转换为T,也会收到编译器警告,因为风险仍然存在。
以下替代方案在类型安全方面更好,但有点麻烦:
abstract class Parent<T extends Parent<T>> {
public abstract T copy();
}
class Child extends Parent<Child> {
public Child copy() {
return new Child();
}
}
答案 1 :(得分:1)
你不需要Generics来做你想做的事。
Java允许协变返回类型:
abstract class Parent {
protected int i;
public Parent(int i) {
this.i = i;
}
public abstract Parent copy();
}
public class Child extends Parent {
private int j;
public Child(int i, int j) {
super(i);
this.j = j;
}
@Override
public Child copy() {
return new Child(this.i, this.j);
}
}
详细介绍了这一点
编辑以响应OP添加到Q:
答案是你不要打电话给super.copy()
。您正在copy()
方法中实例化一个新对象,这意味着构造函数已经涉及。 Child
的构造函数将调用Parent
的构造函数。在Child
的{{1}}中,您只需调用copy()
构造函数即可。我编辑了上面的例子来说明我的意思。
答案 2 :(得分:0)
泛型允许程序员指定T
的类型。如果用户尝试类似
OtherChild child = <OtherChild>copy();
OtherChild extends Parent
,OtherChild
不是Child
,Java会期望copy()
返回T
或OtherChild
类型} 在这种情况下。由于OtherChild
不是Child
,因此会出现编译时错误。您可能希望尝试按照Nikolay的建议将返回值转换为T
,或者将其保留给最终用户并将copy()
的返回类型更改为Child
。
修改强>
如果要在问题中实现抽象方法,则需要使用强制转换方法;显然,在这里更改方法的返回类型是不可接受的。
答案 3 :(得分:-1)
您需要手动将结果投射到T,例如
public <T extends Parent> T copy() {
return (T) new Child();
}