[英]Java compile error overriding generic method with generic parameter
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
存在编译错误:
AB 类型的方法 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
相同的编译错误,以及我希望在get2
上get
的明显类型安全警告。get3
的类型隐藏问题很明显,如上所述。这里:
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 对那部分的出色回答。
正如GhostCat已经提到的, 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
s(从您的示例中不清楚),您可以将上面的内部类替换为:
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;
}
}
B.get2()
不覆盖A.get2()
的原因是因为根据 JLS两者没有相同的类型参数......
...如果以下两项都为真,则两个方法或构造函数
M 1
和M 2
具有相同的类型参数: ...
M 1
和M 2
具有相同数量的类型参数(可能为零)。其中
A 1 , ..., An
是M
的类型参数,B 1 , ..., B n
是N
的类型参数,令θ=[B 1 :=A 1 , ..., B n :=A n ]
。 然后,对于所有i (1 ≤ i ≤ n)
,A i
的边界与应用于B i
的边界的θ
类型相同。
A.get2()
具有public abstract <X>
类型参数部分。 但R<Double>
在public R<Double> B.get2()
不在该特定上下文类型参数。 在这种情况下, Double
是A
同名泛型方法的调用(实例化)中的类型参数。
为了有 JLS 合法的覆盖情况,两种方法必须是JLS 称为覆盖等效的方法......
...两个方法签名
M 1
和M 2
是覆盖等效当且仅当任一M 1
是一个子签名M 2
或M 2
是一个子签名M 1
...
除非两个方法之一是另一个的子签名,否则两个方法不能是覆盖等效的...
...
方法
M 1
的签名是方法M 2
签名的子签名,如果: ...
M 2
具有与M 1
相同的签名,或M 1
的签名与M 2
的签名的擦除(第 4.6 节)相同。...
两个方法不能是彼此的子签名,除非它们具有相同的签名......
... 如果两个方法具有相同的名称和参数类型,则它们具有相同的签名...
您的两个方法没有相同的签名,因为它们不满足JLS的相同参数类型条件......
...
如果以下所有条件都成立,则两个方法或构造函数声明
M
和N
具有相同的参数类型:
- 它们具有相同数量的形式参数(可能为零)
- 它们具有相同数量的类型参数(可能为零)
- 让
A 1 , ..., A n
是M
的类型参数,让B 1 , ..., B n
是N
的类型参数。 将N
类型中每次出现的 aB i
重命名为A i
,对应的类型变量的边界相同,M
和N
形参类型相同。...
因此,为了让B.get2()
编译——并且B.get()
是 100% 类型安全的——那么你需要将方法更改为覆盖等效。
最简单的方法是使它们具有与它们覆盖的A
中相同数量的类型参数......
import java.util.Collection;
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 static class B extends A {
@Override
public <T> R<T> get() {
return null;
}
@Override
public <U> R<U> get2(Collection<String> p) {
return null;
}
@Override
public <V> R<V> get3(Collection<Integer> p) {
return null;
}
}
}
尝试
...
public <X> R<X> get2(Collection<String> p){
...
public <X> R<X> get3(Collection<Integer> p) {
...
您的X
泛型类型不是 and Object
,而是扩展Object
东西,因为用Object
替换Object
确实没有意义。 get2 方法的有效原型是这样的:
// X or Y or any generic type or class
public <Y> R<Y> get2(Collection<String> p) {
return null;
}
与你的 get3 方法一样,你不需要泛型来操作对象,它应该是扩展Object
东西
public <Y> R<Y> get3(Collection<Integer> p) {
return null;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.