静态对比 Java 中的动态绑定

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19017258/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 13:25:26  来源:igfitidea点击:

Static Vs. Dynamic Binding in Java

javadynamic-bindingstatic-binding

提问by user2309750

I'm currently doing an assignment for one of my classes, and in it, I have to give examples, using Java syntax, of staticand dynamic binding.

我目前正在为我的一个课程做作业,在其中,我必须使用 Java 语法给出静态动态绑定的示例。

I understand the basic concept, that static binding happens at compile time and dynamic binding happens at runtime, but I can't figure out how they actually work specifically.

我理解基本概念,静态绑定发生在编译时,动态绑定发生在运行时,但我无法弄清楚它们具体是如何工作的。

I found an example of static binding online that gives this example:

我在网上找到了一个静态绑定的例子,给出了这个例子:

public static void callEat(Animal animal) {
    System.out.println("Animal is eating");
}

public static void callEat(Dog dog) {
    System.out.println("Dog is eating");
}

public static void main(String args[])
{
    Animal a = new Dog();
    callEat(a);
}

And that this would print "animal is eating" because the call to callEatuses static binding, but I'm unsure as to whythis is considered static binding.

并且这会打印“animal is eat”,因为调用callEat使用 static binding,但我不确定为什么这被认为是静态绑定。

So far none of the sources I've seen have managed to explain this in a way that I can follow.

到目前为止,我所看到的所有消息来源都无法以我可以遵循的方式解释这一点。

采纳答案by Maulik Patel

From Javarevisited blog post:

Javarevisited 博客文章

Here are a few important differences between static and dynamic binding:

  1. Static binding in Java occurs during compile time while dynamic binding occurs during runtime.
  2. private, finaland staticmethods and variables use static binding and are bonded by compiler while virtual methods are bonded during runtime based upon runtime object.
  3. Static binding uses Type(classin Java) information for binding while dynamic binding uses object to resolve binding.
  4. Overloaded methods are bonded using static binding while overridden methods are bonded using dynamic binding at runtime.

Here is an example which will help you to understand both static and dynamic binding in Java.

Static Binding Example in Java

public class StaticBindingTest {  
    public static void main(String args[]) {
        Collection c = new HashSet();
        StaticBindingTest et = new StaticBindingTest();
        et.sort(c);
    }
    //overloaded method takes Collection argument
    public Collection sort(Collection c) {
        System.out.println("Inside Collection sort method");
        return c;
    }
    //another overloaded method which takes HashSet argument which is sub class
    public Collection sort(HashSet hs) {
        System.out.println("Inside HashSet sort method");
        return hs;
    }
}

Output: Inside Collection sort method

Example of Dynamic Binding in Java

public class DynamicBindingTest {   
    public static void main(String args[]) {
        Vehicle vehicle = new Car(); //here Type is vehicle but object will be Car
        vehicle.start(); //Car's start called because start() is overridden method
    }
}

class Vehicle {
    public void start() {
        System.out.println("Inside start method of Vehicle");
    }
}

class Car extends Vehicle {
    @Override
    public void start() {
        System.out.println("Inside start method of Car");
    }
}

Output:Inside start method of Car

以下是静态和动态绑定之间的一些重要区别:

  1. Java 中的静态绑定发生在编译时,而动态绑定发生在运行时。
  2. privatefinal以及static方法和变量使用静态结合和由编译器所键合而虚拟方法基于运行时对象在运行期间接合。
  3. 静态绑定使用Typeclass在 Java 中)信息进行绑定,而动态绑定使用对象来解析绑定。
  4. 重载的方法使用静态绑定绑定,而重写的方法在运行时使用动态绑定绑定。

下面是一个示例,它将帮助您理解 Java 中的静态和动态绑定。

Java 中的静态绑定示例

public class StaticBindingTest {  
    public static void main(String args[]) {
        Collection c = new HashSet();
        StaticBindingTest et = new StaticBindingTest();
        et.sort(c);
    }
    //overloaded method takes Collection argument
    public Collection sort(Collection c) {
        System.out.println("Inside Collection sort method");
        return c;
    }
    //another overloaded method which takes HashSet argument which is sub class
    public Collection sort(HashSet hs) {
        System.out.println("Inside HashSet sort method");
        return hs;
    }
}

输出:内部集合排序方法

Java 中的动态绑定示例

public class DynamicBindingTest {   
    public static void main(String args[]) {
        Vehicle vehicle = new Car(); //here Type is vehicle but object will be Car
        vehicle.start(); //Car's start called because start() is overridden method
    }
}

