Các trường tĩnh trên một tham chiếu rỗng trong Java


119

staticcác thành viên ( statictrường hoặc staticphương thức) trong Java được liên kết với lớp tương ứng của chúng hơn là các đối tượng của lớp này. Đoạn mã sau cố gắng truy cập một trường tĩnh trên một nulltham chiếu.

public class Main
{
    private static final int value = 10;

    public Main getNull()
    {
        return null;
    }

    public static void main(String[] args)
    {
        Main main=new Main();
        System.out.println("value = "+main.getNull().value);
    }
}

Mặc dù main.getNull()trả về null, nó hoạt động và hiển thị value = 10. Mã này hoạt động như thế nào?



4
Để giải trí, hãy thử Main main = null; main.getNull().value.
Marko Topolnik vào

1
Điều này nhắc nhở tôi về new Thread[]{}[-1].sleep(10);nơi sleep () là một phương thức tĩnh. Điều này đã từng thành công trên một số phiên bản Java cũ hơn.
hertzsprung

Câu trả lời:


93

Hành vi đó được chỉ định trong Đặc tả ngôn ngữ Java :

một tham chiếu null có thể được sử dụng để truy cập một biến lớp (tĩnh) mà không gây ra ngoại lệ.

Chi tiết hơn, một đánh giá lĩnh vực tĩnh , chẳng hạn như Primary.staticFieldcông trình như sau (tôi nhấn mạnh) - trong trường hợp của bạn, Primary = main.getNull():

  • Biểu thức chính được đánh giá và kết quả bị loại bỏ . [...]
  • Nếu trường là trường cuối cùng không trống, thì kết quả là giá trị của biến lớp được chỉ định trong lớp hoặc giao diện là kiểu của biểu thức Chính. [...]

5
Nếu ai đó có thông tin về lý do tại sao lựa chọn này được thực hiện, điều đó sẽ rất thú vị.

6
@JonofAllTrades Tôi nghĩ điều này là hiển nhiên: không nên ném bất kỳ ngoại lệ nào khi gọi tham chiếu null vì nó không quan trọng vì phương thức là tĩnh.
Malcolm

13
@JonofAllTrades: câu hỏi thực sự là tại sao lựa chọn cho phép các thành viên tĩnh được gọi là thể hiện được đưa ra ... Đối với tôi, nó dường như chỉ dẫn đến sự nhầm lẫn và mã ít dễ đọc hơn.
Falanwe

2
@Falanwe: Đồng ý, và đó là một cấu trúc mà tôi không có nhu cầu, mặc dù tôi chủ yếu làm việc trong .NET nơi nó không được phép. Tôi đoán bạn có thể muốn gọi phương thức tĩnh thích hợp của một lớp con khi bạn được cung cấp một tham chiếu đến một lớp cha.

8
@Falanwe Điều này được cho phép, nhưng đưa ra cảnh báo trong Eclipse: "Trường tĩnh Main.value nên được truy cập theo cách tĩnh". Ít nhất những người trong chúng ta cầu kỳ về các cảnh báo (như tôi) sẽ tránh mã như vậy.
Artyom

19

Bởi vì, như bạn đã nói, các trường tĩnh không được liên kết với một cá thể.

Khả năng truy cập các trường tĩnh từ một tham chiếu cá thể (như bạn đang làm) chỉ là một đường cú pháp và không có ý nghĩa bổ sung.
Mã của bạn biên dịch thành

main.getNull(); 
Main.value

7
Tôi sẽ gọi nó là đường cú pháp, giống như cú pháp cưa bụi;)
Stephen Swensen

3

Bất cứ khi nào bạn truy cập một biến hoặc phương thức tĩnh với các đối tượng tại thời điểm biên dịch, nó được chuyển đổi thành tên Lớp. ví dụ:

Main main = null;
System.out.println(main.value);

Nó sẽ in giá trị của giá trị biến tĩnh vì tại thời điểm biên dịch Nó sẽ được chuyển đổi thành

System.out.println(Main.value);

Bằng chứng:

tải xuống trình dịch ngược và Giải mã tệp .class của bạn thành tệp .java và bạn có thể thấy tất cả các phương thức tĩnh hoặc tên đối tượng được tham chiếu biến được tự động thay thế bằng tên lớp.


3
  1. Việc truy cập vào một staticthành viên với tên lớp là hợp pháp, nhưng không được viết rằng người ta không thể truy cập staticthành viên bằng cách sử dụng biến tham chiếu đối tượng. Vì vậy, nó hoạt động ở đây.

  2. Một nullbiến tham chiếu đối tượng được phép truy cập một staticbiến lớp mà không đưa ra ngoại lệ ở thời gian biên dịch hoặc chạy.


2

Biến static và phương thức luôn thuộc về lớp. Vì vậy, đã bao giờ chúng ta tạo bất kỳ đối tượng nào mà chỉ có biến không tĩnh và các phương thức đi vào heap cùng với đối tượng nhưng tĩnh nằm trong vùng phương thức với lớp. Đó là lý do tại sao khi chúng ta cố gắng truy cập vào một biến hoặc phương thức tĩnh mà nó được chuyển đổi thành biến dot tên lớp hoặc tên phương thức.

Vui lòng tham khảo liên kết dưới đây để biết thêm chi tiết.

http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.