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(集合)必须重写或实现超类型方法
只有带有泛型的参数才会出现此错误<代码>get3编译,但当然有一个警告:
>
显然还有其他方法可以解决这个问题,但在我的理解中,这应该是一个法律优先事项,我的问题更多的是为什么会有这个编译错误。提前谢谢!
编辑:
对不起,我的例子不够清楚。因此,这里有一个新的答案来回应你的一些观点。
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
的明显类型安全警告,我也希望在get2
上获得。- 我希望每个方法都有自己的类型,所以类类型不是解决方案。
- 在这个例子中使用Object是一个错误的决定,但这不是我的观点,旧
get3
的类型隐藏问题如上所述很清楚。- 问题就出在签名上,就像lancore说的,所以我要评论一下他的回答。
之所以B.get2()没有覆盖A.get2()是因为根据JLS,这两个类型参数不相同。。。
...如果以下两个都为真,则两个方法或构造函数M1
和M2
具有相同的类型参数:...
>
其中
是n
的类型参数,设θ=[B1:=A1,…,Bn:=An]。然后,对于所有<代码>i(1≤ 我≤ n)
,Ai的界与应用于Bi的界的θ的类型相同。
A. get2()
具有公共摘要
为了使JLS具有合法的覆盖情况,两种方法必须是JLS所称的覆盖等效方法。。。
...两个方法签名
M1
和M2
是覆盖等效的,如果M1
是M2
的子签名或M2
是M1
的子签名...
除非两个方法中的一个是另一个的子签名,否则这两个方法不能重写为等价的。。。
...
方法签名是方法签名的子签名,如果存在以下任一情况:。。。
M的签名与M的签名相同
M的签名与M的签名的擦除(§4.6)相同
...
两个方法不能是彼此的子签名,除非它们具有相同的签名。。。
...如果两个方法具有相同的名称和参数类型,则它们具有相同的签名...
您的两个方法没有相同的签名,因为它们不满足JLS的相同参数类型条件。。。
...
如果以下所有条件都成立,则两个方法或构造函数声明
M
和N
具有相同的参数类型:
它们具有相同数量的形式参数(可能为零)
- 它们具有相同数量的类型参数(可能为零)
- 设
A1,..., An
为M
的类型参数,设B1,..., Bn
为N
的类型参数。将N
中的Bi
的每次出现重命名为Ai
后,对应类型变量的界限相同,M
和N
的形式参数类型相同。
...
因此,对于编译的
B.get2()
,以及对于100%类型安全的B.get()
,您需要将方法更改为重写等效方法。
最简单的方法是使它们具有与它们覆盖的
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;
}
}
}
正如Ghost Cat已经提到的,get3
中的Object
实际上是一个类型变量。有趣的是,您应该使用什么,但名称令人困惑。
要修复内部类,必须为所有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;
}
}
然而,所有这些重复的<代码>
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;
}
}
在这里:
public <Object> R<Object> get3(Collection<Integer> p) {
可能不是你的意思。
您正在这里引入另一个类型变量,称为Object
。
将其与:
public R<Object> get2(Collection<String> p) {
换句话说:get2()
使用java.lang.对象。get3()
使用一个泛型类型,不幸的是,它被命名为Object
。你也可以写
public <NONSENSE> R<NONSENSE> get3(Collection<Integer> p) {
最后:get2()
也不是您要做的。请参阅迈克尔关于该部分的精彩回答。
安吉丽卡·兰格(Angelica Langer)在关于仿制药的常见问题解答中说(参见Technicalities.FAQ822): 如果这些方法具有具有不同边界的类型参数,则它们不会重写,因为这些方法的签名不是重写等价的。请记住,类型参数边界是泛型方法签名的一部分。 示例(泛型子类型方法重载泛型超类型方法;不推荐): 我不明白为什么方法在类中重载。据我所知,这应该是一个编译时错误,因为在和中具有相
我试图覆盖add(),但它不会编译 错误消息 java:36:错误:名称冲突:AVLTree中的add(E#1)和BinaryTree中的add(E#2)具有相同的擦除,但两者都不重写另一个公共void add(E toInsert)^,其中E#1、E#2是类型变量:E#1扩展了在类AVLTree中声明的Comparable E#2扩展了在类BinaryTree中声明的Comparable
我正在尝试覆盖子类中从父类继承抽象方法的方法。我正在尝试更改泛型返回类型,但我有点困惑。 基本泛型类: 儿童班: 实施: 我想在其中覆盖参数化方法的子视图类: 这是Eclipse抛出错误消息的地方: 注意类和接口:事件和级别: 以及继承自 的 Model 类 我试图实现的是编写更抽象的代码,因为这些类、接口将被多个类扩展(在我的例子中是不同的视图类型)。这些是抽象类:< code>BaseAdap
来自Java文档:在类C中声明的实例方法m1覆盖在类A中声明的另一个实例方法m2,如果以下所有条件都为真:。。。。。m1的签名是m2签名的子签名(§8.4.2)。 方法m1的签名是方法m2签名的子签名,前提是:m1的签名与m2签名的擦除相同(§4.6)。 是对一个 如果是这样,什么是错的? EDIT1:或者如果我切换通用类型: 这种情况下有什么问题? EDIT2:我知道如何修复它,但我想了解,在这
这是如何编译的: 但这并不是: 它给我以下编译错误: Impl不是抽象的,并且不会覆盖测试中的抽象方法getValue(整数) 错误:名称冲突:Impl中的getValue(T)和测试中的getValue(Integer)具有相同的擦除,但两者都不重写另一个 擦除不能确保t被整数替换吗?那么为什么第二个例子是无效的呢?
我正在做一个体验,尝试用以下方式重写泛型类的方法: 为什么我不能?编译错误是 yGenFun。java:15:错误:对doX的引用不明确,Do中的方法doX(A)和MyGenFun中的方法doX(T)都匹配x.doX(“测试”);^其中A、T是类型变量:在类Do T中声明的extends对象扩展在类MyGenFun 1 error中声明的CharSequence 如果我注释“第1行”,我可以编译代