Tôi có thể truyền tham số bằng tham chiếu trong Java không?


Câu trả lời:


225

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

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

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

Sẽ in Hellora bàn điều khiển. Các tùy chọn nếu bạn muốn mã ở trên để in Goodbyesử dụng 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"); }

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

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

3
AtomicReference là một quá mức cần thiết, bạn không nhất thiết muốn có rào cản bộ nhớ ở đó và chúng có thể khiến bạn phải trả giá. JRuby có vấn đề về độ hoàn hảo do một biến dễ bay hơi được sử dụng khi xây dựng một Object. Tùy chọn sử dụng mảng làm tài liệu tham khảo đặc biệt có vẻ đủ tốt cho tôi và tôi đã thấy nó được sử dụng nhiều lần.
Elazar Leibovich

Tôi không nghĩ rằng điều này là khó hiểu, tuy nhiên đây là hành vi bình thường. Các loại giá trị tồn tại trên ngăn xếp và các loại tham chiếu tồn tại trên heap, nhưng tham chiếu cho các loại tham chiếu cũng tồn tại trên ngăn xếp. Do đó, bạn luôn luôn hoạt động với giá trị trên ngăn xếp. Tôi tin rằng câu hỏi ở đây là: Có thể chuyển tham chiếu từ ngăn xếp trỏ đến một số giá trị khác cũng nằm trên ngăn xếp. Hoặc chuyển tham chiếu của tài liệu tham khảo khác mà điểm trên một số giá trị sống trên heap?
eomeroff

đây là thông tin tuyệt vời tôi đã sử dụng mảng nhưng điều này có vẻ giống như một cái gì đó được xây dựng cho công việc. Tuy nhiên, tôi không biết về hiệu suất của điều này so với mảng, nếu trong một vòng quan trọng về hiệu suất
steveh

65

Tôi có thể truyền tham số bằng tham chiếu trong Java không?

Không.

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

Ghi chú:

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

Đối với tất cả những người khác, bạn nhận được một bản sao của tài liệu tham khảo và điều này cũng được gọi là chuyển qua giá trị.

Đó là tất cả trong bức tranh này:

nhập mô tả hình ảnh ở đây


25

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

Vì sự tò mò, bạn có thể triển khai một ngữ nghĩa giống như trong Java chỉ đơn giản là bọc các đối tượng của bạn trong một lớp 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();
    }
}

thử nghiệm:

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

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

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

java.lang.ref.Reference không có phương thức thiết lập, nó không thể thay đổi
dfa

Tại sao không sử dụng AtomicReference(đối với người không nguyên thủy)? Hoặc AtomicSomething(ví dụ AtomicBoolean:) cho người nguyên thủy?
Arvin

Thật không may, <T> không chấp nhận các kiểu nguyên thủy. Muốn làm điều này: Tham khảo <int>
jk7

1
@ jk7 Có thực sự đủ quan trọng để sử dụng intthay vì Integer, boolthay vì Booleanvà như vậy không? Đó là, các lớp bao bọc (được tự động mở ra nếu bạn lo lắng về cú pháp) không hoạt động?
Paul Stelian

18

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

"... Có chính xác một chế độ truyền tham số trong Java - truyền theo giá trị - và điều đó giúp mọi thứ đơn giản. .."


2
Phát âm của thần ngôn ngữ nên được tuyên bố câu trả lời.
ingyhere

3
@ingyhere :: The pronouncement of the language god should be declared the answerKhông hẳn. Bất chấp những gì người tạo ra Java 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

1
Trong thực tế, nó nằm trong JLS, trong phần 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 biểu thức đối số thực tế khởi tạo các biến tham số mới được tạo , mỗi biến của kiểu 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

Chính xác. Sarcasm từ các thành viên đại diện thấp không hữu ích.
duffymo

11

Tôi không nghĩ bạn có thể. Tùy chọn tốt nhất của bạn có thể là gói gọn thứ bạn muốn chuyển "bằng ref" sang một thể hiện của lớp khác và truyền tham chiếu của lớp (bên ngoài) (theo giá trị). Nếu bạn hiểu ý tôi là ...

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


7

Java luôn luôn vượt qua 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.


4

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

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.