Sự khác biệt về bộ nhớ giữa một biến được gán cho null và một biến không được gán


8

Sự khác biệt về bộ nhớ giữa một biến được gán cho null và một biến không được gán là gì?

Tôi biết rằng có một sự khác biệt trong cách sử dụng, nhưng sự khác biệt trong bộ nhớ là gì?


1
Chia sẻ nghiên cứu của bạn giúp mọi người . Hãy cho chúng tôi những gì bạn đã cố gắng và tại sao nó không đáp ứng nhu cầu của bạn. Điều này chứng tỏ rằng bạn đã dành thời gian để cố gắng tự giúp mình, nó giúp chúng tôi tránh nhắc lại các câu trả lời rõ ràng và hầu hết nó giúp bạn có được câu trả lời cụ thể và phù hợp hơn. Xem thêm Cách hỏi
gnat

Câu trả lời:


11

Không có sự khác biệt giữa hai "trong bộ nhớ."

Từ Đặc tả ngôn ngữ Java, 4.12,5. Giá trị ban đầu của các biến :

Mỗi biến trong một chương trình phải có một giá trị trước khi giá trị của nó được sử dụng:

  • Mỗi biến lớp, biến thể hiện hoặc thành phần mảng được khởi tạo với giá trị mặc định khi nó được tạo (§15.9, §15.10.2):

...

    • Đối với tất cả các loại tham chiếu (§4.3), giá trị mặc định là null.

...

    • Một biến cục bộ (§14.4, §14,14) phải được cung cấp một giá trị rõ ràng trước khi nó được sử dụng, bằng cách khởi tạo (§14.4) hoặc gán (§15,26), theo cách có thể được xác minh bằng cách sử dụng quy tắc cho phép gán xác định (§ 16 (Bài tập xác định)).

Các biến tham chiếu ở cấp độ hoặc đối tượng sẽ được gán một giá trị null.

Các biến tham chiếu ở mức phương thức (ngăn xếp) sẽ có giá trị không xác định (sử dụng thuật ngữ C ++). Trong thực tế, điều này thường là null, nhưng tiêu chuẩn không chỉ định những gì trong biến tham chiếu, chỉ có điều nó phải được chỉ định trước khi sử dụng. Sử dụng một biến tham chiếu trên ngăn xếp theo bất kỳ cách nào khác ngoài việc gán như lần sử dụng đầu tiên sẽ dẫn đến lỗi biên dịch.


Khi bạn khai báo một biến mà không khởi tạo nó thành null, sau đó khởi tạo nó trong một if-thenkhối, trình biên dịch sẽ cho bạn biết rằng biến đó có thể chưa được khởi tạo trước trong mã nếu thenkhối không được thực thi. Nếu bạn khởi tạo nó để nullbiên dịch mã. Tại sao điều đó được đưa ra rằng "một tham chiếu không được gán rõ ràng một giá trị sẽ có giá trị null" ?
Tulains Córdova

@Snowman Không phải là một chi tiết thực hiện? Chỉ các biến lớp, biến thể hiện và các thành phần mảng được yêu cầu khởi tạo thành các giá trị mặc định của chúng. Không có yêu cầu về các biến cục bộ và bạn không thể sử dụng chúng trước khi chúng được khởi tạo. Nếu bạn nhìn vào một biến cục bộ chưa được khởi tạo trong bộ nhớ, bạn sẽ thấy bất cứ điều gì thực hiện xảy ra với nó, điều này có thể không liên quan đến việc khởi tạo nó nullvì nó sẽ là công việc không cần thiết để làm như vậy.
Doval

@Snowman - Vì việc sử dụng một cục bộ trước khi nó được gán một giá trị là bất hợp pháp, cho dù một biến cục bộ chưa được khởi tạo có được đưa ra một giá trị ban đầu hay không là một chi tiết triển khai.
David Hammen

1
Xin vui lòng xem chỉnh sửa gần đây nhất của tôi. Tôi đổ lỗi cho cà phê không đủ vào một buổi sáng thứ Hai.

4

Sự khác biệt giữa một biến được gán cho null và các biến khác không được gán trong bộ nhớ là gì?

Không có thứ gọi là biến không được gán trong Java. Các thành viên dữ liệu lớp không có phân công rõ ràng được gán giá trị mặc định cho loại, null cho một đối tượng hoặc một cái gì đó gần giống với 0 cho các kiểu nguyên thủy.

Biến cục bộ sống trên stack. (Các địa phương không nguyên thủy như MyType foocũng sống trên ngăn xếp, làm tài liệu tham khảo.) Việc phân bổ ngăn xếp rất đơn giản. Nếu một khối chứa khai báo cho các biến cục bộ, không gian cần thiết cho các biến cục bộ đó được dành riêng trên ngăn xếp. Việc các giá trị được gán cho các biến cục bộ đó khi điều chỉnh ngăn xếp để chứa các biến cục bộ đó là không liên quan.

