“Cái này” có bao giờ là rỗng trong Java không?


109

Đã thấy dòng này trong một phương thức lớp và phản ứng đầu tiên của tôi là chế nhạo nhà phát triển đã viết ra nó .. Nhưng sau đó, tôi nghĩ mình nên chắc chắn rằng mình đã đúng trước.

public void dataViewActivated(DataViewEvent e) {
    if (this != null)
        // Do some work
}

Dòng đó có bao giờ đánh giá thành false không?


104
Luôn chế giễu trước và đặt câu hỏi sau. Xin lỗi dễ hơn là chớp lấy cơ hội ngàn vàng để xé xác ai đó trong đống diêm sinh.
Joel Etherton

5
+1 cho thuật ngữ "flurry of brimstone".
Marty Pitt

13
Bạn biết điều gì vui không? Điều này có thể xảy ra trong C # do lỗi trình biên dịch!
Blindy

1
@Blindy sẽ +1 cho mẫu mã.
Nathan Feger

6
tốt trong C # nó có thể là null. Trong một số trường hợp cạnh. Tôi cũng có cùng một xung động: nhạo báng kẻ bú sữa nhưng sau đó tôi bình tĩnh lại. Hãy xem ở đây: stackoverflow.com/questions/2464097/…
Andrei Rînea

Câu trả lời:


88

Không, không thể. Nếu bạn đang sử dụng this, thì bạn đang ở trong trường hợp thisnày không phải là null.

JLS nói:

Khi được sử dụng như một biểu thức chính, từ khóa này biểu thị một giá trị là một tham chiếu đến đối tượng mà phương thức thể hiện được gọi (§15.12) hoặc đối tượng đang được xây dựng.

Nếu bạn gọi một phương thức từ một đối tượng, thì đối tượng đó tồn tại hoặc bạn sẽ có một phương thức NullPointerExceptiontrước đó (hoặc đó là một phương thức tĩnh nhưng sau đó, bạn không thể sử dụng thisnó).


Tài nguyên :


4
Tôi không biết sâu về Java, nhưng trong C ++, thisphương thức thể hiện có thể là NULL. Vì vậy, tôi không hoàn toàn tin rằng đây là một lý do đủ trong Java.
kennytm 24/09/10

4
ngoại lệ con trỏ null trong một cái gì đó giống như foo.bar()sẽ được ném khi foođược phát hiện là null. nó xảy ra trước khi nhập phương thức, nhưng câu chuyện thực sự là không có phương thức nào để cố gắng gọi.
Claudiu

5
@KennyTM: nó là đủ trong Java. Nếu bạn đang sử dụng thistừ khóa và nó được biên dịch, nó không rỗng khi bạn quan sát nó. Nhưng như những người khác nói rằng điều đó không ngăn NPE khi cố gắng gọi phương thức, ví dụ: Nhưng điều đó hoàn toàn nằm ngoài tầm kiểm soát của bạn với tư cách là một phương pháp và việc kiểm tra rỗng trong phương thức sẽ không thay đổi bất cứ điều gì.
Mark Peters

5
@Kenny: Không phải không có hành vi không xác định , mặc dù nếu bạn biết chi tiết triển khai của mình, bạn có thể sử dụng nó.

4
Tôi sẽ không đăng ký câu trả lời dứt khoát này, ngay cả khi nó hoàn toàn hợp lý. Tôi có báo cáo sự cố cho một ứng dụng Android trong đó điều này == null khi một phương thức phiên bản được gọi ngay sau khi biến đang được null-ified từ một chuỗi khác. Cuộc gọi thực tế đi qua ngay cả khi biến là null, và nó bị treo khi nó cố gắng để đọc một thành viên dụ :)
Adrian Cretu

63

Nó giống như tự hỏi bản thân "Tôi còn sống?" thiskhông bao giờ có thể là rỗng


44
tôi còn sống ?! trời
Claudiu

Bạn đang làm cho nó giống như this != nulllà điều hiển nhiên. Nó không - trong C ++, chẳng hạn, thiscũng có thể là NULL, đối với một phương thức không ảo.
Niki 24/09/10

1
@nikie Theo một nghĩa nào đó, điều đó là hiển nhiên. Ngay cả trong C ++, bất kỳ chương trình nào mà điều này xảy ra đều có hành vi không xác định. Nó cũng có thể xảy ra đối với các chức năng ảo trên GCC: ideone.com/W7RmU .
Johannes Schaub - litb

