Vs. Dynamic Binding di Java

103

Saat ini saya sedang mengerjakan tugas untuk salah satu kelas saya, dan di dalamnya, saya harus memberikan contoh, menggunakan sintaks Java, pengikatan statis dan dinamis .

Saya memahami konsep dasar, bahwa pengikatan statis terjadi pada waktu kompilasi dan pengikatan dinamis terjadi pada waktu proses, tetapi saya tidak dapat mengetahui cara kerjanya secara spesifik.

Saya menemukan contoh online binding statis yang memberikan contoh ini:

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

Dan ini akan mencetak "hewan sedang makan" karena panggilan untuk callEatmenggunakan pengikatan statis , tapi saya tidak yakin mengapa ini dianggap pengikatan statis.

Sejauh ini tidak ada sumber yang saya lihat berhasil menjelaskan hal ini dengan cara yang dapat saya ikuti.

pengguna2309750
sumber
1
Perhatikan bahwa ada beberapa konsep berbeda yang disebut sebagai "mengikat". Dalam kasus khusus ini, untuk jenis pengikatan ini (yang melibatkan pilihan antara metode "tanda tangan" yang serupa tetapi tidak identik) kompilator (yang membuat keputusan "statis", karena tidak bervariasi pada waktu proses) memutuskan bahwa parameternya adalah "Hewan" karena itu adalah jenis (statis) dari variabel "a".
Hot Licks
(Ada bahasa di mana pilihan tanda tangan metode tertentu akan dibiarkan hingga runtime, dan callEat (Dog) akan dipilih.)
Hot Licks

Jawaban:

115

Dari postingan blog yang dikunjungi Javare :

Berikut beberapa perbedaan penting antara pengikatan statis dan dinamis:

  1. Pengikatan statis di Java terjadi selama waktu kompilasi sementara pengikatan dinamis terjadi selama runtime.
  2. private, finaldan staticmetode serta variabel menggunakan pengikatan statis dan terikat oleh kompiler sementara metode virtual terikat selama runtime berdasarkan objek runtime.
  3. Pengikatan statis menggunakan informasi Type( classdi Java) untuk pengikatan sementara pengikatan dinamis menggunakan objek untuk menyelesaikan pengikatan.
  4. Metode kelebihan beban terikat menggunakan pengikatan statis sementara metode yang diganti terikat menggunakan pengikatan dinamis saat runtime.

Berikut adalah contoh yang akan membantu Anda memahami pengikatan statis dan dinamis di Java.

Contoh Static Binding di 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 : Di dalam metode sortir Koleksi

Contoh Dynamic Binding di 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: Metode start di dalam Mobil

Maulik Patel
sumber
43
dan dari javarevisited.blogspot.in/2012/03/…
Gopal Gopi
11
Saya masih tidak mengerti perbedaannya,
technazi
9
@technazi statis mengikat hanya melihat jenis (apa yang pernah sebelum sama misalnya Koleksi c = baru HashSet (); jadi itu akan dilihat hanya sebagai objek koleksi ketika infact itu adalah hashset). Pengikatan dinmik memperhitungkan objek sebenarnya (apa setelah sama sehingga benar-benar mengenali HashSet-nya).
Tandai
22

Menghubungkan panggilan metode ke badan metode disebut Binding. Seperti yang dikatakan Maulik, "Pengikatan statis menggunakan informasi Jenis (Kelas di Java) untuk pengikatan, sedangkan pengikatan dinamis menggunakan Objek untuk menyelesaikan pengikatan." Jadi kode ini:

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

Akan menghasilkan hasil: anjing sedang makan ... karena menggunakan referensi objek untuk menemukan metode yang akan digunakan. Jika kita mengubah kode di atas menjadi ini:

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

Ini akan menghasilkan: hewan sedang makan ... karena ini adalah metode statis, jadi menggunakan Jenis (dalam hal ini Hewan) untuk menyelesaikan metode statis mana yang harus dipanggil. Selain metode statis, metode privat dan final menggunakan pendekatan yang sama.

Tuan Q
sumber
1
Mengapa Java tidak dapat menyimpulkan bahwa aitu sebenarnya adalah Dogwaktu kompilasi?
Minh Nghĩa
4

