2015-11-18 23 views
10

Tôi không thể hiểu tại sao biến riêng tư là null ngay cả khi nội tuyến được khởi tạo. Dưới đây là một đoạn mã của tôi:Java: trường cuối cùng nội tuyến riêng tư cuối cùng là null

public abstract class A { 
    public A() { 
     initialize(); 
    } 

    protected abstract void initializeLayout(); 
    protected void initialize() { 
     // Do something 
     initializeLayout(); 
    } 
} 

public abstract class B extends A { 
    private final Object myVariable = new Object(); 

    @Override 
    protected void initializeLayout() { 
     // Do something with myVariable 
    } 
} 

Vâng, khi mã này đạt B.initailizeLayout, myVariable là NULL. Tôi nghĩ rằng trường nội tuyến đã được khởi tạo trước mọi thứ khác, ngay cả trước constructor. Tôi có sai với thứ gì đó không?

+1

Heck là 'varType' là gì? Chỉ đề cập đến như một người giữ chỗ? Vì vậy, giống như bất kỳ đối tượng? – 3kings

+0

Vâng, tôi chỉ là một trình giữ chỗ. Tôi nên đã sử dụng một cái gì đó thích hợp hơn có lẽ ngay cả khi tôi nghĩ rằng nó là khá rõ ràng – Andrea

+0

chỉ cần sử dụng 'Object' như một giữ chỗ – redFIVE

Trả lời

19

Nhà xây dựng của siêu hạng A (gọi initialize() gọi B 's initializeLayout()) được thực hiện trước khi các biến mẫu của tiểu nhóm B được khởi tạo. Do đó, biến cá thể của bạn myVariable vẫn là null tại thời điểm đó.

+0

Chà, không biết điều đó. Cảm ơn bạn – Andrea

2

Các (có thể tiềm ẩn) constructor của trẻ em B sẽ làm như sau:

  • đã mọi lĩnh vực zeroed (null, 0, 0.0, false)
  • gọi constructor của siêu Một
    • gọi B.initializeLayout với tất cả các lĩnh vực là null
  • khởi tạo tất cả các lĩnh vực được phân công trong việc kê khai của họ
  • gọi số còn lại của hàm tạo

Vì vậy, những gì bạn đang cố gắng làm là rất dễ xảy ra trong java. Nhiều trình kiểm tra kiểu đánh dấu mã này là kiểu xấu (gọi phương thức không phải cuối cùng trong hàm tạo).

Bạn có thể làm

private /*final*/ Object myVariable; // Must not be initialized! 

@Override 
protected void initializeLayout() { 
    myVariable = new Object(); 
    // Do something with myVariable 
} 

Có myVariable khởi tạo sẽ khởi myVariable sau khi cuộc gọi đến initializeLayout.

Tốt hơn để tránh.

+0

tốt đẹp, tôi thích lý do bạn đưa ra để tránh loại hình này. Nhưng những gì nó có với các từ ** gọi phương pháp không cuối cùng trong constructor **? bạn có thể xây dựng phần đó hoặc cung cấp một số liên kết hữu ích không. – rajuGT

+1

@rajuGT Một lớp cơ sở không thể gọi một phương thức lớp con không được khai báo trên lớp cơ sở, do đó bất kỳ phương thức nào được gọi từ hàm tạo phải được khai báo trên lớp cơ sở. Bất kỳ phương thức lớp 'final' cơ sở nào cũng không thể được ghi đè bởi lớp con, vì vậy việc thực thi lớp cơ sở sẽ được sử dụng (an toàn, vì các thành viên của lớp cơ sở được khởi tạo trước khi hàm tạo được gọi). Ngược lại, bất kỳ phương pháp nào không phải là 'cuối cùng' có thể bị ghi đè bởi đứa trẻ và do đó chịu sự nguy hiểm này. Do đó, các phương thức không phải 'không phải' chắc chắn không an toàn để gọi từ hàm tạo. –

+1

@PlatinumAzure đã nói điều đó. Gọi phương thức cuối cùng (= không thể ghi đè) như phương thức riêng tư là an toàn (nếu chính nó không gọi là bất kỳ overridable nào). Do đó nếu một trong những cuộc gọi một setter trong một nhà xây dựng tốt hơn làm cho nó cuối cùng. –

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