Bisakah saya melewati parameter dengan referensi di Java?


Jawaban:


225

Java membingungkan karena semuanya dilewatkan oleh nilai . Namun untuk parameter tipe referensi (yaitu bukan parameter tipe primitif) itu adalah referensi itu sendiri yang dilewatkan oleh nilai, maka itu tampaknya menjadi pass-by-reference (dan orang sering mengklaim bahwa itu adalah). Ini tidak terjadi, seperti yang ditunjukkan oleh hal berikut:

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

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

Akan mencetak Helloke konsol. Opsi jika Anda ingin mencetak kode di atas Goodbyeadalah dengan menggunakan referensi eksplisit sebagai berikut:

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
Juga, sebuah array dengan panjang 1 dapat digunakan untuk membuat referensi jika Anda benar-benar ingin membingungkan orang :)
Christoffer

2
AtomicReference dan kelas terkait (AtomicInteger) adalah yang terbaik untuk operasi seperti itu
Naveen

3
AtomicReference adalah kerja keras, Anda tidak perlu penghalang memori di sana, dan mereka mungkin dikenakan biaya. JRuby memiliki masalah kinerja karena variabel volatil yang digunakan ketika membangun Obyek. Opsi menggunakan array sebagai referensi ad-hoc tampaknya cukup baik untuk saya, dan saya telah melihatnya menggunakan lebih dari sekali.
Elazar Leibovich

Saya tidak berpikir bahwa ini membingungkan, namun ini adalah perilaku normal. Jenis nilai ada di stack dan tipe referensi ada di heap, tetapi referensi untuk tipe referensi ada di stack juga. Dengan demikian Anda selalu beroperasi dengan nilai yang ada di stack. Saya percaya bahwa pertanyaan di sini adalah: Apakah mungkin untuk melewati referensi dari stack yang menunjuk pada beberapa nilai lain yang juga ada di stack. Atau lulus referensi dari referensi lain yang menunjuk pada beberapa nilai yang hidup di heap?
eomeroff

ini saya info bagus. Saya telah menggunakan array tetapi ini sepertinya sesuatu yang dibangun untuk pekerjaan itu. saya tidak tahu tentang kinerja array vs ini, jika dalam loop kinerja kritis
steveh

65

Bisakah saya melewati parameter dengan referensi di Java?

Tidak.

Mengapa Java hanya memiliki satu mode meneruskan argumen ke metode: dengan nilai.

catatan:

Untuk primitif ini mudah dimengerti: Anda mendapatkan salinan nilainya.

Untuk semua yang lain Anda mendapatkan salinan referensi dan ini disebut juga lewat nilai.

Semuanya ada dalam gambar ini:

masukkan deskripsi gambar di sini


25

Di Jawa tidak ada pada tingkat bahasa yang mirip dengan ref . Di Jawa hanya ada yang lewat nilai semantik

Demi rasa ingin tahu Anda dapat menerapkan semantik seperti-ref di Jawa hanya membungkus objek Anda dalam kelas yang bisa berubah:

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();
    }
}

Kasus cobaan:

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

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

Mengapa tidak menggunakan java.lang.ref.Referensi sebagai gantinya?
Hardcoded

java.lang.ref.Reference tidak memiliki metode set, tidak bisa berubah
DFA

mengapa tidak menggunakan AtomicReference(untuk non-primitif)? Atau AtomicSomething(misalnya AtomicBoolean:) untuk primitif?
Arvin

Sayangnya, <T> tidak menerima tipe primitif. Ingin melakukan ini: Ref <int>
jk7

1
@ jk7 Apakah benar-benar cukup penting untuk harus menggunakan intalih- alih Integer, boolbukannya Booleandan seterusnya? Yaitu, kelas wrapper (yang secara otomatis tidak terbuka jika Anda khawatir tentang sintaks) tidak berfungsi?
Paul Stelian

18

Dari James Gosling dalam "Bahasa Pemrograman Java":

"... Hanya ada satu mode passing parameter di Jawa - lulus dengan nilai - dan itu membuat semuanya menjadi sederhana ..."


2
Pernyataan dewa bahasa harus dinyatakan sebagai jawabannya.
ingyhere

3
@ingyhere:: The pronouncement of the language god should be declared the answerTidak juga. Terlepas dari apa yang dipikirkan atau diyakini oleh pencipta Jawa, jawaban absolut akan datang dari kutipan dari spesifikasi bahasa.
paercebal

1
Sebenarnya itu ada di JLS, di bagian 8.4.1 , dan JLS mengutip Gosling sebagai penulis pertama: "Ketika metode atau konstruktor dipanggil (§15.12), nilai-nilai dari argumen aktual ekspresi menginisialisasi variabel parameter yang baru dibuat , masing-masing dari tipe yang dideklarasikan, sebelum eksekusi tubuh metode atau konstruktor. "
ingyhere

Persis. Sarkasme dari anggota perwakilan rendah tidak membantu.
duffymo

11

Saya pikir kamu tidak bisa. Pilihan terbaik Anda mungkin untuk merangkum hal yang ingin Anda sampaikan "dengan ref" ke instance kelas lain, dan meneruskan referensi kelas (luar) (berdasarkan nilai). Jika Anda melihat apa yang saya maksud ...

yaitu metode Anda mengubah keadaan internal objek yang dilewati, yang kemudian terlihat oleh pemanggil.


7

Java selalu melewati nilai.

Ketika Anda melewati primitif itu adalah salinan nilai, ketika Anda melewati objek itu adalah salinan dari pointer referensi.


4

Opsi lain adalah menggunakan array, mis. void method(SomeClass[] v) { v[0] = ...; } Tetapi 1) array harus diinisialisasi sebelum metode dipanggil, 2) masih ada yang tidak dapat mengimplementasikan mis. Metode swap dengan cara ini ... Cara ini digunakan di JDK, misalnya dalam java.util.concurrent.atomic.AtomicMarkableReference.get(boolean[]).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.