class Vehicle {
    public void start() {
        System.out.println("Inside start method of Vehicle");
    }
}

class Car extends Vehicle {
    @Override
    public void start() {
        System.out.println("Inside start method of Car");
    }
}

输出:Car 的内部启动方法

回答by Aaron

Because the compiler knows the binding at compile time. If you invoke a method on an interface, for example, then the compiler can't know and the binding is resolved at runtime because the actual object having a method invoked on it could possible be one of several. Therefore that is runtime or dynamic binding.

因为编译器在编译时就知道绑定。例如,如果您在接口上调用一个方法,那么编译器无法知道并且绑定在运行时解析,因为在其上调用方法的实际对象可能是多个对象之一。因此,这是运行时或动态绑定。

Your invocation is bound to the Animal class at compile time because you've specified the type. If you passed that variable into another method somewhere else, noone would know (apart from you because you wrote it) what actual class it would be. The only clue is the declared type of Animal.

您的调用在编译时绑定到 Animal 类,因为您已经指定了类型。如果您将该变量传递给其他地方的另一个方法,则没有人知道(除了您,因为您编写了它)它将是什么实际类。唯一的线索是声明的 Animal 类型。

回答by user2378479

The compiler only knows that the type of "a" is Animal; this happens at compile time, because of which it is called static binding (Method overloading). But if it is dynamic binding then it would call the Dogclass method. Here is an example of dynamic binding.

编译器只知道“a”的类型是Animal;这发生在编译时,因此称为静态绑定(方法重载)。但是如果是动态绑定,那么它会调用Dog类方法。下面是一个动态绑定的例子。

public class DynamicBindingTest {

    public static void main(String args[]) {
        Animal a= new Dog(); //here Type is Animal but object will be Dog
        a.eat();       //Dog's eat called because eat() is overridden method
    }
}

class Animal {

    public void eat() {
        System.out.println("Inside eat method of Animal");
    }
}

class Dog extends Animal {

    @Override
    public void eat() {
        System.out.println("Inside eat method of Dog");
    }
}

Output: Inside eat method of Dog

输出:Dog里面的eat方法

回答by Mr.Q

Connecting a method call to the method body is known as Binding. As Maulik said "Static binding uses Type(Class in Java) information for binding while Dynamic binding uses Object to resolve binding." So this code :

将方法调用连接到方法主体称为绑定。正如 Maulik 所说,“静态绑定使用类型(Java 中的类)信息进行绑定,而动态绑定使用对象来解析绑定。” 所以这段代码:

public class Animal {
    void eat() {
        System.out.println("animal is eating...");
    }
}

class Dog extends Animal {

    public static void main(String args[]) {
        Animal a = new Dog();
        a.eat(); // prints >> dog is eating...
    }

    @Override
    void eat() {
        System.out.println("dog is eating...");
    }
}

Will produce the result: dog is eating...because it is using the object reference to find which method to use. If we change the above code to this:

会产生这样的结果:dog is eat...因为它正在使用对象引用来查找要使用的方法。如果我们把上面的代码改成这样:

class Animal {
    static void eat() {
        System.out.println("animal is eating...");
    }
}

class Dog extends Animal {

    public static void main(String args[]) {

        Animal a = new Dog();
        a.eat(); // prints >> animal is eating...

    }

    static void eat() {
        System.out.println("dog is eating...");
    }
}

It will produce : animal is eating...because it is a static method, so it is using Type (in this case Animal) to resolve which static method to call. Beside static methods private and final methods use the same approach.

它会产生:animal is eat...因为它是一个静态方法,所以它使用 Type(在本例中为 Animal)来解析要调用的静态方法。除了静态方法私有和最终方法使用相同的方法。

回答by hexpheus

There are three major differences between static and dynamic binding while designing the compilers and how variablesand proceduresare transferred to the runtimeenvironment. These differences are as follows:

在设计编译器以及如何将变量过程传输到运行时环境,静态和动态绑定之间存在三个主要区别。这些差异如下:

Static Binding: In static binding three following problems are discussed:

静态绑定:在静态绑定中讨论了以下三个问题:

  • Definition of a procedure

  • Declaration of a name(variable, etc.)

  • Scope of the declaration

  • 程序的定义

  • 名称的声明(变量等)

  • 申报范围

Dynamic Binding: Three problems that come across in the dynamic binding are as following:

动态绑定动态绑定中遇到的三个问题如下:

  • Activation of a procedure

  • Binding of a name

  • Lifetime of a binding

  • 程序的激活

  • 名称的绑定

  • 绑定的生命周期

