ChatGPT解决这个技术问题 Extra ChatGPT

Static Vs. Dynamic Binding in Java

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

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 callEat uses static binding, but I'm unsure as to why this is considered static binding.

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

Note that there are several different concepts that are referred to as "binding". In this particular case, for this type of binding (which involves a choice between similar but not identical method "signatures") the compiler (which makes "static" decisions, since they do not vary at run time) decides that the parameter is an "Animal" because that is the (static) type of the variable "a".
(There are languages where the choice of the specific method signature would be left until runtime, and callEat(Dog) would be selected.)

A
Andrew

From Javarevisited blog post:

Here are a few important differences between static and dynamic binding: Static binding in Java occurs during compile time while dynamic binding occurs during runtime. private, final and static methods and variables use static binding and are bonded by compiler while virtual methods are bonded during runtime based upon runtime object. Static binding uses Type (class in Java) information for binding while dynamic binding uses object to resolve binding. 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


I still don't understand the difference,
@technazi static binding just looks at the type (what ever is before the equals e.g Collection c = new HashSet(); so it will be seen as just a collection object when infact it is a hashset). Dyanmic binding takes into account the actual object (whats after the equals so it actually recognises its a HashSet).
Very good example. But I am confused with this scenario. Lets say StaticBindingTestChild extends StaticBindingTest and overrided botht the overloaded methods. Now if we do something like this: Collection c = new HashSet(); StaticBindingTest et = new StaticBindingTestChild(); et.sort(c); will it be static or dynamic binding?
For another discussion and example on what late or dynamic binding is you may also want to look at this question: stackoverflow.com/questions/19098459/…
r
realPK

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 :

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:

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.


Why can't Java deduce that a is actually a Dog at compile time?
N
Naresh Joshi

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

Let's take below example where Mammal is a parent class which has a method speak() and Human class extends Mammal, overrides the speak() method and then again overloads it with 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)

https://i.stack.imgur.com/zo2QU.png

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 Overloading is known as Static Polymorphism or Static Binding.

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

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

Well, the answer is hidden in the bytecode itself and it is invokevirtual instruction set. JVM uses the invokevirtual instruction 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).

In Java, every reference variable holds two hidden pointers

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] A pointer to the memory allocated on the heap for that object’s data e.g. values of instance variables.

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).

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.

So whenever JVM encounter with a invokevirtual instruction 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.

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

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


A
Arvindh Mani

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 Dog class method. Here is an example of dynamic binding.

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


Wouldn't this throw a compilation error such as "Cannot reference a non-static class/method from a static context"? I'm always confused with that, having in mind that main is static. Thanks in advance.
h
hexpheus

There are three major differences between static and dynamic binding while designing the compilers and how variables and procedures are transferred to the runtime environment. 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


S
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

N
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 cannot be overridden in 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 reference and 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.

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


K
Krishan

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();
    }

}

A
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.


Not true. The compiler would make the exact same decision if you were doing a call on an interface.
@HotLicks Exact same decision as what? If you compile a class to invoke a foo(String str) method on an interface, the compiler cannot know at compile time what class the foo(String str) method should be invoked upon. Only at runtime can the method invocation be bound to a particular class implementation.
But static binding to the specific method signature still would occur. The compiler would still pick callEat(Animal) over callEat(Dog).
@HotLicks Sure, but that's not the question I answered. Perhaps it was misleading of me :D I compared it to invoking on an interface to highlight that at compile time the compiler cannot know whether you actually instantiated a different subclass/implementation or not.
Actually, at compile time the compiler can (in this case) very easily could know that "a" is a Dog. In fact, it likely has to go to some lengths to "forget" that.