Kompilator hanya mengetahui bahwa tipe "a" adalah Animal; ini terjadi pada waktu kompilasi, karena itu disebut pengikatan statis (Metode overloading). Tetapi jika itu adalah pengikatan dinamis maka itu akan memanggil Dogmetode kelas. Berikut adalah contoh pengikatan dinamis.

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

Hasil: Metode makan di dalam Anjing

pengguna2378479
sumber
Bukankah ini akan memunculkan kesalahan kompilasi seperti "Tidak dapat mereferensikan kelas / metode non-statis dari konteks statis"? Saya selalu bingung dengan itu, mengingat utama itu statis. Terima kasih sebelumnya.
Amnor
4

Nah untuk memahami bagaimana mengikat statis dan dinamis sebenarnya bekerja? atau bagaimana mereka diidentifikasi oleh compiler dan JVM?

Mari kita ambil contoh di bawah ini di mana Mammalkelas induk yang memiliki metode speak()dan Humankelas diperpanjang Mammal, mengganti speak()metode dan kemudian membebani lagi dengan 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
    }
}

Ketika kita mengkompilasi kode di atas dan mencoba untuk melihat bytecode yang digunakan javap -verbose OverridingInternalExample, kita dapat melihat bahwa compiler menghasilkan tabel konstan di mana ia memberikan kode integer ke setiap panggilan metode dan kode byte untuk program yang telah saya ekstrak dan dimasukkan dalam program itu sendiri ( lihat komentar di bawah setiap panggilan metode)

Program Bytecode