回答by Soudipta Dutta

With the static method in the parent and child class: Static Binding

使用父子类中的静态方法:静态绑定

public class test1 {   
    public static void main(String args[]) {
        parent pc = new child(); 
        pc.start(); 
    }
}

class parent {
    static public void start() {
        System.out.println("Inside start method of parent");
    }
}

class child extends parent {

    static public void start() {
        System.out.println("Inside start method of child");
    }
}

// Output => Inside start method of parent

Dynamic Binding :

动态绑定:

public class test1 {   
    public static void main(String args[]) {
        parent pc = new child();
        pc.start(); 
    }
}

class parent {
   public void start() {
        System.out.println("Inside start method of parent");
    }
}

class child extends parent {

   public void start() {
        System.out.println("Inside start method of child");
    }
}

// Output => Inside start method of child

回答by Naresh Joshi

Well in order to understand how static and dynamic bindingactually works? or how they are identified by compiler and JVM?

那么为了了解静态和动态绑定实际上是如何工作的?或者编译器和JVM如何识别它们?

Let's take below example where Mammalis a parent class which has a method speak()and Humanclass extends Mammal, overrides the speak()method and then again overloads it with speak(String language).

让我们看下面的例子,其中Mammal有一个父类,它有一个方法speak()Human类 extends Mammal,覆盖该speak()方法,然后再次用speak(String language).

public class OverridingInternalExample {

    private static class Mammal {
        public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
    }

    private static class Human extends Mammal {

        @Override
        public void speak() { System.out.println("Hello"); }

        // Valid overload of speak
        public void speak(String language) {
            if (language.equals("Hindi")) System.out.println("Namaste");
            else System.out.println("Hello");
        }

        @Override
        public String toString() { return "Human Class"; }

    }

    //  Code below contains the output and bytecode of the method calls
    public static void main(String[] args) {
        Mammal anyMammal = new Mammal();
        anyMammal.speak();  // Output - ohlllalalalalalaoaoaoa
        // 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V

        Mammal humanMammal = new Human();
        humanMammal.speak(); // Output - Hello
        // 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V

        Human human = new Human();
        human.speak(); // Output - Hello
        // 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V

        human.speak("Hindi"); // Output - Namaste
        // 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
    }
}

When we compile the above code and try to look at the bytecode using javap -verbose OverridingInternalExample, we can see that compiler generates a constant table where it assigns integer codes to every method call and byte code for the program which I have extracted and included in the program itself (see the comments below every method call)

当我们编译上面的代码并尝试使用 来查看字节码时javap -verbose OverridingInternalExample,我们可以看到编译器生成了一个常量表,它将整数代码分配给我提取并包含在程序本身中的程序的每个方法调用和字节码(请参阅每个方法调用下方的注释)

Program Bytecode

程序字节码

