2013-02-25 84 views
5

Có một mã được đưa ra như một nhiệm vụ cho một nhà phát triển Java cơ sở. Tôi sử dụng Java trong năm năm và đoạn mã này hoàn toàn khó hiểu cho tôi:Java: chuỗi khởi tạo của đối tượng

public class Main { 

    String variable; 

    public static void main(String[] args) { 
     System.out.println("Hello World!"); 
     B b = new B(); 
    } 

    public Main(){ 
     printVariable(); 
    } 

    protected void printVariable(){ 
     variable = "variable is initialized in Main Class"; 
    } 
} 

public class B extends Main { 

    String variable = null; 

    public B(){ 
     System.out.println("variable value = " + variable); 
    } 

    protected void printVariable(){ 
     variable = "variable is initialized in B Class"; 
    } 
} 

Kết quả sẽ là:

Hello World! 
variable value = null 

Nhưng nếu chúng ta thay đổi String variable = null;-String variable; chúng ta sẽ có:

Hello World! 
variable value = variable is initialized in B Class 

Kết quả thứ hai rõ ràng hơn đối với tôi. Vì vậy, như xa như tôi biết trình tự của inizialisation trong Java như thế này:

  • Chúng tôi đi vào thư mục gốc của hệ thống phân cấp lớp (cho Java nó luôn Object class), khi chúng tôi đến lớp cha mẹ gốc này :
    • Tất cả các trường dữ liệu tĩnh được khởi tạo;
    • Tất cả các bộ khởi tạo trường tĩnh và khối khởi tạo tĩnh được thực thi;
    • Tất cả các trường dữ liệu không tĩnh được khởi tạo;
    • Tất cả các trình khởi tạo trường không tĩnh và các khối khởi tạo không tĩnh được thực thi;
    • Hàm tạo mặc định được thực hiện;
  • Sau đó, chúng tôi lặp lại quy trình cho lớp con cơ bản.

Cũng có bài trong đó mô tả hành vi của các từ khóa this trong bối cảnh của một lớp cha - Calling base class overridden function from base class method

Dựa trên các quy tắc đưa ra ở trên, tôi giả sử có chuỗi như thế này:

  1. Chúng ta sẽ tạo một thể hiện mới của lớp B;
  2. Chúng tôi chuyển đến lớp học Main;
  3. Khởi tạo main.variable bằng không;
  4. Sau đó, chúng tôi chuyển sang hàm tạo mặc định của lớp Main;
  5. Phương thức gọi phương thức xây dựng b.printVariable() trong lớp Main; (Tại sao nó không gọi main.printvariable Chúng tôi không có this từ khóa ở đây?).
  6. Trường b.variable "biến được khởi tạo trong B Class"
  7. Bây giờ chúng ta trở về với lớp B;
  8. Chúng tôi phải khởi tạo trường b.variable với giá trị null, tôi có đúng không ?;
  9. Các constructor mặc định của lớp B thực hiện

Xin vui lòng, ai đó có thể đưa ra một giải thích đầy đủ và đầy đủ về cách chuỗi inizialisation thừa kế này làm việc.Và tại sao thay đổi String variable = null; thành String variable; dẫn đến đầu ra khác.

+1

printVariable() là một tên phương pháp khá gây hiểu nhầm - nên được nhiều hơn như setVariable () – Jimmt

+1

Bạn đã viết java được 5 năm và bạn không biết cách sử dụng trình gỡ rối? (Bước qua mã của bạn sẽ cho bạn thấy chính xác những gì đang xảy ra và theo thứ tự nào). –

+0

@BrianRoach Chắc chắn tôi có thể sử dụng trình gỡ lỗi và tôi cũng đã thử javap -v -c B.class. Nhưng mỗi khi tôi thấy các nhiệm vụ như vậy đối với một nhà phát triển java hoặc câu hỏi phỏng vấn, tôi cố gắng dự đoán đầu ra và hiểu nó, tại sao nó hoạt động như thế này và điều gì sẽ xảy ra nếu tôi sửa đổi mã một chút. Bước qua không giải thích quy tắc và lý do của quá trình thực hiện. – INlHELL

Trả lời

8

Trình tự là:

  1. Main -> "Xin chào"
  2. Main -> new B()
  3. B() -> Main() -> b.printVariable() -> đặt biến
  4. Quay lại initialisi ng B, do đó biến = null xảy ra.

Về cơ bản, đối tượng siêu chính() được xây dựng trước bất kỳ sự kiện intialisation nào của lớp B. Điều này có nghĩa là biến = null xảy ra sau đó. Điều này có ý nghĩa như nếu không B có thể phá vỡ sự khởi tạo của chính.

Joshua Bloch bao gồm rất nhiều nền tảng tốt trong cuốn sách java hiệu quả của ông về cách thừa kế nguy hiểm là để có được quyền, tôi sẽ giới thiệu nó.

+0

Cảm ơn bạn rất nhiều vì lời giải thích, cũng cảm ơn rất nhiều cho cuốn sách mà bạn đã đề cập tôi sẽ đọc kỹ nó một lần nữa. – INlHELL

2

Trước tiên, bạn cần phải hiểu, điều gì sẽ xảy ra khi bạn viết variable = null;. Khi nào mã được thực hiện. Điều này về cơ bản xác định đầu ra.

Trước khi bắt đầu, tôi cũng nên đề cập rằng khi bạn tạo một đối tượng class B, chức năng printVariable() của lớp chính không được gọi. Thay vào đó, luôn luôn gọi số printVariable() của B.

Lưu ý điều này, khi bạn có variable = null, việc thực hiện cho hàm tạo B sẽ bắt đầu. Đầu tiên, Main() sẽ được gọi, sẽ gọi phương thức printVariable(). Cuối cùng, variable=null, sẽ được gọi là ghi đè biến số variable.

Trong trường hợp khác, nơi bạn không khởi tạo variable=null, variable được đặt bởi hàm printVariable() sẽ không bị ghi đè, do đó bạn nhận được những gì bạn mong đợi.

Nói tóm lại, đây là thứ tự thực hiện các báo cáo, khi bạn làm new B():

Main()  //super constructor 
    B#printVariable() 
    initializtion of variables in B's constructor (if any) [i.e. variable=null, if present] 
+0

cảm ơn bạn rất nhiều, lời giải thích của bạn làm rõ mã này hoàn toàn. Những gì tôi không nhận được, có thể khởi tạo trường theo cách như vậy: super_class-> method_of_child_class-> field_of_child_class và trường này có thể bị ghi đè (trong trường hợp trường không phải là rỗng) trong quá trình khởi tạo con lớp học. – INlHELL

1

Đây là một bài tập hay! Nhưng nó không phải là một câu hỏi công bằng để hỏi các nhà phát triển cơ sở. Cái này dành cho người cao niên. Tuy nhiên, để làm cho văn bản này hữu ích trong cuộc phỏng vấn kỹ thuật, tôi đã sửa đổi nó bằng cách thêm một đối số cho constructor của chi tiết:

public Main(String something){ 
printVariable(); 
} 

Nếu người đó sẽ trả lời những gì sẽ xảy ra, sau đó loại bỏ các lập luận và hỏi những câu hỏi ban đầu . Nếu người đó không trả lời - không cần phải tiếp tục - anh ấy là học sinh cơ sở.

Bạn cũng có thể loại bỏ các vòng bảo vệ trong lớp B và hỏi điều gì sẽ xảy ra nếu bạn có một mục tiêu không phải thuê người này :)

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