Java

时间:2017-11-23 04:17:39

标签: java oop compilation runtime

我已经阅读了一些关于Java中静态绑定动态绑定的文章。我有以下问题(我已经搜索了很多但没有找到任何关于它的提及)

例如,我有以下几行代码:

Person a = new Student(); // Student is a subclass of Person
a.speak();

我们已经知道的是在编译时,编译器将检查类speak()中是否存在Person的方法定义并将其调用如果它存在在运行时,它会调用speak()指向的实际对象的a方法(在这种情况下,实际对象显然是Student

所以我的问题是为什么它不能在编译时直接调用类speak() Student方法,而是等到运行 - 时间这样做?这背后有什么理由吗?

3 个答案:

答案 0 :(得分:4)

当代码编译时,有时候,不清楚需要调用哪个方法。只能在运行时确定。

以这个简单的代码为例。

class Animal{   

    public void makeNoise(){
       System.out.println("Default");
    };
}

class Dog extends Animal{

    //override the makeNoise()
    public void makeNoise(){
        System.out.println("Woof");
    };
}

class Cat extends Animal{

        //override the makeNoise()
        public void makeNoise(){
            System.out.println("Meow");
        };
    } 

public class Sounds{

    public static void AnimalSounds(Animal animal){
    animal.makeNoise();
    }

    public static void main(String args[]){

        Animal dog = new Dog();     
        Animal cat = new Cat(); 
        AnimalSounds(dog);
        AnimalSounds(cat);  
    }
}

AnimalSounds(Animal animal)方法接受任何传递Animal的ISA测试的对象并调用该对象的相应方法。如您所见,它也会删除代码重复,因为我们可以在不同类型的对象上使用相同的方法。

希望这能解决您的问题。

答案 1 :(得分:3)

要理解这个主题,您应该知道什么是编译和运行时进程。简而言之,当您构建应用程序时,编译器会遍历所有代码并检查一致性,安全性和可运行性。如果编译器没有创建错误,则会从源代码(class文件)生成java个文件。当应用程序运行时,意味着您的class文件被加载到内存中,JVM按指令执行您的应用程序指令。

从你的例子:

Person a = new Student(); // Student is a subclass of Person
a.speak();     

编译过程 编译器检查此行:Person a = new Student();以确保类型安全(兼容性)。因此,如果学生is a人员编译转到下一行,则其失败。在下一行中:a.speak();编译器查看a类型,发现它是Person并在speak()类型中查找Person方法。如果该方法没有由编译器编译过程失败。

运行时流程: 当JVM执行此行时:Person a = new Student();它将从顶层(父类)到底层(子类)进行初始化过程。在下一行:a.speak(); JVM创建student对象通过引用a查找方法speak(),如果它在Student中创建然后执行它,否则它从父类speak()运行Person方法。

继承主题的另一个例子:

class Person {
    public void speak() {}
    public void think() {}
}

class Student extends Person {
    @Override
    public void speak() {}
    public void speakALot() {}
}

Person a = new Student();
a.speak(); // calling overrided version of speak() 
a.think(); // since this method is not overrided in child class it will be called from parent class
a.speakALot(); // since Person doesn't know anything about specific methods of derived classes compilation fails 

Student b = new Student();
b.speak(); // calling speak() method of student object
b.think(); // inheritance trick, child class keeps reference to its base class and that's why public and protected fields and methods are available
b.speakALot(); // calling speakALot() method of student object

答案 2 :(得分:0)

如果我只是编写一个通用课程来测试任何类型的工具,如下所示。

public class Workshop{
    public boolean test(Vehicle vehicle){
        vehicle.start();
        vehicle.stop();
        //...more code
        return true;
    }
 }

我只能使用Vehicle类型编译此代码,但是没有编写Vehicle的子类。通常,框架利用这种在没有具体类型的情况下提供基于泛型类型的处理的能力(客户端可以自由扩展子类层次结构)。在这种情况下,编译器只会确保车辆至少有一个实现(类似{}的空实现也可以接受),以免破坏代码。