为什么不能在编译时重写,但重载可以?

时间:2018-06-15 14:53:48

标签: java runtime method-overriding

我知道重载是在编译时完成的,因为指定了参数的数量和类型,编译器知道对象中的哪一个方法被调用。

但是在重写为什么编译器不会看到子类是否存在于超类中?

如果编译器在编译时不知道类,那么它如何识别重载?

谢谢!

2 个答案:

答案 0 :(得分:8)

让自己置身于编译器之中。想象一下,你必须编译以下方法:

public void foo(List<String> list) {
    System.put.println(list.size());
}

你怎么可能知道list的具体类型是什么,从而调用size()方法的具体实现?它是一个ArrayList吗?一个LinkedList?一个CopyOnWriteArrayList?你不能知道。

如果您还不相信,该方法的调用者可以执行类似

的操作
if (Math.random() > 0.5) {
    foo(new ArrayList<>());
}
else {
    foo(new LinkedList<>());
}

在编译时无法知道列表的具体类型是什么。您只能在运行时知道。因此,调用哪个size()方法只能在运行时决定。

答案 1 :(得分:2)

在编译时检查覆盖

看看这个:

class Base {
    public void myMethod() {}
}

class Derived extends Base {
    @Override // error!
    public void myMethod2() {}
}

编译器检查myMethod2是否在基类中,它不是,因此编译器会给出错误。

但是,决定在运行时确定要调用的重写方法的版本。这是因为要确定要调用哪个方法,必须知道对象的运行时类型。编译器无法知道变量的运行时类型,除非它运行您的代码,此时它不再编译&#34; -time ...

看看这个:

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:)。