Lý do nó không quan trọng là liệu các biến cục bộ có hoặc không được gán một giá trị tại thời điểm thực hiện nhập vào khối là gấp đôi. Một lý do là kích thước cần thiết không thay đổi. Người nguyên thủy có kích thước cố định và người không nguyên thủy thực sự là tài liệu tham khảo. (Đối tượng được tham chiếu sống trên heap chứ không phải stack.) Lý do thứ hai là việc sử dụng biến cục bộ chưa được gán giá trị là lỗi biên dịch. Điều này tùy thuộc vào thời gian chạy Java liệu có đưa ra một số giá trị (không nhất thiết là mặc định) cho một biến cục bộ được khai báo nhưng không được gán.


Đâu đó trong câu trả lời của bạn là lời giải thích cho điều này: Khi bạn khai báo một biến mà không khởi tạo nó thành null, sau đó khởi tạo nó trong một if-thenkhối, trình biên dịch sẽ cho bạn biết rằng biến đó có thể chưa được khởi tạo trước trong mã nếu thenkhối không được thực thi. Nếu bạn khởi tạo nó để nullbiên dịch mã. Tại sao điều đó được đưa ra rằng "một tham chiếu không được gán rõ ràng một giá trị sẽ có giá trị null" ? Nhưng nó vẫn chưa đủ rõ ràng đối với tôi. Bạn có thể giải thích nó bằng những từ khác?
Tulains Córdova

2
Các biến cục bộ không cần phải được đưa ra một giá trị ban đầu. Họ cần được chỉ định một giá trị trước khi sử dụng ban đầu. Liệu bộ nhớ liên quan đến biến đó có được đưa ra một giá trị ban đầu rõ ràng hay không, ngay cả trong trường hợp khai báo không có gán, là một chi tiết thực hiện. Bộ nhớ tồn tại (đó là cách các ngăn xếp hoạt động), nhưng không gian bộ nhớ đó có thể bị lấp đầy với bất cứ điều gì xảy ra trong bộ nhớ đó trước khi điều chỉnh ngăn xếp.
David Hammen

@ user61852 - Một tham chiếu không được gán một giá trị rõ ràng sẽ có giá trị null là đúng với các thành viên lớp, nhưng không nhất thiết cho các biến cục bộ. Nếu bạn đang biên dịch mã của mình với tính năng gỡ lỗi được kích hoạt, trình biên dịch gần như chắc chắn sẽ khởi tạo các biến cục bộ không nguyên thủy chưa được khởi tạo của bạn thành null. Điều này giúp đơn giản hóa rất nhiều sự phát triển của trình gỡ lỗi Java. Nhưng nếu bạn biên dịch với gỡ lỗi bị vô hiệu hóa thì sao? Bây giờ việc khởi tạo là công việc phụ không cần thiết. Những gì trong bộ nhớ đó là không liên quan vì được biết rằng bộ nhớ sẽ chứa một giá trị hợp lệ trong lần sử dụng đầu tiên.
David Hammen

Từ phối cảnh mã byte, các biến cục bộ được phân bổ trên ngăn xếp. Tuy nhiên, JITter có thể quyết định rằng một mục nhập ngăn xếp cụ thể thực sự không nên được lưu trữ trên ngăn xếp, nhưng việc lưu trữ và tải từ mục nhập đó nên được hướng vào một thanh ghi CPU cụ thể. Hơn nữa, nếu JITter xác định rằng một khi thực thi đạt đến một điểm nhất định, không có cách nào một mục nhập ngăn xếp sẽ được đọc mà không được viết lại, nó có thể gán lại đăng ký liên kết của mục đích đó cho mục đích khác.
supercat

1

Đầu tiên, thực sự không cần phải lo lắng về không gian được sử dụng bởi các biến cục bộ. Trong một dòng tôi có thể phân bổ một mảng gồm 100.000 số nguyên sẽ chiếm nhiều không gian hơn tất cả các biến cục bộ mà bạn sẽ sử dụng.

Thứ hai, mã của bạn được biên dịch bởi một trình biên dịch có khả năng là thông minh. Nếu biến của bạn không được khởi tạo, nó không được sử dụng (vì trình biên dịch không cho phép sử dụng các biến chưa được khởi tạo). Nhưng nếu bạn khởi tạo nó thành con số không, nó vẫn không được sử dụng! Trình biên dịch sẽ dễ dàng nhận ra rằng nó không được sử dụng và thực tế không sử dụng không gian cho biến. Ngay cả khi nó được sử dụng, trình biên dịch sẽ dễ dàng nhận ra rằng giá trị là 0 và sử dụng nil thay vì biến.

Nhưng thứ ba, đây là tất cả các tối ưu hóa vi mô sẽ không giúp bạn tối ưu hóa chương trình theo bất kỳ cách nào. Bạn đang cố gắng lưu bốn hoặc tám byte. Tập trung vào việc tiết kiệm megabyte nếu bạn muốn tiết kiệm mọi thứ.

Và cuối cùng, trong khi một số người tuyên bố các biến phải luôn được khởi tạo, điều đó không đúng trong Java. Bạn chỉ nên đặt một biến thành một giá trị có ý nghĩa. Giả sử bạn muốn đặt một biến thành tên của một người và bạn quên làm điều này trong một đường dẫn mã. Nếu bạn mù quáng khởi tạo biến thành nil, trình biên dịch không thể cho bạn biết. Nếu không khởi tạo, trình biên dịch có thể và sẽ cho bạn biết về lỗi của bạn.

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.