不允许在Java方法重写上使用超类型的原因是什么?
编译器认为以下代码无效:不允许在Java方法重写上使用超类型的原因是什么?,java,overloading,Java,Overloading,编译器认为以下代码无效: class Foo { void foo(String foo) { ... } } class Bar extends Foo { @Override void foo(Object foo) { ... } } 我认为这在“m1的签名是m2签名的子签名(§8.4.2)”和8.4.2“相应类型变量的边界相同”中有描述 我的问题是:为什么子类型(Bar)中的参数不能是超类型(Foo)中参数的超类型。在示例中,对象是字符串的超类型。就我所知,允
class Foo {
void foo(String foo) { ... }
}
class Bar extends Foo {
@Override
void foo(Object foo) { ... }
}
我认为这在“m1的签名是m2签名的子签名(§8.4.2)”和8.4.2“相应类型变量的边界相同”中有描述
我的问题是:为什么子类型(Bar)中的参数不能是超类型(Foo)中参数的超类型。在示例中,对象是字符串的超类型。就我所知,允许这样做不会违反法律
是否存在允许这样做会破坏代码的场景,或者这是当前JLS的限制?假设您可以这样做。现在,您的超类如下所示:
class Foo {
void foo(String foo) { ... }
void foo(Number foo) { ... }
}
class Foo {
public void foo(String foo) { ... }
}
class Bar extends Foo {
@Override
public void foo(String foo) { this.foo((Object)foo); }
public void foo(Object foo) { ... }
}
现在你的子类是:
class Bar extends Foo {
@Override
void foo(Object foo) { ... }
}
该语言可能允许这样的事情(只需将Foo.Foo(字符串)和Foo.Foo(数字)分派给Bar.Foo(对象)),但显然Java的设计决策是一个方法只能覆盖另一个方法
[编辑]
正如dasblinkenlight在他的回答中所说的,一个人可以拥有一个没有@Override的foo(对象),但这只是重载foo函数,而不是重写它们。调用时,java选择最具体的方法,因此foo(“Hello World”)将始终被分派到foo(String)方法。(从另一个角度重写…我的原始答案包含错误。:()
为什么子类型(Bar)中的参数不能是超类型(Foo)中参数的超类型。
我相信从技术上讲它可以,而且它不会破坏遵循类型替换(Liskov替换原则)的祖先契约
- 类型按值传递(包括引用类型)
- 调用方永远不能被迫处理与其传入的参数类型不同的参数类型
- 方法体可以交换参数类型,但不能将其返回给调用方(没有“输出参数类型”之类的东西)
- 如果您的建议被允许,并且对祖先方法签名进行了调用,则Decent类可以使用更广泛的类型覆盖该方法,但是仍然不可能返回比调用方设置的更广泛的类型
- 重写永远不会破坏使用狭义祖先方法契约的客户端
- 与性能相关的:允许覆盖更广泛的类型会影响运行时性能,这是一个主要问题
- 与功能相关的:它只添加了少量功能。目前,您可以添加“更广泛的方法”作为重载方法,而无需重写。然后您还可以使用精确的签名匹配来重写原始方法。最终结果是:您在功能上实现了非常类似的结果
方法重写的编译器要求-JLS 7 编译器需要根据您的经验进行操作。: 子类中的方法可以重写祖先类中的方法:
- 方法名称相同(和)
- 删除泛型类型参数后,方法参数具有相同的类型(8.4.2和8.4.8.1)
- 返回类型是可替代祖先类中返回类型的类型,即相同类型或更窄的类型() 注意:子签名并不意味着重写方法使用被重写方法的子类型。如果重写方法具有完全相同的类型签名,则称重写方法具有被重写方法的子签名,但泛型类型和相应的原始类型被认为是等效的
用于方法匹配和调用的编译器v运行时处理 通过多态类型匹配有一个性能命中匹配方法签名。通过将覆盖方法签名限制为祖先的精确匹配,JLS将此过程的大部分转移到编译时。-总结:
- 获取调用方法的基类型T
- 这是向编译器声明的引用类型,而不是运行时类型(可以替换子类型)
- 搜索编译时基类型T,查找与名称和参数匹配的适用方法,以及与调用一致的返回类型。
- 解析T的泛型参数,该参数可以是显式传递的,也可以是从调用方法参数的类型隐式推断的
- 阶段1:通过一致类型/子类型(“子类型”)适用的方法
- 第2阶段:通过自动装箱/拆箱和子类型应用的方法
- 阶段3:通过自动装箱/拆箱加上子类型加上变量“arity”参数适用的方法
- 确定最具体的匹配方法签名(即可以成功传递给所有其他匹配方法签名的方法签名);如果没有:编译器/歧义错误
- 确定运行时目标引用类型
- 评估参数
- 检查方法的可访问性
- Locate方法-与编译时匹配的签名完全匹配的签名
- 援引
性能命中率 按JLS中的文本分类: 第1步:5% 第二步:60% 第三步:5% 第四步:30% 第二步不仅在文本中大量出现,而且
class Foo {
void foo(String foo) { ... }
}
class Bar extends Foo {
@Override
void foo(Object foo) { ... }
}
class Another extends Bar {
@Override
void foo(Number foo) { ... }
}
class Foo {
void foo(String foo) { ... }
}
class Bar extends Foo {
@Override
private void foo(String foo) { ... }
void foo(Object foo) { ... }
}
class Another extends Bar {
@Override
private void foo(Object foo) { ... }
void foo(Number foo) { ... }
}
class Foo{ //Super Class
void foo(String string){
// Your implementation here
}
}
class Bar extends Foo{
@Override
void foo(String string){
super(); //This method is implied when not explicitly stated in the method but the @Override annotation is present.
// Your implementation here
}
// An overloaded method
void foo(Object object){
// Your implementation here
}
}