编译器在java中编译时和运行时函数绑定之间的标准是什么

时间:2016-10-05 12:10:42

标签: java

首先,我觉得Java有时使用运行时绑定并且有时编译时间绑定是非常奇怪的。如果它总是运行时绑定不是更简单吗?无论如何。我的问题如下:

在以下代码中:

public class Animal {
    public void eat() {
        System.out.println("Generic Animal Eating Generically");
    }
}

public class Horse extends Animal {
    @override
    public void eat() {//overridden eat method
        System.out.println("Horse eating hay ");
    }
    public void eat(String s) {//overloaded eat method
        System.out.println("Horse eating " + s);
    }
}

问题: 1.在下面的代码中,我知道“哪种方法可以运行?”在编译时决定。太明显了。但是决定它的标准是什么?

Animal a = new Animal();
a.eat();

2.以下代码中的内容。

Animal a = new Horse();//line 1
a.eat();

我知道在这种情况下,方法被覆盖并且发生了运行时绑定。但是编译器跳过编译时绑定的标准是什么?

我的假设:它是否认为数据类型和构造函数调用属于不同的类(在第1行中),并且由于这种差异,它会跳过编译时绑定?

3.在下面的代码中:

 Animal a = new Horse();
 a.eat("some string");//compile time error

如果我的假设为真,则此代码不应导致编译时错误,因为已跳过编译时绑定。我无法理解为什么它会产生编译时错误。 有人可以澄清吗?

3 个答案:

答案 0 :(得分:2)

几乎总是运行时绑定。即所有的java方法都是虚方法。除了非虚拟的静态方法。

也无法覆盖最终和私有方法。

但是,我们在java中确实有一些编译时类型检查。在以下代码中,您遇到编译错误,因为类Animal没有eat(String)方法。

Animal a = new Horse();
a.eat("some string");//compile time error

如果Animaleat(String)方法,则代码会编译。但是,由于运行时绑定,它将执行Horse.eat()

在动态类型语言中,如python或javascript,没有这种类型检查。如果该方法在运行时存在,则会调用它。否则会抛出错误。这也称为Duck Typing

答案 1 :(得分:2)

实例方法调用规则非常简单:

  • 在编译时选择签名方法。
  • 在运行时选择具有该签名的方法的特定实现。即使方法和/或类是final也是如此,因为可以重新编译类并引入新的覆盖。调用类不会受这些更改的影响。

答案 2 :(得分:1)

Java使用实际类在运行时找到所需的方法,但它使用接口来判断实际上是方法在编译时。您的班级动物 隐式还定义了动物界面,在这种情况下,该界面仅包含无参数方法'吃()&#39 ;.它没有定义单参数方法' eat(String)'。类隐式定义 Horse 接口,该接口使用单参数方法扩展 Animal 接口。

在您的示例(1)和(2)中,无论您实例化哪个实际类,都分配给实现 Animal 接口的变量。因此,当编译器看到语句' a.eat();'它会检查' a'的界面。实现一种无论证的方法' eat()' - 它做的。在您的示例(3)中,实际的类是但该变量仍然只实现 Animal 接口; at statement' a.eat(" some string");'它检查是否' a'实施' eat(String)' - 它没有,因此编译错误。