By looking at above code we can see that the bytecodes of humanMammal.speak(), human.speak()and human.speak("Hindi")are totally different (invokevirtual #4, invokevirtual #7, invokevirtual #9) because the compiler is able to differentiate between them based on the argument list and class reference. Because all of this get resolved at compile time statically that is why Method Overloadingis known as Static Polymorphismor Static Binding.

通过看上面的代码中我们可以看到的字节码humanMammal.speak()human.speak()并且human.speak("Hindi")是完全不同的(invokevirtual #4invokevirtual #7invokevirtual #9),因为编译器能够根据参数列表和类引用上区分它们。因为所有这些都在编译时静态解决,这就是方法重载被称为静态多态静态绑定的原因

But bytecode for anyMammal.speak()and humanMammal.speak()is same (invokevirtual #4) because according to compiler both methods are called on Mammalreference.

但是字节码anyMammal.speak()humanMammal.speak()是相同的(invokevirtual #4),因为根据编译器这两种方法都要求Mammal参考。

So now the question comes if both method calls have same bytecode then how does JVM know which method to call?

所以现在问题来了,如果两个方法调用都有相同的字节码,那么 JVM 怎么知道调用哪个方法呢?

Well, the answer is hidden in the bytecode itself and it is invokevirtualinstruction set. JVM uses the invokevirtualinstruction to invoke Java equivalent of the C++ virtual methods. In C++ if we want to override one method in another class we need to declare it as virtual, But in Java, all methods are virtual by default because we can override every method in the child class (except private, final and static methods).

嗯,答案隐藏在字节码本身中,它是invokevirtual指令集。JVM 使用该invokevirtual指令调用 Java 等效的 C++ 虚拟方法。在 C++ 中,如果我们想覆盖另一个类中的一个方法,我们需要将其声明为虚拟的,但在 Java 中,默认情况下所有方法都是虚拟的,因为我们可以覆盖子类中的每个方法(私有、最终和静态方法除外)。

In Java, every reference variable holds two hidden pointers

在 Java 中,每个引用变量都包含两个隐藏的指针

  1. A pointer to a table which again holds methods of the object and a pointer to the Class object. e.g. [speak(), speak(String) Class object]
  2. A pointer to the memory allocated on the heap for that object's data e.g. values of instance variables.
  1. 指向再次保存对象方法的表的指针和指向 Class 对象的指针。例如 [speak(), speak(String) 类对象]
  2. 指向在堆上为该对象的数据分配的内存的指针,例如实例变量的值。

So all object references indirectly hold a reference to a table which holds all the method references of that object. Java has borrowed this concept from C++ and this table is known as virtual table (vtable).

因此,所有对象引用都间接地持有对表的引用,该表持有该对象的所有方法引用。Java 从 C++ 借用了这个概念,这个表被称为虚拟表(vtable)。

A vtable is an array like structure which holds virtual method names and their references on array indices. JVM creates only one vtable per class when it loads the class into memory.

vtable 是一个类似数组的结构,它保存虚拟方法名称及其对数组索引的引用。JVM 在将类加载到内存中时,为每个类只创建一个 vtable。

So whenever JVM encounter with a invokevirtualinstruction set, it checks the vtable of that class for the method reference and invokes the specific method which in our case is the method from a object not the reference.

因此,每当 JVM 遇到invokevirtual指令集时,它都会检查该类的 vtable 以获取方法引用并调用特定方法,在我们的例子中,它是来自对象的方法而不是引用。

Because all of this get resolved at runtime only and at runtime JVM gets to know which method to invoke, that is why Method Overridingis known as Dynamic Polymorphismor simply Polymorphismor Dynamic Binding.

因为所有这些都只在运行时得到解决,并且在运行时 JVM 知道要调用哪个方法,这就是方法覆盖被称为动态多态或简称为多态动态绑定的原因

You can read it more details on my article How Does JVM Handle Method Overloading and Overriding Internally.

您可以在我的文章“JVM 如何内部处理方法重载和覆盖”中阅读更多详细信息。

回答by Namrata M

All answers here are correct but i want to add something which is missing. when you are overriding a static method, it looks like we are overriding it but actually it is not method overriding. Instead it is called method hiding. Static methods cannotbe overridden in Java.

这里的所有答案都是正确的,但我想添加一些缺失的东西。当您覆盖静态方法时,看起来我们正在覆盖它,但实际上它不是方法覆盖。相反,它被称为方法隐藏。Java 中不能覆盖静态方法。

Look at below example:

看下面的例子:

class Animal {
    static void eat() {
        System.out.println("animal is eating...");
    }
}

class Dog extends Animal {

    public static void main(String args[]) {

        Animal a = new Dog();
        a.eat(); // prints >> animal is eating...

    }

    static void eat() {
        System.out.println("dog is eating...");
    }
}

In dynamic binding, method is called depending on the type of referenceand not the type of object that the reference variable is holding Here static bindinghappens because method hiding is not a dynamic polymorphism. If you remove static keyword in front of eat() and make it a non static method then it will show you dynamic polymorphism and not method-hiding.

在动态绑定中,方法的调用取决于引用的类型,而不是引用变量所持有的对象的类型。这里发生静态绑定,因为方法隐藏不是动态多态。如果删除eat() 前面的static 关键字并使其成为非静态方法,那么它将向您显示动态多态性而不是方法隐藏。

i found the below link to support my answer: https://youtu.be/tNgZpn7AeP0

我找到了以下链接来支持我的回答:https: //youtu.be/tNgZpn7AeP0

回答by dalusC

In the case of the static binding type of object determined at the compile-time whereas in the dynamic binding type of the object is determined at the runtime.

在编译时确定对象的静态绑定类型的情况下,而在运行时确定对象的动态绑定类型的情况。



class Dainamic{

    void run2(){
        System.out.println("dainamic_binding");
    }

}


public class StaticDainamicBinding extends Dainamic {

    void run(){
        System.out.println("static_binding");
    }

    @Override
    void run2() {
        super.run2();
    }

    public static void main(String[] args) {
        StaticDainamicBinding st_vs_dai = new StaticDainamicBinding();
        st_vs_dai.run();
        st_vs_dai.run2();
    }

}