2009-07-01 31 views

Trả lời

210

Java khó hiểu vì mọi thứ được chuyển theo giá trị. Tuy nhiên đối với tham số của loại tham chiếu (nghĩa là không phải là tham số kiểu nguyên thủy), nó là tham chiếu chính nó được chuyển theo giá trị, do đó nó xuất hiện để được tham chiếu (và mọi người thường cho rằng Là). Đây không phải là trường hợp, như được hiển thị bởi những điều sau đây:

Object o = "Hello"; 
mutate(o) 
System.out.println(o); 

private void mutate(Object o) { o = "Goodbye"; } //NOT THE SAME o! 

Sẽ in Hello vào bảng điều khiển. Các tùy chọn nếu bạn muốn mã ở trên để in Goodbye là để sử dụng một tham chiếu rõ ràng như sau:

AtomicReference<Object> ref = new AtomicReference<Object>("Hello"); 
mutate(ref); 
System.out.println(ref.get()); //Goodbye! 

private void mutate(AtomicReference<Object> ref) { ref.set("Goodbye"); } 
+46

Ngoài ra, một mảng chiều dài 1 có thể được sử dụng để Tạo một tham chiếu nếu bạn thực sự muốn gây nhầm lẫn cho mọi người :) – Christoffer

+1

Điều này là rất đúng –

+2

AtomicReference và các lớp tương ứng (AtomicInteger) là tốt nhất cho các hoạt động đó – Naveen

10

Tôi không nghĩ rằng bạn có thể. Lựa chọn tốt nhất của bạn có thể là đóng gói thứ bạn muốn chuyển qua "by ref" vào một cá thể lớp khác và chuyển tham chiếu của lớp (bên ngoài) (theo giá trị). Nếu bạn hiểu ý tôi là gì ...

tức là phương pháp của bạn sẽ thay đổi trạng thái bên trong của đối tượng được truyền, sau đó nó sẽ hiển thị với người gọi.

23

Trong Java, không có gì ở cấp độ ngôn ngữ tương tự như ref. Trong Java có chỉ đi ngang qua giá trị ngữ nghĩa

Vì lợi ích của sự tò mò, bạn có thể thực hiện một ref giống như ngữ nghĩa trong Java chỉ đơn giản gói đối tượng của bạn trong một lớp học có thể thay đổi:

public class Ref<T> { 

    private T value; 

    public Ref(T value) { 
     this.value = value; 
    } 

    public T get() { 
     return value; 
    } 

    public void set(T anotherValue) { 
     value = anotherValue; 
    } 

    @Override 
    public String toString() { 
     return value.toString(); 
    } 

    @Override 
    public boolean equals(Object obj) { 
     return value.equals(obj); 
    } 

    @Override 
    public int hashCode() { 
     return value.hashCode(); 
    } 
} 

testcase:

public void changeRef(Ref<String> ref) { 
    ref.set("bbb"); 
} 

// ... 
Ref<String> ref = new Ref<String>("aaa"); 
changeRef(ref); 
System.out.println(ref); // prints "bbb" 
+1

Nếu dòng thứ hai cuối cùng đọc "test (ref);"? –

+0

@ Fisher Fisher: cố định, cảm ơn – dfa

+0

Tại sao không sử dụng java.lang.ref.Reference thay thế? – Hardcoded

62

Tôi có thể chuyển tham số theo tham chiếu trong Java?

số

Tại sao? Java có chỉ một chế độ đối số truyền qua các phương thức: theo giá trị.

Lưu ý:

Đối với nguyên thủy, điều này rất dễ hiểu: bạn nhận được bản sao của giá trị.

Đối với tất cả các trường hợp khác, bạn sẽ nhận được một bản sao của tham chiếu và điều này cũng được gọi là đi qua giá trị.

Đó là tất cả trong ảnh này:

enter image description here

+14

+1 cho nerdness! – dfa

+3

Ảnh bị hỏng. – Omar

+8

+1 Ví dụ nơi hình ảnh cung cấp giải thích rõ ràng hơn các từ – bmartins

5

Java luôn vượt qua bởi giá trị.

Khi bạn vượt qua một nguyên thủy đó là một bản sao của giá trị, khi bạn vượt qua một đối tượng đó là một bản sao của con trỏ tham chiếu.

18

Từ James Gosling trong "The Java Ngôn ngữ lập trình":

"... Có đúng một tham số chế độ đi qua trong Java - đi qua giá trị - và giữ cho mọi thứ đơn giản ..."

+2

Việc tuyên bố của ngôn ngữ thần nên được tuyên bố câu trả lời. – ingyhere

+2

@ingyhere: 'Tuyên bố của ngôn ngữ thần nên được khai báo câu trả lời': Không thực sự. Mặc dù những gì người sáng tạo của Java suy nghĩ hoặc tin, câu trả lời tuyệt đối sẽ đến từ một trích dẫn từ đặc tả ngôn ngữ. – paercebal

+0

Trên thực tế, nó nằm trong [JLS, trong phần 8.4.1] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.1), và JLS trích dẫn Gosling là tác giả đầu tiên: "Khi phương thức hoặc hàm tạo được gọi (§15.12), ** các giá trị của các biểu thức đối số thực sự khởi tạo các biến tham số mới được tạo **, mỗi loại khai báo, trước khi thực thi phần thân của phương thức hoặc hàm tạo. " – ingyhere

4

Tùy chọn khác là sử dụng mảng, ví dụ: void method(SomeClass[] v) { v[0] = ...; } nhưng 1) mảng phải được khởi tạo trước khi phương thức được gọi, 2) vẫn không thể triển khai thực hiện ví dụ: phương pháp hoán đổi theo cách này ... Cách này được sử dụng trong JDK, ví dụ: trong số java.util.concurrent.atomic.AtomicMarkableReference.get(boolean[]).

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