2015-06-15 25 views
53

Sau đây không biên dịch, đưa ra một 'bất hợp pháp mong tham khảo' thông điệp:Tại sao hai chương trình có lỗi tham chiếu về phía trước trong khi chương trình thứ ba thì không?

class StaticInitialisation { 

    static 
    { 
     System.out.println("Test string is: " + testString); 
    } 

    private static String testString; 

    public static void main(String args[]) { 
     new StaticInitialisation(); 
    } 
} 

Tuy nhiên, sau đây không biên dịch:

class InstanceInitialisation1 { 

    { 
     System.out.println("Test string is: " + this.testString); 
    } 

    private String testString; 

    public static void main(String args[]) { 
     new InstanceInitialisation1(); 
    } 
} 

Nhưng sau đây không biên dịch, đưa ra một 'về phía trước bất hợp pháp tham chiếu 'message:

class InstanceInitialisation2 { 

     private String testString1; 

    { 
     testString1 = testString2; 
    } 

    private String testString2; 

    public static void main(String args[]) { 
     new InstanceInitialisation2(); 
    } 
} 

Tại sao StaticInitialisation và InstanceInitialisation2 không biên dịch, trong khi InstanceInitialisation1 doe S?

+1

Xem Đoạn thứ 3 sẽ làm việc nếu thay đổi cho 'testString1 = this.testString2;' – Eran

+1

của nó lần đầu tiên tôi thấy một khối mã trong một lớp Java đó không phải là một phần của một ctor, hoặc ctor tĩnh hoặc phương thức. rất thích biết nó là gì, làm thế nào nó đi qua biên dịch và khi nào nó được thực thi –

+12

@sharonbn: Chúng là các khởi tạo thể hiện hoặc các khởi tạo tĩnh, được mô tả trong phần 8.6 và 8.7 của JLS tương ứng. –

Trả lời

57

này được bao phủ bởi phần 8.3.3 của JLS:

Sử dụng các biến lớp học có tờ khai xuất hiện textually sau khi sử dụng đôi khi bị hạn chế, mặc dù các biến lớp trong phạm vi (§6.3). Cụ thể, đó là một lỗi thời gian biên dịch nếu tất cả những điều sau đây là đúng:

  • Việc kê khai của một biến lớp học trong một lớp học hoặc giao diện C xuất hiện textually sau một sử dụng các biến lớp học;

  • Việc sử dụng là tên đơn giản trong bộ khởi tạo biến lớp của C hoặc bộ khởi tạo tĩnh của C;

  • Cách sử dụng không nằm ở phía bên tay trái của bài tập;

  • C là lớp hoặc giao diện trong cùng bao quanh việc sử dụng.

Sử dụng các biến mẫu có khai báo văn bản sau khi sử dụng đôi khi bị hạn chế, mặc dù các biến mẫu này nằm trong phạm vi. Cụ thể, đó là một lỗi thời gian biên dịch nếu tất cả những điều sau đây là đúng:

  • Việc kê khai của một biến Ví dụ trong một lớp học hoặc giao diện C xuất hiện textually sau một sử dụng các instance variable;

  • Việc sử dụng là tên đơn giản trong bộ khởi tạo biến thể hiện của C hoặc trình khởi tạo đối tượng của C;

  • Cách sử dụng không nằm ở phía bên tay trái của bài tập;

  • C là lớp hoặc giao diện trong cùng bao quanh việc sử dụng.

Trong trường hợp thứ hai của bạn, việc sử dụng không phải là một tên rất đơn giản - bạn đã có this một cách rõ ràng. Điều đó có nghĩa là nó không tuân thủ viên đạn thứ hai trong danh sách thứ hai được trích dẫn ở trên, vì vậy không có lỗi.

Nếu bạn thay đổi nó để:

System.out.println("Test string is: " + testString); 

...sau đó nó sẽ không biên dịch.

Hoặc theo hướng ngược lại, bạn có thể thay đổi mã trong khối initializer tĩnh để:

System.out.println("Test string is: " + StaticInitialisation.testString); 

Odd, nhưng đó là cách nó đi.

+1

Tôi đến đây vì tweet của bạn và bạn nhận được +1 của mình, nhưng đây là [không mới] (http://stackoverflow.com/q/15820302/256431) vì @ bayou.io liên kết đến. –

+0

@MarkHurd: Yup, nó chỉ mới với tôi :) –

1

Ở đây điều chúng tôi phải hiểu là trong đoạn mã thứ 2 Bạn đang sử dụng khối và từ khóa này.

  1. Khối thực hiện nếu đối tượng được tạo.
  2. Điều đó có nghĩa là đối tượng được tạo trong vùng heap.
  3. Bạn đang sử dụng bên ngoài từ khóa này để nhận giá trị của biến mẫu.
  4. Tại đây đối tượng được tạo với giá trị mặc định sẽ trả về dưới dạng giá trị.
  5. Khi sử dụng từ khóa này, bạn cũng không thể biên dịch đoạn 2.
2

Cho phép xem xét hai ví dụ này, tôi đoán điều này sẽ làm cho bạn rõ ràng.

public class InstanceAndSataticInit { 

    { 
     System.out.println("Test string is (instance init): " + this.testString); 
    } 

    static{ 
     System.out.println("Test string is (static init): " + InstanceAndSataticInit.testStringStatic); 
    } 

    public static String testStringStatic="test"; 
    public String testString="test"; 

    public static void main(String args[]) { 
     new InstanceAndSataticInit(); 
    } 

} 

Output:

Test string is (static init): null 
Test string is (instance init): null 

public class InstanceAndSataticInitVariableFirst { 

    public static String testStringStatic="test"; 
    public String testString="test"; 

    { 
     System.out.println("Test string is (instance init): " + this.testString); 
    } 

    static{ 
     System.out.println("Test string is (static init): " + InstanceAndSataticInitVariableFirst.testStringStatic); 
    } 



    public static void main(String args[]) { 
     new InstanceAndSataticInitVariableFirst(); 
    } 


} 

đầu ra:

Test string is (static init): test 
Test string is (instance init): test 

Vì vậy, bạn có thể nói trình tự là như thế này.

  1. Biến tĩnh sẽ được tạo nhưng không được khởi tạo.

  2. Khởi tạo tĩnh sẽ được thực hiện theo trình tự đã cho.

  3. Biến không tĩnh sẽ được tạo nhưng không được khởi tạo.
  4. Khởi tạo không tĩnh sẽ được thực hiện theo trình tự đã cho.

Theo trình tự, tôi có nghĩa là sự xuất hiện trong mã.

Tôi đoán đây bước trả lời của bạn hai không làm việc dụ StaticInitialisationInstanceInitialisation2

Nhưng trong trường hợp bạn thứ hai ví dụ làm việcInstanceInitialisation1 bằng cách sử dụng this từ khóa bạn đang thực sự giúp trình biên dịch bỏ qua phân cấp văn bản.Điều tương tự cũng xảy ra trong trường hợp static khi tôi gọi InstanceAndSataticInit.testStringStatic trong ví dụ đầu tiên của tôi InstanceAndSataticInit

2

lý do đơn giản - đó là quá đắt hoặc không thể phân tích và cấm tất cả các tài liệu tham khảo về phía trước. ví dụ.

{ 
    print(getX(); ); // this.x 
    print(that().x); // this.x 
} 

int x; 
int getX(){ return x; } 

This that(){ return this; } 

Đặc điểm này giải quyết việc cấm một số trường hợp đơn giản biểu thị sai lầm lập trình chung.

cũng Recursive initializer works when I add "this"?

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