8
@John: Bạn đang có. Một phần của sự tra tấn là bạn không thể xác nhận nó.

@ JohannesSchaub-litb Không xác định được hoạt động của chương trình c ++ với null ref cho điều này là không đúng. Nó được định nghĩa miễn là bạn không bỏ qua điều này
Rune FS

9

Không bao giờ , bản thân từ khóa 'this' đại diện cho cá thể (đối tượng) còn sống hiện tại của lớp đó trong phạm vi của lớp đó, mà bạn có thể truy cập vào tất cả các trường và thành viên của nó (bao gồm cả các hàm tạo) và các trường hiển thị của lớp cha của nó.

Và thú vị hơn, hãy thử đặt nó:

this = null;

Hãy suy nghĩ về nó? Làm sao có thể, sẽ không giống như chặt cành đang ngồi. Vì từ khóa 'this' có sẵn trong phạm vi của lớp nên ngay sau khi bạn nói this = null; ở bất kỳ đâu trong lớp thì về cơ bản bạn đang yêu cầu JVM giải phóng bộ nhớ được gán cho đối tượng đó ở giữa một số thao tác mà JVM không thể cho phép xảy ra vì nó cần trở lại an toàn sau khi kết thúc thao tác đó.

Hơn nữa, cố gắng this = null;sẽ dẫn đến lỗi trình biên dịch. Lý do khá đơn giản, một từ khóa trong Java (hoặc bất kỳ ngôn ngữ nào) không bao giờ có thể được gán một giá trị tức là một từ khóa không bao giờ có thể là giá trị bên trái của một thao tác gán.

Các ví dụ khác, bạn không thể nói:

true = new Boolean(true);
true = false;

Bạn giải thích tốt.
Pankaj Sharma

@PankajSharma Cảm ơn :)
sactiw

Tôi tìm thấy cái này vì tôi muốn xem liệu tôi có thể sử dụng không this = null. Phiên bản của tôi là trong android, nơi tôi muốn xóa chế độ xem và đặt đối tượng xử lý chế độ xem thành null. Sau đó, tôi muốn sử dụng một phương thức remove()sẽ loại bỏ chế độ xem thực tế và sau đó đối tượng xử lý sẽ trở nên vô dụng, vì vậy tôi muốn vô hiệu hóa nó.
Yokich

Không chắc tôi đồng ý với yêu cầu của bạn. (ít nhất là phần giữa; phần lvalue cũng được ... mặc dù tôi khá chắc chắn rằng trên thực tế có những ngôn ngữ bị hỏng cho phép bạn gán ví dụ: true = false (và ngay cả những ngôn ngữ tôi không gọi là bị hỏng cũng có thể cho phép nó với Phản ánh hoặc thủ đoạn tương tự)). Dù sao đi nữa, Nếu tôi có một số đối tượng foo và tôi phải làm (bỏ qua việc đó là bất hợp pháp) foo.this = null, foo sẽ vẫn trỏ đến bộ nhớ và do đó JVM sẽ không thu thập nó.
Foon

@ Vâng, câu hỏi nói chính xác về ngôn ngữ Java, hơn nữa, tôi chưa gặp bất kỳ ngôn ngữ nào cho phép đặt this = null. Đó là, nếu có tồn tại những ngôn ngữ như vậy thì tôi rất nghi ngờ rằng 'điều này' trong những ngôn ngữ như vậy sẽ có cùng ngữ cảnh và hệ tư tưởng.
sactiw

7

Nếu bạn biên dịch bằng -target 1.3hoặc sớm hơn, thì một bên ngoài this có thể là null. Hoặc ít nhất nó đã từng ...


2
Tôi đoán thông qua phản chiếu, chúng ta có thể đặt bên ngoài cái này thành null. có thể là một tháng tư lừa đùa trên một người nào đó khi anh vô trỏ ngoại lệ trong tham khảoOuter.this.member
irreputable

3

Không. Để gọi một phương thức của một thể hiện của một lớp, thể hiện đó phải tồn tại. Cá thể được truyền ngầm dưới dạng một tham số cho phương thức, được tham chiếu bởi this. Nếu thisnullthì sẽ không có trường hợp nào để gọi một phương thức của.


3

Ngôn ngữ thực thi nó là chưa đủ. VM cần phải thực thi nó. Trừ khi VM thực thi nó, bạn có thể viết một trình biên dịch không thực thi kiểm tra null trước khi gọi phương thức được viết bằng Java. Các mã opcodes cho một lệnh gọi phương thức phiên bản bao gồm tải tham chiếu này vào ngăn xếp, hãy xem: http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html#14787 . Thay thế điều này cho một tham chiếu null sẽ thực sự dẫn đến kết quả là thử nghiệm sai


