2015-06-17 12 views
5

Câu hỏi của tôi có liên quan đến:Cuộc sống của một đối tượng mới mà không tham khảo

Điều gì thực sự xảy ra khi chúng ta có một cái gì đó như thế này trong mã của chúng tôi:

(new SomeClass()).longMethod(); 

Vẫn còn một số loại tham chiếu không tên (mạnh?) trỏ đến đối tượng mới được tạo trên Heap đặt trên Stack?

Nếu không có gì ở trên Stack, thì Garbage Collector biết cách giữ gìn đối tượng trong suốt thời gian của phương thức?

là nó có thể giống như

{ 
    // very local scope 
    SomeClass throwAwayRef = new SomeClass(); 
    throwAwayRef.longMethod(); 
} 
+0

bao giờ nghe của 'this'? – Ingo

+0

@Ingo - Hãy cẩn thận để xây dựng? –

+0

Trả lời trước. Nó là gì trong một phương pháp? Và nó đến từ đâu? – Ingo

Trả lời

1

Vâng, tham chiếu đến đối tượng mới tồn tại trên stack.

thẳng từ Oracle:

Để truy cập vào một lĩnh vực, bạn có thể sử dụng một tài liệu tham khảo đặt tên cho một đối tượng, như trong ví dụ trước, hoặc bạn có thể sử dụng bất kỳ biểu thức trả về một tham chiếu đối tượng. Nhớ lại rằng toán tử mới trả về một tham chiếu đến một đối tượng. Vì vậy, bạn có thể sử dụng giá trị trả về từ mới để truy cập các lĩnh vực một mới của đối tượng:

int height = new Rectangle().height;

Lệnh này tạo một đối tượng Rectangle mới và ngay lập tức nhận được chiều cao của nó. Về bản chất, câu lệnh tính chiều cao mặc định của Hình chữ nhật. Lưu ý rằng sau khi tuyên bố này đã được thực thi, chương trình không còn có tham chiếu đối với Hình chữ nhật được tạo, bởi vì chương trình không bao giờ lưu trữ tham chiếu ở bất kỳ đâu. Đối tượng không được tham chiếu, và tài nguyên của nó là miễn phí để được tái chế bởi Máy ảo Java.

nguồn: https://docs.oracle.com/javase/tutorial/java/javaOO/usingobject.html

+3

nhiều bằng chứng hoặc ví dụ xin vui lòng – jgr208

+0

Phương pháp chiều cao có thể lưu trữ 'này' một nơi nào đó, do đó, Oracle không phải là khá đúng ở đây. Không biết mã chiều cao, chúng ta không biết liệu tham chiếu có được lưu trữ ở đâu đó không. – Ingo

+0

@ Vâng Vâng tôi giả sử họ có nghĩa là 'java.awt.Rectangle' mà không có hành vi đó, nhưng bạn làm cho một điểm tốt cho trường hợp chung. –

3

Vâng,

new SomeClass().longMethod(); 

là một cách hiệu quả giống như, đặc biệt là từ một quan điểm thu gom rác thải:

{ 
    SomeClass throwAwayRef = new SomeClass(); 
    throwAwayRef.longMethod(); 
} 

Các in-line phiên bản có một tham chiếu ngầm định đối tượng mới (trên ngăn xếp). Nó sẽ có sẵn để thu gom rác ngay sau khi cuộc gọi phương thức kết thúc.

+0

Lưu ý rằng hai đoạn mã khác nhau ở cấp độ bytecode, mặc dù chúng thực sự tương đương về mặt chức năng. – arshajii

+0

Có phải tài liệu được viết ở đâu đó hoặc còn lại để triển khai JVM không? –

5

Bạn có thể ghé qua bytecode cho cái nhìn sâu sắc:

0: new   #16     // class SomeClass 
    3: dup 
    4: invokespecial #18     // Method SomeClass."<init>":()V 
    7: invokevirtual #19     // Method SomeClass.longMethod:()V 
  • new thực sự phân bổ các đối tượng, một tham chiếu đến được đẩy vào stack.
  • dup sao chép phần trên cùng của ngăn xếp; bây giờ hai mục stack hàng đầu là các tham chiếu đến đối tượng mới được tạo ra.
  • invokespecial tại đây gọi hàm tạo của SomeClass, popping ngăn xếp; bây giờ ngăn xếp bao gồm chỉ một tham chiếu duy nhất cho ví dụ SomeClass của chúng tôi. Ví dụ không phải là GCed vì một tham chiếu đến nó tồn tại trên stack.
  • invokevirtual tại đây gọi longMethod. Một lần nữa, cá thể không phải là GCed vì một tham chiếu đến nó vẫn tồn tại trên ngăn xếp (và được xuất hiện sau khi phương thức hoàn thành, sau đó phương thức đủ điều kiện cho GC).

(new SomeClass()).longMethod(); 

là không giống như

{ 
    // very local scope 
    SomeClass throwAwayRef = new SomeClass(); 
    throwAwayRef.longMethod(); 
} 

ở cấp bytecode, vì sau này liên quan đến một astore và một aload. Tuy nhiên, cả hai chắc chắn có chức năng tương đương. Ví dụ SomeClass vẫn trở thành đủ điều kiện cho GC sau khi hoàn thành longMethod (ngăn xếp cho hai đoạn mã sẽ giống hệt nhau khi invokevirtual được thực hiện).


tham khảo:

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