Sự khác biệt giữa biến đối tượng chưa được khởi tạo và biến đối tượng được khởi tạo thành null trong Java


12

Tôi có hai biến đối tượng sau

Date a;
Date b=null;

Chắc chắn cả 'a' và 'b' đều không đề cập đến bất kỳ đối tượng nào.

Bây giờ nếu tôi gọi câu lệnh sau

System.out.println(a.toString());

Sẽ có một lỗi thời gian biên dịch, trong khi nếu tôi gọi câu lệnh sau

System.out.println(b.toString());

Sẽ không có lỗi thời gian biên dịch nhưng sẽ có lỗi thời gian chạy. Lý do cho điều này là gì và giá trị nào sẽ thực sự được lưu trữ trong 'b' để thể hiện giá trị null?


2
đã hỏi và trả lời nhiều lần tại SO: Tại sao các biến cục bộ không được khởi tạo trong Java? , Các biến và thành viên chưa được khởi tạo trong Java và trong nhiều câu hỏi được liên kết với chúng
gnat

@gnat, có câu hỏi nào khác liên quan đến sự khác biệt giữa "uninitialized" và "null" không? Chỉ vì câu trả lời tương tự không có nghĩa đây là một câu hỏi trùng lặp.
DougM

@DougM chắc chắn, bạn đã đọc câu hỏi đầu tiên tôi giới thiệu? "Có bất kỳ lý do nào khiến các nhà thiết kế của Java cảm thấy rằng các biến cục bộ không nên được đưa ra một giá trị mặc định không? Nghiêm túc, nếu các biến thể hiện có thể được cung cấp một giá trị mặc định, thì tại sao chúng ta không thể làm tương tự cho các biến cục bộ?" (FWIW về mặt kỹ thuật nó không thể là một bản sao, đơn giản vì nó ở một trang web khác)
gnat

1
Điều đó không giải quyết sự khác biệt giữa "uninitialized" và "khởi tạo là null", chỉ "tại sao các biến không tự động được kích hoạt thành null?" Cùng một chủ đề, câu hỏi hơi khác nhau.
DougM

Câu trả lời:


3

Đó là bởi vì trạng thái của các biến cục bộ được kiểm soát trong phạm vi của nó

 // method/loop/if/try-catch etc...
 {
   Date d; // if it's not intialised in this scope then its not intialised  anywhere
 }

Đó không phải là trường hợp cho các lĩnh vực

class Foo{
 Date d; // it could be intialised anywhere, so its out of control and java will set to null for you
}

Bây giờ, tại sao nó tốt để đặt một biến thành null và sử dụng nó ngay lập tức? có thể đó là một sai lầm lịch sử đôi khi dẫn đến những sai lầm khủng khiếp

 {
  Date d = null;
  try{
  }catch{ // hide it here 
  }
  return d;
 } 

Bây giờ sự khác biệt về ngữ nghĩa là gì?

Date d;

chỉ cần khai báo biến có thể chứa một tham chiếu trỏ đến một đối tượng kiểu Date, tuy nhiên

Date d= null; 

thực hiện chính xác như vậy nhưng lần này tham chiếu trỏ đến null, null giống như bất kỳ tham chiếu nào, nó chiếm một khoảng trống của con trỏ riêng, đó là 4 byte trên máy 32 bit và 8 byte trên máy 64 bit


điều này dường như chỉ lặp lại điểm được thực hiện và giải thích trong câu trả lời trước được đăng một giờ trước
gnat

@gnat Cảm ơn bình luận của bạn, nhưng tôi không nghĩ đó là, chúc mừng
Sleiman Jneidi

Bạn có nghĩa là null cũng là một đối tượng được lưu trữ ở đâu đó trong bộ nhớ và tất cả các biến đối tượng được gán với null đều trỏ đến đối tượng null đó.
Harish_N

@ Harish.N không, tôi không nói điều đó, tôi đã nói nó là một tài liệu tham khảo và không phải là một đối tượng
Sleiman Jneidi

Trong ví dụ bạn đã đưa ra 'd' là một tham chiếu .. nó được tham chiếu đến một đối tượng có kiểu Ngày ... tương tự nếu null là tham chiếu .. đến đối tượng mà nó đề cập đến ..?
Harish_N

19

Không có sự khác biệt cho các trường lớp. Chúng nulltheo mặc định cho các đối tượng, 0 cho các giá trị số và falsecho booleans.

Đối với các biến được khai báo trong các phương thức - Java yêu cầu chúng phải được khởi tạo. Không khởi tạo chúng gây ra lỗi thời gian biên dịch khi chúng được truy cập.

Lý do là gì? Các trường lớp có thể được sửa đổi bằng bất kỳ phương thức nào. Theo bất kỳ thứ tự nào phương thức được gọi. Tất cả các trường không riêng tư có thể được sửa đổi bởi các lớp khác và / hoặc các lớp mở rộng lớp đó. Do đó, không có điểm nào trong việc thông báo về một biến chưa được khởi tạo, vì nó có thể được gán ở nhiều, nhiều nơi.

Các biến bên trong các phương thức, tuy nhiên, là cục bộ và chỉ có thể được sửa đổi bên trong chính phương thức đó. Do đó, cả hai đều có thể và hợp lý để chỉ ra những sai lầm có thể xảy ra. Và trình biên dịch cố gắng làm điều đó. Nếu nó biết trường không được khởi tạo, nó sẽ hiển thị lỗi, vì đó không bao giờ là điều bạn muốn. Nếu không chắc chắn - nó sẽ đưa ra cảnh báo, để bạn có thể chắc chắn.

public static class Test {
    Date a; // ok 
    Date b = null; // ok

    public void test() {
        Date c;
        Date d = null;

        System.out.println(a.toString());
        System.out.println(b.toString());
        System.out.println(c.toString()); // error
        System.out.println(d.toString()); // warning
    }
}
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.