3

Trong các phương thức lớp tĩnh, thiskhông được định nghĩa vì thisđược liên kết với các cá thể chứ không phải các lớp. Tôi tin rằng nó sẽ gây ra lỗi trình biên dịch khi cố gắng sử dụng thistừ khóa trong ngữ cảnh tĩnh.


2

Một bình thường thiskhông bao giờ có thể có nulltrong mã Java thực 1 và ví dụ của bạn sử dụng một bình thường this. Xem các câu trả lời khác để biết thêm chi tiết.

Một người đủ điều kiện không bao giờ this nênnull, nhưng có thể phá vỡ điều này. Hãy xem xét những điều sau:

public class Outer {
   public Outer() {}

   public class Inner {
       public Inner() {}

       public String toString() {
           return "outer is " + Outer.this;  // Qualified this!!
       }
   }
}

Khi chúng ta muốn tạo một instance của Inner, chúng ta cần thực hiện điều này:

public static void main(String[] args) {
    Outer outer = new Outer();
    Inner inner = outer.new Inner();
    System.out.println(inner);

    outer = null;
    inner = outer.new Inner();  // FAIL ... throws an NPE
}

Đầu ra là:

outer is Outer@2a139a55
Exception in thread "main" java.lang.NullPointerException
        at Outer.main(Outer.java:19)

cho thấy rằng nỗ lực của chúng tôi để tạo Innermột nulltham chiếu đến nó Outerđã thất bại.

Trên thực tế, nếu bạn dính vào bao thư "Pure Java", bạn không thể phá vỡ điều này.

Tuy nhiên, mỗi Innertrường hợp có một finaltrường tổng hợp ẩn (được gọi "this$0") chứa tham chiếu đến Outer. Nếu bạn thực sự khôn lanh, có thể sử dụng các phương tiện "không thuần túy" để gán nullcho lĩnh vực này.

  • Bạn có thể sử dụng Unsafeđể làm điều đó.
  • Bạn có thể sử dụng mã gốc (ví dụ: JNI) để làm điều đó.
  • Bạn có thể làm điều đó bằng cách sử dụng sự phản chiếu.

Dù bạn làm theo cách nào thì kết quả cuối cùng là Outer.thisbiểu thức sẽ đánh giá là null2 .

Trong ngắn hạn, nó là có thể cho một đủ điều kiện thisđể được null. Nhưng điều đó là không thể nếu chương trình của bạn tuân theo các quy tắc "Pure Java".


1 - Tôi giảm bớt các thủ thuật như "viết" các mã bytecodes bằng tay và chuyển chúng thành Java thực, điều chỉnh các mã bytecodes bằng BCEL hoặc tương tự, hoặc nhảy vào mã gốc và xử lý các thanh ghi đã lưu. IMO, đó KHÔNG phải là Java. Theo giả thuyết, những điều như vậy cũng có thể xảy ra do lỗi JVM ... nhưng tôi không nhớ mọi lần nhìn thấy báo cáo lỗi.

2 - Trên thực tế, JLS không cho biết hành vi sẽ như thế nào, và nó có thể phụ thuộc vào việc triển khai ... trong số những thứ khác.


1

Khi bạn gọi một phương thức trên nulltham chiếu, phương thức NullPointerExceptionsẽ được ném từ Java VM. Đây là thông số kỹ thuật, vì vậy nếu máy ảo Java của bạn tuân thủ nghiêm ngặt đặc điểm kỹ thuật thì thissẽ không bao giờ null.


1

Nếu phương thức là tĩnh, thì không có bất kỳ phương thức nào this. Nếu phương thức là ảo, thì thiskhông được rỗng, vì để gọi phương thức, thời gian chạy sẽ cần tham chiếu đến vtable bằng cách sử dụng thiscon trỏ. Nếu phương thức không phảiảo thì có, có thể thislà không.

C # và C ++ cho phép các phương thức không phải ảo, nhưng trong Java tất cả các phương thức không tĩnh đều là ảo, vì vậy thissẽ không bao giờ là rỗng.


0

tl; dr, "this" chỉ có thể được gọi từ một phương thức không tĩnh và chúng ta đều biết rằng một phương thức không tĩnh được gọi từ một số loại đối tượng không thể rỗng.

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.