web-dev-qa-db-fra.com

Vs statiques Liaison dynamique en Java

Je suis actuellement en train de faire un devoir pour l'une de mes classes et je dois y donner des exemples, en utilisant la syntaxe Java, de static et dynamic binding .

Je comprends le concept de base selon lequel la liaison statique se produit au moment de la compilation et la liaison dynamique au moment de l'exécution, mais je ne peux pas comprendre comment elles fonctionnent réellement.

J'ai trouvé un exemple de liaison statique en ligne qui donne cet exemple:

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

Et que cela afficherait "animal mange" parce que l'appel à callEat utilise une liaison statique , mais je ne suis pas sûr de pourquoi ceci est considéré comme une liaison statique.

Jusqu'à présent, aucune des sources que j'ai vues n'a réussi à expliquer cela d'une manière que je puisse suivre.

65
user2309750

De Article de blog Javarevisited :

Voici quelques différences importantes entre la liaison statique et dynamique:

  1. La liaison statique en Java se produit pendant la compilation tandis que la liaison dynamique se produit pendant l'exécution. 
  2. Les méthodes et variables private, final et static utilisent une liaison statique et sont liées par le compilateur, tandis que les méthodes virtuelles sont liées lors de l'exécution, en fonction de l'objet d'exécution. 
  3. La liaison statique utilise les informations Type (class en Java) pour la liaison, tandis que la liaison dynamique utilise un objet pour résoudre la liaison. 
  4. Les méthodes surchargées sont liées à l'aide d'une liaison statique, tandis que les méthodes remplacées sont liées à l'aide d'une liaison dynamique au moment de l'exécution. 

Voici un exemple qui vous aidera à comprendre les liaisons statiques et dynamiques en Java. 

Exemple de liaison statique en 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: Méthode de tri Inside Collection 

Exemple de liaison dynamique en 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");
    }
}

Sortie: Méthode de démarrage interne de la voiture

84
Maulik Patel

La connexion d'un appel de méthode au corps de la méthode s'appelle Binding. Comme le dit Maulik, "La liaison statique utilise des informations de type (Classe en Java) pour la liaison, tandis que la liaison dynamique utilise Object pour résoudre la liaison." Donc ce 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...");
    }
}

Produira le résultat: chien mange ... parce qu'il utilise la référence de l'objet pour trouver la méthode à utiliser. Si nous changeons le code ci-dessus en ceci:

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...");
    }
}

Il produira: un animal mange ... parce que c'est une méthode statique, il utilise donc Type (dans ce cas, Animal) pour résoudre la méthode statique à appeler. À côté des méthodes statiques, les méthodes privées et finales utilisent la même approche.

10
Mr.Q

Le compilateur sait seulement que le type de "a" est Animal; cela se produit lors de la compilation, c'est pourquoi on l'appelle liaison statique (surcharge de méthode). Mais s'il s'agit d'une liaison dynamique, elle appelle la méthode de classe Dog. Voici un exemple de liaison dynamique.

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

Sortie: À l'intérieur de manger méthode de chien

3
user2378479

Il existe trois différences majeures entre la liaison statique et la liaison dynamique lors de la conception des compilateurs et le mode de transfert de variables et procedures dans l'environnement runtime . Ces différences sont les suivantes:

Static Binding: dans la liaison statique, trois problèmes suivants sont discutés:

  • Définition d'une procédure

  • Déclaration d'un nom (variable, etc.)

  • Portée de la déclaration 

Dynamic Binding: Trois problèmes rencontrés dans la liaison dynamique sont les suivants:

  • Activation d'une procédure

  • Reliure d'un nom

  • Durée de vie d'une reliure

1
alighdev

Avec la méthode statique dans les classes parent et enfant: 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

Reliure dynamique:

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
0
Soudipta Dutta

Bien pour comprendre comment fonctionne static et dynamic bind? ou comment ils sont identifiés par le compilateur et JVM?

Prenons l'exemple suivant où Mammal est une classe parent qui a une méthode speak() et une classe Human extend Mammal, substitue la méthode speak() et la surcharge à nouveau avec 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
    }
}

Lorsque nous compilons le code ci-dessus et essayons de regarder le bytecode en utilisant javap -verbose OverridingInternalExample, nous pouvons voir que le compilateur génère une table constante dans laquelle il attribue des codes entiers à chaque appel de méthode et code octet du programme que j'ai extrait et inclus dans le programme lui-même. (voir les commentaires ci-dessous chaque appel de méthode)

 Program Bytecode

En regardant le code ci-dessus, nous pouvons voir que les bytecodes de humanMammal.speak(), human.speak() et human.speak("Hindi") sont totalement différents (invokevirtual #4, invokevirtual #7, invokevirtual #9) car le compilateur est en mesure de les différencier en fonction de la liste d'arguments et de la référence de classe. Parce que tout cela est résolu statiquement au moment de la compilation, c’est pourquoi Method Overloading est appelé Static Polymorphism ou Static Binding.

Mais le bytecode pour anyMammal.speak() et humanMammal.speak() est identique (invokevirtual #4) car, selon le compilateur, les deux méthodes sont appelées avec une référence Mammal.

Alors maintenant, la question vient si les deux appels de méthode ont le même bytecode, alors comment JVM sait-il quelle méthode appeler?

Eh bien, la réponse est cachée dans le bytecode lui-même et il s'agit d'un jeu d'instructions invokevirtual. La machine virtuelle Java utilise l'instruction invokevirtual pour appeler l'équivalent Java des méthodes virtuelles C++. En C++, si nous voulons remplacer une méthode dans une autre classe, nous devons la déclarer comme virtuelle. Cependant, en Java, toutes les méthodes sont virtuelles par défaut, car nous pouvons remplacer toutes les méthodes de la classe enfant (à l'exception des méthodes privées, finales et statiques).

En Java, chaque variable de référence contient deux pointeurs cachés

  1. Un pointeur sur une table contenant à nouveau les méthodes de l'objet et un pointeur sur l'objet Class. par exemple. [speak (), speak (String) Objet de classe]
  2. Un pointeur sur la mémoire allouée sur le tas pour les données de cet objet, par ex. valeurs des variables d'instance.

Ainsi, toutes les références d'objet contiennent indirectement une référence à une table qui contient toutes les références de méthode de cet objet. Java a emprunté ce concept à C++ et cette table est appelée table virtuelle (vtable).

Une vtable est une structure semblable à un tableau qui contient les noms de méthodes virtuelles et leurs références sur des index de tableaux. La machine virtuelle Java ne crée qu'une seule table virtuelle par classe lorsqu'elle charge la classe en mémoire.

Ainsi, chaque fois que la machine virtuelle Java rencontre un jeu d'instructions invokevirtual, elle vérifie la référence de la méthode dans la table vtable de cette classe et appelle la méthode spécifique, qui dans notre cas est la méthode d'un objet et non la référence.

Etant donné que tout cela est résolu uniquement à l'exécution et à l'exécution, JVM sait quelle méthode utiliser, raison pour laquelle Method Overriding est appelé Dynamic Polymorphism ou simplement Polymorphism ou Dynamic Contraignant.

Vous pouvez le lire plus en détail sur mon article Comment la machine virtuelle Java gère-t-elle la surcharge et la substitution de méthodes en interne .

0
Naresh Joshi