2013-08-12 39 views
5

Hãy xem xét các đoạn mã sau:Phương pháp trọng và thừa kế trong java

class A{ /* assume static and non static block are here */ } 
class B extends A{ /* assume static and non static block are here */ } 

Trong phương pháp chính,

new B(); 

Vì vậy, thứ tự của các khởi tạo sẽ là:

  1. thành viên tĩnh khởi tạo cho lớp A
  2. thành viên tĩnh initializati trên cho lớp B
  3. phi thành viên tĩnh khởi cho lớp Một
  4. sau đó thực thi mã bên trong constructor Một thành viên
  5. phi tĩnh khởi cho lớp B
  6. sau đó thực thi mã bên trong constructor B

Bây giờ, hãy xem đoạn mã này,

class A{ 
    A(){ 
     this.m(); //line 1 
    } 

    void m(){ 
     System.out.println("A.m()"); 
    } 
    } 

    class B extends A{ 
    void m(){ 
     System.out.println("B.m()"); 
    } 
    } 

Trong phương pháp chính,

new B(); 

Khi mã của hàm tạo A đang được thực hiện, nó chỉ có thể thấy phương thức m trong lớp A vì các thành viên không tĩnh chưa được khởi tạo cho lớp B (theo thứ tự tôi đã đề cập). Tuy nhiên kết quả là "B.m()". (phương pháp của lớp phụ đã được thực hiện) Ai đó có thể giải thích những gì đang xảy ra ở đây (phương pháp overridng) xem xét thứ tự mà tôi đã đề cập?

+0

[This] (http://stackoverflow.com/a/15327631/335858) nên mang lại một số rõ ràng, mặc dù nó không phải là một bản sao chính xác. – dasblinkenlight

+1

có thể trùng lặp của [Thứ tự khởi tạo lớp Java và phương thức ghi đè] (http: // stackoverflow.com/questions/18138397/java-class-initialization-order-and-overridden-methods) –

+2

Bạn nên ** không bao giờ, Không bao giờ, KHÔNG BAO GIỜ ** gọi các phương thức ảo trong một hàm tạo/hủy. Đây là ý tưởng tồi tệ * xác định * khủng khiếp. Việc gọi các phương thức 'final' instance có thể là * okay *, nhưng tôi thường coi nó là một ý tưởng * xấu * và tránh nó khi có thể. Đó là một ý tưởng * khủng khiếp * mà nó được đề cập trong Hiệu ứng C++ của Scott Meyer và trong khi câu hỏi của bạn * là * về Java, những lý do chính mà anh ta đưa ra ở đây áp dụng ở đây. Đừng làm thế. – jason

Trả lời

3

Ghi đè phương thức xảy ra cho dù lớp bắt nguồn đã được khởi tạo hay chưa.

Đây là lý do tại sao bạn nên tránh gọi các phương thức ảo trong trình khởi tạo.

8

Khi mã của hàm tạo A đang được thực thi, nó chỉ có thể thấy phương thức m trong lớp A vì các thành viên không tĩnh chưa được khởi tạo cho lớp B (theo thứ tự tôi đã đề cập).

Bạn giả định rằng các phương pháp là một phần của "thành viên không tĩnh" được khởi tạo. Đó không phải là trường hợp - nó thực sự là vấn đề của các trường trong B được khởi tạo khi hàm tạo A hoàn tất.

Ngay sau khi một đối tượng được tạo trong Java, loại của nó được đặt và không bao giờ thay đổi. Đủ không gian được phân bổ cho tất cả các trường - nhưng các trường thực tế là được khởi tạo từ đầu hệ thống phân cấp thừa kế xuống. Vì vậy, có, nếu bạn gọi một phương thức ghi đè từ một hàm tạo, nó sẽ thực thi trong một ngữ cảnh mà một số trường mà nó muốn sử dụng không được khởi tạo - vì vậy bạn nên tránh làm điều đó nếu có thể.

+0

Jon, Đã có câu hỏi nhanh, Tôi tự hỏi nếu tôi đang thực hiện điều này đúng hướng; Cách đơn giản để hiểu điều này là, khi chúng ta có một thể hiện của lớp B, đó là đối tượng đang hoạt động ở đây. Vì vậy, B mới(), sẽ gọi hàm tạo siêu cho A(), trong đó this.m() tương đương với B(). M() mới vì phương thức này bị ghi đè. – JNL

+0

@ JNL: Vâng nó không thực sự tương đương với 'mới B(). M() 'bởi vì nó không tạo ra một đối tượng mới ... –

+0

Jon, Đồng ý nó không tạo ra một đối tượng mới, ý tôi là, nếu Tôi đặt chính xác, tôi có thể nói this.m() sẽ được tương đương với objectOfClassB.m() được gọi là chính, kể từ khi thread chính được thực hiện chương trình có một đối tượng mới B(). Tôi hy vọng nó không khó hiểu? – JNL

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