2017-11-23 104 views
5

Tôi đã đọc qua một số bài viết về liên kết tĩnhliên kết động bằng Java. Và tôi có những câu dưới đây (Tôi đã tìm kiếm rất nhiều nhưng không tìm thấy bất kỳ đề cập về nó chưa):Các vấn đề với ràng buộc tĩnh và liên kết động trong Java

Ví dụ, tôi có dòng mã sau đây:

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

gì chúng tôi đã biết là tại thời gian biên dịch, trình biên dịch sẽ kiểm tra xem có tồn tại định nghĩa phương thức cho speak() trong lớp Person và gọi nó nếu nó tồn tại. Và tại thời gian chạy, nó sẽ gọi phương thức speak() của đối tượng thực tế mà a trỏ (Đối tượng thực tế trong trường hợp này rõ ràng là Student)

Vì vậy, câu hỏi của tôi là lý do tại sao nó không trực tiếp gọi speak() phương thức của lớp Studenttại thời điểm biên dịch, nhưng đợi đến thời gian chạy để làm điều đó? Có lý do nào đằng sau chuyện này không?

+0

Vì việc biên dịch phần mềm của bạn khác với việc chạy phần mềm. –

+0

Bởi vì * bạn * đã nói với trình biên dịch rằng 'a' sẽ được coi là' Người' thay vì 'Học sinh'. Và tại sao nó phải biên dịch mã theo một cách khác với bạn yêu cầu? Bạn đang giả định lợi thế nào cho chiến lược khác nhau đó? – Holger

Trả lời

3

Khi mã biên dịch, đôi khi, không rõ phương thức nào cần được gọi. Nó chỉ có thể được xác định khi chạy.

Lấy mã đơn giản này làm ví dụ.

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) phương pháp có bất kỳ đối tượng đó đi ISA thử nghiệm Thú và gọi phương thức tương ứng của đối tượng đó. Như bạn có thể thấy, nó cũng loại bỏ trùng lặp mã vì chúng ta có thể sử dụng cùng một phương thức trên các kiểu đối tượng khác nhau.

Hy vọng địa chỉ này là mối quan tâm của bạn.

+0

Cảm ơn trước. Nhưng bạn có thể cung cấp một số chi tiết về "đôi khi, nó không phải là rõ ràng phương pháp cần phải được gọi" trên ví dụ của bạn ở trên? – DunDev

+0

animal.makeNoise(); ở đây, tại thời gian biên dịch nó không được biết loại của đối tượng. Vào thời gian chạy, bạn vượt qua một đối tượng động vật cụ thể và dựa trên đó, nó gọi phương thức tương ứng của con vật đó (ví dụ: Chó hoặc Mèo) –

3

Để hiểu chủ đề này, bạn nên biết quy trình tổng hợp và thời gian chạy là gì. Trong ngắn hạn, khi bạn xây dựng trình biên dịch ứng dụng của bạn đi qua tất cả các mã của bạn và kiểm tra tính nhất quán, an toàn và khả năng chạy. Nếu không có lỗi do trình biên dịch tạo ra, nó sẽ tạo ra các tệp class từ mã nguồn của bạn (java tệp). Khi ứng dụng đang chạy nó có nghĩa là các tệp class của bạn được tải vào bộ nhớ và JVM thực thi lệnh ứng dụng của bạn theo hướng dẫn.

Từ ví dụ của bạn:

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

quá trình Compilation: kiểm tra trình biên dịch dòng này: Person a = new Student(); cho sự an toàn loại (tương thích). Vì vậy, nếu sinh viên is a người biên dịch đi đến dòng tiếp theo khác nó không thành công. Trong dòng tiếp theo: a.speak(); trình biên dịch xem xét a loại, nhận thấy rằng đó là một Person và tìm kiếm phương thức speak() ở loại Person. Nếu phương thức đó không được thành lập bởi quá trình biên dịch trình biên dịch thất bại.

Runtime quá trình: Khi JVM thực thi dòng này: Person a = new Student(); nó đi qua quá trình khởi tạo từ đầu (lớp cha) xuống dưới (lớp trẻ).Trong dòng tiếp theo: a.speak(); JVM được tìm thấy student đối tượng thông qua tham chiếu a tìm phương thức speak() nếu được thành lập theo số Student thì thực thi nó, nếu không nó sẽ chạy phương thức speak() từ cấp độ gốc Person.

Một ví dụ từ đối tượng thừa kế:

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 
+0

cảm ơn bạn, bạn đang đưa ra một lời giải thích tuyệt vời .. nhưng tôi có một câu hỏi, đang nghiên cứu java từ javatpoint turorials, và từ liên kết này [liên kết tĩnh và ràng buộc động] (https://www.javatpoint.com/static-binding-and-dynamic-binding) Tôi đã hiểu rằng ràng buộc là hoạt động của kết nối một cuộc gọi phương thức với một phương thức cơ thể, nhưng tôi gặp một số khó khăn trong việc hiểu một số trường hợp, như trong ví dụ của bạn, bạn có thể sửa câu trả lời để thêm kiểu ràng buộc cho mỗi lời gọi phương thức không? hoặc thậm chí viết ở đây. –

+1

Trước tiên hãy xem [hướng dẫn] này (http://javaconceptoftheday.com/static-binding-and-dynamic-binding-in-java/). Nếu bạn có câu hỏi, tôi sẽ cập nhật câu trả lời của tôi – jibrahim

+0

Tôi tin rằng câu hỏi này sẽ xác định xem tôi có hiểu đúng hay không .. điều đó có nghĩa là ràng buộc tĩnh và động là các bước (không phải tùy chọn) và cả hai có thể xảy ra cùng một phương thức gọi để xác định thân phương thức cần được gọi là ?? –

0

Nếu tôi chỉ cần viết một lớp mục đích chung để kiểm tra bất kỳ loại xe như sau.

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

Tôi chỉ có thể biên dịch mã này với loại xe, mặc dù không có lớp con nào của xe đã được viết. Trong các khung công tác chung khai thác khả năng xử lý này dựa trên kiểu generic khi không có các kiểu cụ thể (các máy khách được tự do mở rộng hệ thống phân cấp lớp con). Trong những trường hợp như vậy Compiler sẽ chỉ đảm bảo rằng chiếc xe sẽ có ít nhất một lần thực hiện (thực hiện null như {} cũng được chấp nhận) sẽ có sẵn để không phá vỡ mã.

Các vấn đề liên quan