Java泛型参数如何在被重写的方法中工作?
我有两门课 A.javaJava泛型参数如何在被重写的方法中工作?,java,generics,Java,Generics,我有两门课 A.java add()方法会编译,但是addWithParam会产生一个错误,说明addWithParam(B)必须重写一个更高类中的方法(在本场景中为a)。修复方法是完全丢失覆盖注释,但我的意图是强制用户覆盖类B中的方法,并返回类型为B的对象 我只能想出两种方法来解决这个问题。第一种解决方案是将返回类型从泛型类型T设置为A。这将允许我返回类型A,但是用户必须将返回结果从B.addWithParam(B)转换为类型B,这正是我试图避免的 另一个解决方案是将抽象方法的可见性从publ
add()
方法会编译,但是addWithParam
会产生一个错误,说明addWithParam(B)必须重写一个更高类中的方法(在本场景中为a)。修复方法是完全丢失覆盖注释,但我的意图是强制用户覆盖类B
中的方法,并返回类型为B
的对象
我只能想出两种方法来解决这个问题。第一种解决方案是将返回类型从泛型类型T
设置为A
。这将允许我返回类型A
,但是用户必须将返回结果从B.addWithParam(B)
转换为类型B,这正是我试图避免的
另一个解决方案是将抽象方法的可见性从public更改为protected(在A.java
中)。在前面提到的解决方案中,我将返回类型更改为A
,A
的继承类创建了一个方法,该方法返回(B)B.addWithParam(B param)
(请记住B.addWithParam(B param)
返回超类指定的类型A
)
所以这里的问题是,为什么会产生原始错误?我只是写错了代码,还是Java直接不支持我要实现的目标
public abstract <T extends A> T add();
你不是这个意思。相信我
public abstract A add();
这意味着在任何A
上调用add()
至少会使您返回A
,并且A
的子类型可以更详细地指定它们返回的确切类型,以便您可以编写
class B extends A {
public B add() { ... }
}
那更合理一点。这不允许您指定addWithParam
方法只接受B
,而不接受另一种a
类型
没有任何方法可以强制子类返回其自身类型的实例。有各种各样的技巧和提示,人们使用这些技巧和提示来实现不同程度的有效性,例如:
class A<T extends A> {
abstract T add();
abstract T addWithParam(T t);
}
class B extends A<B> {
B add() { ... }
B addWithParam(B b) { ... }
}
A类{
抽象T add();
抽象T addWithParam(T T);
}
B类扩展了A类{
B add(){…}
B addWithParam(B){…}
}
这至少和你想做的一样。它不会阻止某人编写
类C扩展编译器错误的直接原因是在抽象类中,在运行时,addWithParam()
方法将对象作为输入,并返回对象。在您的覆盖版本中(实际上并没有真正覆盖),您将以具体的<代码> b>代码>类型作为输入,然后返回<代码> b>代码>类型。@ TimiGeeleSeEN:反例:考虑代码< >代码< A/COD>被称为<代码>类A<代码>的情况,该方法是“代码> T AddiaPayAM(t PARAM)而B
被声明为B类扩展了A
,B
的addWithParam
是B addWithParam(B param)
。您的前提也适用于这种情况——在运行时,A
的addWithParam
接受对象并返回对象,在覆盖版本中,它接受B
并返回B
——因此根据您的逻辑,它应该是无效的。然而,这个案例是完全正确的,我同意你的回答,但我不会把它称为你所说的有效解决方案的黑客攻击。当我们编写接口/类时,我们声明无论您放置什么来代替泛型类型,都将在该方法中返回。如果我选择将<代码> XYZ 作为泛型类型,我希望得到从这种方法返回的。我认为它是一个黑客,正是因为它不能保证<代码> T >代码>实际上是“自”类型;正如我所说,您仍然可以编写C扩展A
,这违反了设计的意图。我同意,不可能强制使用与问题中所问泛型类型相同的类,但要了解java框架中的约束/限制,没有人会对类C扩展A
的情况感到惊讶。虽然它可能不是在所有情况下都有意义。谢谢你的输入!我正在考虑将超级返回类型更改为仅A
,但这会导致有人编写C.addWithParam(A)
返回B
类型的内容。无论哪种方式,这两种解决方案最终都将依赖于用户返回预期类型。再次感谢!
public abstract A add();
class B extends A {
public B add() { ... }
}
class A<T extends A> {
abstract T add();
abstract T addWithParam(T t);
}
class B extends A<B> {
B add() { ... }
B addWithParam(B b) { ... }
}