Java 为什么可以';重写不能在编译时完成,但重载可以吗?
我知道重载是在编译时完成的,因为指定了参数的数量和类型,并且编译器知道调用了对象中的哪个方法 但是在重写过程中,为什么编译器看不到超类中是否存在子类方法 如果编译器在编译时不知道类,那么它如何识别重载Java 为什么可以';重写不能在编译时完成,但重载可以吗?,java,runtime,overriding,Java,Runtime,Overriding,我知道重载是在编译时完成的,因为指定了参数的数量和类型,并且编译器知道调用了对象中的哪个方法 但是在重写过程中,为什么编译器看不到超类中是否存在子类方法 如果编译器在编译时不知道类,那么它如何识别重载 谢谢 设身处地为编译器着想。假设您必须编译以下方法: public void foo(List<String> list) { System.put.println(list.size()); } 在编译时无法知道列表的具体类型。您只能在运行时知道。因此,只能在运行时决定调用
谢谢 设身处地为编译器着想。假设您必须编译以下方法:
public void foo(List<String> list) {
System.put.println(list.size());
}
在编译时无法知道列表的具体类型。您只能在运行时知道。因此,只能在运行时决定调用哪个size()
方法。在编译时检查重写
看看这个:
class Base {
public void myMethod() {}
}
class Derived extends Base {
@Override // error!
public void myMethod2() {}
}
class Base {
public void myMethod() {}
}
class Derived extends Base {
@Override
public void myMethod() {}
}
// ...
Base obj;
if (Math.random() > 0.5) {
obj = new Derived();
} else {
obj = new Base();
}
obj.myMethod();
编译器检查myMethod2
是否在基类中,而不是基类中,因此编译器会给出一个错误
但是,在运行时确定要调用的重写方法的版本。这是因为要确定调用哪个方法,必须知道对象的运行时类型。编译器无法知道变量的运行时类型,除非它运行您的代码,此时不再是“编译”时间
看看这个:
class Base {
public void myMethod() {}
}
class Derived extends Base {
@Override // error!
public void myMethod2() {}
}
class Base {
public void myMethod() {}
}
class Derived extends Base {
@Override
public void myMethod() {}
}
// ...
Base obj;
if (Math.random() > 0.5) {
obj = new Derived();
} else {
obj = new Base();
}
obj.myMethod();
矛盾证明:
如果要调用的方法的版本是在编译时决定的,那么这里的
myMethod()
调用将始终在运行时调用相同版本的方法,无论您运行代码多少次。但是从if语句中,我们可以看到调用的方法根据条件而变化。但这种情况在不同的代码运行中有所不同。这会产生矛盾,因此必须在运行时确定要调用的版本。QED:)。“在重写为什么编译器看不到超类中是否存在子类方法”中,它只从子类中选择一个。您可能对注释感兴趣。@Andy Turner为什么不能在编译时选择?链接到Java 7 API文档,当然你可以以某种方式访问它。@Jamie请注意,@Override
对运行时行为没有影响。它只是编译时的一个安全网,检查您的一个超类是否实际具有与您用@Override
@Turing85注释的方法相同的签名。参数的具体类型可以是实现java.util.List的任何具体类。你怎么知道是哪一个呢?Java编译器就是这么做的。Java运行时根据列表的具体运行时类型选择要调用的具体方法(即ArrayList#size()、LinkedList#size()或WhateverOtherList#size())。这就是最神奇的地方。哦,这就是你的意思=)对不起。我以为你的意思是调用foo(…)
。我的评论很快就会自我毁灭。@Turing85我澄清了我的意思。