擦除如何处理Java中的覆盖场景?
这个问题来自我在上一篇文章。在我发布问题之前,我正在粘贴oracle文档中的内容擦除如何处理Java中的覆盖场景?,java,generics,overriding,Java,Generics,Overriding,这个问题来自我在上一篇文章。在我发布问题之前,我正在粘贴oracle文档中的内容 8.4.8.1. Overriding (by Instance Methods) An instance method m1, declared in class C, overrides another instance method m2, declared in class A iff all of the following are true: C is a subclass of A.
8.4.8.1. Overriding (by Instance Methods)
An instance method m1, declared in class C, overrides another instance method m2, declared in class A iff all of the following are true:
C is a subclass of A.
The signature of m1 is a subsignature (§8.4.2) of the signature of m2.
8.4.2. Method Signature
The signature of a method m1 is a subsignature of the signature of a method m2 if either:
m2 has the same signature as m1, or
the signature of m1 is the same as the erasure (§4.6) of the signature of m2.
当涉及到重写时,我对类型擦除的理解如下:
如果在擦除之后
,m1和m2的签名相同,则认为它们被覆盖
。
因此,在我上面的前一篇文章中,我试图覆盖一个需要
列表
通过子类方法
执行列表
假设在类型擦除后
剩下的只是列表
。但这是错误的。所以我对上述定义的理解
当涉及到擦除
时,方法重写
是完全错误的。有人能给出一个简单的答案吗
举例说明上述观点
谢谢。顺便说一句,以上几点来自,因为Java是一种严格类型化的语言,它必须小心协变性和类型如何协同工作。擦除不是违反类型规则的借口
例如:
class BaseGood<T> {
public void doStuff(T elem) {
// ...
}
}
class DerivedGood<T> extends BaseGood {
public void doStuff(Object elem) {
super.doStuff(elem);
}
}
class BaseBad {
public void doStuff(List<Double> list) {
// ...
}
}
class DerivedBad extends BaseBad {
public void doStuff(List<Integer> list) {
super.doStuff(list);
// ...
}
}
classbasegood{
公共真空度(T元素){
// ...
}
}
类派生的good扩展了BaseGood{
公共作废文件(对象元素){
超级多斯塔夫(elem);
}
}
BaseBad类{
公共作废文件(列表){
// ...
}
}
类DerivedBad扩展了BaseBad{
公共作废文件(列表){
超级多斯塔夫(列表);
// ...
}
}
这里,我们有两种不同的擦除情况
对于BaseGood
和DerivedGood
类,这两种方法具有相同的擦除:void doStuff(Object elem)
,可以知道T
始终是Object
类型,因此函数是类型安全的
对于BaseBad
和DerivedBad
类,这两种方法具有相同的擦除功能:voiddostuff(List)
;但是,类型系统无法安全地从列表
转换为列表
(或转换为任何列表
)。允许这种转换可能会允许尝试将Double
s放入Integer
s列表中(或者泛型将检测转移到编译时的问题)
擦除后使方法覆盖友好并不意味着类型系统无法在擦除前检查不兼容
编辑
此外,应用于类/方法定义的实际擦除不会在编译时发生,而是在运行时发生。引用泛型方法的代码只需编译,就好像调用函数时没有使用泛型一样,类型安全由编译器和运行时检查强制执行
见:
还有另一种情况,您将类型擦除的泛型类传递给重写,因为类型系统无法检查您是否根据方法的类型传递了正确的列表,所以它必须允许传递该列表。一个方法是否重写另一个方法不仅仅处理方法的擦除。编译器确定一个方法是否重写另一个方法,并且在发生类型擦除之前,它可以访问涉及的泛型类型参数
您关于使用擦除来确定覆盖的想法不太正确。让我们在讨论中添加以下内容:
在类C中声明的实例方法m1重写在类A中声明的另一个实例方法m2,前提是以下所有条件均为真:
- C是a的一个子类
- m1的签名是m2签名的子签名(§8.4.2)
- 要么:
- m2是公共的、受保护的,或在与C相同的包中声明了默认访问权限,或
- m1覆盖方法m3(m3不同于m1,m3不同于m2),因此m3覆盖m2
要求m1
是m2
的子符号,但不是相反
例1:
class A {
public void foo(List<String> list) { }
}
class B extends A {
@Override
public void foo(List list) {}
}
这是合法的,因为签名是相同的(即使它们是原始的)
例3:
class A {
public void foo(List list) { }
}
class B extends A {
@Override
public void foo(List<Integer> list) {}
}
这同样是不合法的,因为没有考虑重写方法的擦除。也就是说,List
与List
(List
)的擦除相比较,它们是不同的
无法将重写方法中参数的泛型类型参数(例如,List
更改为List
)。在重写未使用泛型的方法(例如(List
到List
)时,不能引入泛型。但是,可以在重写时删除泛型(例如List
到List
)。使用foo怎么样(列表如果父类的方法有List,则父类可以接受Number
或任何扩展Number
的内容,例如双精度、整数
等。对吗?子类不能用列表作为参数覆盖,这仅仅是因为列表
是不变的正确的??这是正确的;子类的方法需要是列表在示例4中,如果我注释掉@override
,仍然存在编译错误。我认为现在应该是重载
,因为类B继承了A
的foo(列表),并且它有自己的foo(列表)方法
。如果由于类型擦除
,我们得到的是原始类型foo(List)
,那么类型信息存储在哪里,以便它将转换回?好的,我想我正在按照您的解释进行操作。使用双[]
和int[]如何
在上面,由于数组
是协变的
,所以不应该存在问题,对吧?这不会起作用,因为双精度
和整数
不在继承层次结构上。整数
不是超集或子集
class A {
public void foo(List list) { }
}
class B extends A {
@Override
public void foo(List<Integer> list) {}
}
class A {
public void foo(List<String> list) { }
}
class B extends A {
@Override
public void foo(List<Integer> list) {}
}