Java泛型参数如何在被重写的方法中工作?

Java泛型参数如何在被重写的方法中工作?,java,generics,Java,Generics,我有两门课 A.java add()方法会编译,但是addWithParam会产生一个错误,说明addWithParam(B)必须重写一个更高类中的方法(在本场景中为a)。修复方法是完全丢失覆盖注释,但我的意图是强制用户覆盖类B中的方法,并返回类型为B的对象 我只能想出两种方法来解决这个问题。第一种解决方案是将返回类型从泛型类型T设置为A。这将允许我返回类型A,但是用户必须将返回结果从B.addWithParam(B)转换为类型B,这正是我试图避免的 另一个解决方案是将抽象方法的可见性从publ

我有两门课

A.java
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) { ... }
}