import java.util.Collection;
public abstract class A {
public class R<T> { }
public abstract <X> R<X> get1();
public abstract <X> R<X> get2(Collection<String> p);
public abstract <X> R<X> get3(Collection<Integer> p);
public class B extends A {
@Override
public R<Object> get1() {
return null;
}
@Override
public R<Object> get2(Collection<String> p) {
return null;
}
@Override
public <Object> R<Object> get3(Collection<Integer> p) {
return null;
}
}
}
get1
方法工作正常,但get2
存在编译错误:
A.B类型的方法get2(Collection)必须覆盖或实现超类型方法
此错误仅出现在带有泛型的参数中。 get3
编译,但当然有警告:
类型参数Object隐藏类型Object
显然还有其他方法可以解决这个问题,但在我的理解中,这应该是一个合法的覆盖,我的问题更多是为什么会出现这个编译错误。提前谢谢!
修改
抱歉,我的例子不够明确。因此,这是一个新的回应你的答案的一些点。
public abstract class A {
public abstract class R<T> { }
public abstract <X> R<X> get();
public abstract <Y> R<Y> get2(Collection<String> p);
public abstract <Z> R<Z> get3(Collection<Integer> p);
public class B extends A {
@Override
public R<String> get() {
return null;
}
@Override
public R<Double> get2(Collection<String> p) {
return null;
}
@Override
public <V> R<V> get3(Collection<Integer> p) {
return null;
}
}
}
get2
相同的编译错误,以及get
的{{1}}明显的类型安全警告,我希望它也会出现在get2
上。get3
的类型隐藏问题很明显,如上所述。答案 0 :(得分:5)
下面:
public <Object> R<Object> get3(Collection<Integer> p) {
可能不你的意思。
您正在引入另一个类型变量,此处称为Object
。
将其与:
进行比较public R<Object> get2(Collection<String> p) {
换句话说:get2()
使用java.lang.Object。 get3()
使用通用类型,但不幸名为Object
。你也可以写
public <NONSENSE> R<NONSENSE> get3(Collection<Integer> p) {
最后:get2()
不是你要做的事情。请参阅Michael的优秀答案。
答案 1 :(得分:2)
As GhostCat already mentioned,Object
中的get3
实际上是一个类型变量。也就是说,有趣的是,你应该使用什么,但名字却令人困惑。
要修复内部类,必须再次为所有3种方法重新声明泛型类型参数:
public class B extends A
{
@Override
public <X> R<X> get1() {
return null;
}
@Override
public <X> R<X> get2(Collection<String> p) {
return null;
}
@Override
public <X> R<X> get3(Collection<Integer> p) {
return null;
}
}
但是,<X>
的所有重复都表明您应该将泛型类型参数移动到类A
。这是我实现这个的方式:
abstract class A<X>
{
public class R<T> { }
public abstract R<X> get1();
public abstract R<X> get2(Collection<String> p);
public abstract R<X> get3(Collection<Integer> p);
public class B extends A<X>
{
@Override
public R<X> get1() {
return null;
}
@Override
public R<X> get2(Collection<String> p) {
return null;
}
@Override
public R<X> get3(Collection<Integer> p) {
return null;
}
}
}
如果B
与所有Object
相关(从您的示例中不清楚),您可以将上面的内部类替换为:
public class B extends A<Object>
{
@Override
public R<Object> get1() {
return null;
}
@Override
public R<Object> get2(Collection<String> p) {
return null;
}
@Override
public R<Object> get3(Collection<Integer> p) {
return null;
}
}
答案 2 :(得分:2)
B.get2()
不覆盖 A.get2()
的原因是因为这两个类型的 参数 according to the JLS ...
... 如果以下两个条件均成立,则两个方法或构造器
M1
和M2
具有相同的类型参数: ...
M1
和M2
具有相同数量的类型参数(可能为零) )。其中
A1, ..., An
是M
的类型参数,而B1, ..., Bn
是N
的类型参数,让θ=[B1:=A1, ..., Bn:=An]
。然后,对于所有i (1 ≤ i ≤ n)
,Ai
的边界与应用于θ
边界的Bi
的类型相同。
A.get2()
具有 public abstract <X>
type parameter section。但是在特定上下文中, R<Double>
中的public R<Double> B.get2()
不是 类型参数 。在这种情况下,Double
是 调用 (实例化)中的 类型参数 )中的同名通用方法。
要想获得JLS法律覆盖的情况,请使用两种方法 必须 what the JLS calls override-equivalent ...
... 两个方法签名
A
和M1
是等效的,前提是 {{1} } 是M2
的子签名或M1
是M2
的子签名 ...
除非两个方法之一是另一个方法的subsignature,否则两个方法不能重写等效。
...
方法
M2
的签名是方法M1
的签名的子签名: ...
- 具有相同的签名
M1
与M2
或M2
的签名与M1
签名的擦除(第4.6节)相同。...
两个方法不能互相成为子签名,除非它们具有相同的签名...
... 如果两个方法具有相同的名称和参数类型,则它们具有相同的签名 ...
您的两个方法没有相同的签名,因为它们不符合 the same argument types condition of the JLS ...
...
如果满足以下所有条件,则两个方法或构造函数声明
M1
和M2
具有相同的参数类型:
- 它们具有相同数量的形式参数(可能为零)
- 它们具有相同数量的类型参数(可能为零)
- 让
M
为N
的类型参数,让A1 , ..., An
为{{ 1}}。将M
类型的每个B1, ..., Bn
重命名为N
后,对应类型变量的界限相同,并且Bi
和N
的形式参数类型相同。...
因此,要编译 Ai
— 并使M
是100%类型安全的 –那么您需要将方法更改为等效。
最简单的方法是使它们具有与它们覆盖的 N
中相同数量的类型参数。
B.get2()
答案 3 :(得分:0)
尝试
...
public <X> R<X> get2(Collection<String> p){
...
public <X> R<X> get3(Collection<Integer> p) {
...
答案 4 :(得分:0)
您的X
泛型类型不是Object
,而是扩展 Object
,因为替换{{ {1}} Object
。 get2方法的有效原型是这样的:
Object
与你的get3方法相同,你不需要泛型来操纵对象,它应该是扩展// X or Y or any generic type or class
public <Y> R<Y> get2(Collection<String> p) {
return null;
}
的东西
Object