Dengan melihat kode di atas kita dapat melihat bahwa bytecode dari humanMammal.speak(), human.speak()dan human.speak("Hindi")sama sekali berbeda ( invokevirtual #4, invokevirtual #7, invokevirtual #9) karena compiler mampu membedakan antara mereka berdasarkan daftar argumen dan referensi kelas. Karena semua ini diselesaikan pada waktu kompilasi secara statis, itulah sebabnya Overloading Metode dikenal sebagai Polimorfisme Statis atau Binding Statis. .

Tetapi bytecode for anyMammal.speak()and humanMammal.speak()is same ( invokevirtual #4) karena menurut kompiler kedua metode dipanggilMammal referensi.

Jadi sekarang pertanyaannya muncul jika kedua pemanggilan metode memiliki bytecode yang sama lalu bagaimana JVM mengetahui metode mana yang harus dipanggil?

Jawabannya tersembunyi di bytecode itu sendiri dan itu adalah invokevirtualset instruksi. JVM menggunakaninvokevirtual instruksi untuk memanggil Java yang setara dengan metode virtual C ++. Di C ++ jika kita ingin mengganti satu metode di kelas lain, kita perlu mendeklarasikannya sebagai virtual, Tetapi di Java, semua metode adalah virtual secara default karena kita dapat mengganti setiap metode di kelas anak (kecuali metode privat, final dan statis).

Di Java, setiap variabel referensi memiliki dua pointer tersembunyi

  1. Sebuah pointer ke tabel yang menyimpan metode objek dan pointer ke objek Kelas. misal [berbicara (), berbicara (String) objek Kelas]
  2. Sebuah pointer ke memori yang dialokasikan di heap untuk data objek tersebut, misalnya nilai variabel instance.

Jadi semua referensi objek secara tidak langsung memiliki referensi ke tabel yang menampung semua referensi metode objek itu. Java telah meminjam konsep ini dari C ++ dan tabel ini dikenal sebagai tabel virtual (vtable).

Vtable adalah struktur seperti array yang menyimpan nama metode virtual dan referensinya pada indeks array. JVM hanya membuat satu vtabel per kelas saat memuat kelas ke dalam memori.

Jadi setiap kali JVM menemukan invokevirtualset instruksi, ia memeriksa vtable kelas itu untuk referensi metode dan memanggil metode tertentu yang dalam kasus kami adalah metode dari objek bukan referensi.

Karena semua ini diselesaikan hanya pada saat runtime dan pada saat runtime JVM mengetahui metode mana yang akan dipanggil, itulah mengapa Metode Overriding dikenal sebagai Dynamic Polymorphism atau hanya Polymorphism atau Dynamic Binding .

Anda dapat membacanya lebih detail di artikel saya Bagaimana JVM Menangani Metode Overloading dan Overriding Secara Internal .

Naresh Joshi
sumber
2

Ada tiga perbedaan utama antara pengikatan statis dan dinamis saat mendesain kompiler dan bagaimana variabel dan prosedur ditransfer ke lingkungan runtime . Perbedaan tersebut adalah sebagai berikut:

Pengikatan Statis : Dalam pengikatan statis, tiga masalah berikut dibahas:

  • Definisi prosedur

  • Deklarasi nama (variabel, dll.)

  • Lingkup deklarasi

Dynamic Binding : Tiga masalah yang muncul dalam dynamic binding adalah sebagai berikut:

  • Aktivasi prosedur

  • Mengikat nama

  • Seumur hidup yang mengikat

hexpheus
sumber
1

Dengan metode statis di kelas induk dan anak: 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

Pengikatan Dinamis:

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

Semua jawaban di sini benar tetapi saya ingin menambahkan sesuatu yang hilang. ketika Anda menimpa metode statis, sepertinya kita menimpanya tetapi sebenarnya itu bukan penimpaan metode. Sebaliknya itu disebut metode persembunyian. Metode statis tidak dapat diganti di Java.

Lihat contoh di bawah ini:

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

Dalam pengikatan dinamis, metode disebut tergantung pada jenis referensi dan bukan jenis objek yang dipegang oleh variabel referensi. Di sini pengikatan statis terjadi karena penyembunyian metode bukanlah polimorfisme dinamis. Jika Anda menghapus kata kunci statis di depan eat () dan menjadikannya sebagai metode non-statis, maka itu akan menunjukkan kepada Anda polimorfisme dinamis dan bukan penyembunyian metode.

saya menemukan tautan di bawah ini untuk mendukung jawaban saya: https://youtu.be/tNgZpn7AeP0

Namrata M
sumber
0

Dalam kasus jenis pengikatan statis objek ditentukan pada waktu kompilasi sedangkan dalam jenis pengikatan dinamis objek ditentukan pada waktu proses.



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

}
dalusC
sumber
-3

Karena kompilator mengetahui pengikatan pada waktu kompilasi. Jika Anda memanggil sebuah metode pada sebuah antarmuka, misalnya, maka compiler tidak dapat mengetahui dan pengikatan diselesaikan pada saat runtime karena objek sebenarnya yang memiliki metode yang dipanggil dapat menjadi salah satu dari beberapa. Oleh karena itu, itu adalah runtime atau dynamic binding.

Permintaan Anda terikat pada kelas Animal pada waktu kompilasi karena Anda telah menentukan tipenya. Jika Anda meneruskan variabel itu ke metode lain di tempat lain, tidak ada yang akan tahu (selain Anda karena Anda menulisnya) kelas sebenarnya apa itu. Satu-satunya petunjuk adalah jenis Hewan yang dideklarasikan.

Aaron
sumber
1
Tidak benar. Kompiler akan membuat keputusan yang sama persis jika Anda melakukan panggilan pada sebuah antarmuka.
Hot Licks
@ HotLicks Keputusan yang sama persis seperti apa? Jika Anda mengkompilasi kelas untuk menjalankan metode foo (String str) pada sebuah antarmuka, kompilator tidak dapat mengetahui pada waktu kompilasi kelas apa yang harus digunakan metode foo (String str). Hanya pada waktu proses pemanggilan metode dapat diikat ke implementasi kelas tertentu.
Aaron
Tetapi pengikatan statis ke tanda tangan metode tertentu masih akan terjadi. Kompilator masih akan memilih callEat (Animal) daripada callEat (Dog).
Hot Licks
@HotLicks Tentu, tapi bukan itu pertanyaan yang saya jawab. Mungkin itu menyesatkan saya: DI membandingkannya dengan pemanggilan pada antarmuka untuk menyoroti bahwa pada waktu kompilasi kompilator tidak dapat mengetahui apakah Anda benar-benar membuat contoh subkelas / implementasi yang berbeda atau tidak.
Aaron
Sebenarnya, pada saat kompilasi kompiler dapat (dalam hal ini) dengan sangat mudah mengetahui bahwa "a" adalah Dog. Bahkan, sepertinya harus berusaha keras untuk "melupakan" itu.
Hot Licks