Rumah  >  Artikel  >  Java  >  Apakah perbezaan antara lulus dengan nilai dan lulus dengan rujukan dalam java

Apakah perbezaan antara lulus dengan nilai dan lulus dengan rujukan dalam java

青灯夜游
青灯夜游asal
2023-01-04 11:50:005739semak imbas

Perbezaan: 1. Pemindahan nilai akan mencipta salinan, manakala pemindahan rujukan tidak mencipta salinan 2. Dalam pemindahan nilai, objek asal tidak boleh diubah dalam fungsi, tetapi dalam pemindahan rujukan, objek asal boleh diubah dalam fungsi. Melepasi nilai bermakna salinan parameter sebenar dihantar ke fungsi apabila memanggil fungsi, supaya jika parameter diubah suai dalam fungsi, parameter sebenar tidak akan terjejas melalui rujukan bermakna parameter sebenar disalin apabila memanggil fungsi Alamat dihantar terus ke fungsi, jadi pengubahsuaian pada parameter dalam fungsi akan mempengaruhi parameter sebenar.

Apakah perbezaan antara lulus dengan nilai dan lulus dengan rujukan dalam java

Persekitaran pengendalian tutorial ini: sistem Windows 7, versi Java 8, komputer DELL G3.

Parameter sebenar dan formal

Kita semua tahu bahawa parameter boleh ditakrifkan semasa mentakrifkan kaedah dalam Java. Sebagai contoh, kaedah utama dalam Java, public static void main(String[ ] args), args di sini ialah parameter. Parameter dibahagikan kepada parameter formal dan parameter sebenar dalam bahasa pengaturcaraan.

  • Parameter formal : ialah parameter yang digunakan semasa mentakrifkan nama fungsi dan badan fungsi Tujuannya adalah untuk menerima parameter yang dihantar semasa memanggil fungsi.

  • Parameter sebenar: Apabila memanggil fungsi berparameter, terdapat perhubungan pemindahan data antara fungsi panggilan dan fungsi yang dipanggil. Apabila memanggil fungsi dalam fungsi panggilan, parameter dalam kurungan selepas nama fungsi dipanggil "parameter sebenar"

Contoh mudah:

public static void main( String[ ] args) {
ParamTest pt = new ParamTest();
pt.sout( "Hollis");//实际参数为Hollis
}
public void sout( String name) {/!形式参数为name
system.out.println(name);
}

Parameter sebenar adakah kandungan sebenarnya diluluskan apabila memanggil kaedah berparameter, manakala parameter formal ialah parameter yang digunakan untuk menerima kandungan parameter sebenar.

Harus nilai dan hantaran rujukan

Seperti yang dinyatakan di atas, apabila kita memanggil fungsi berparameter, parameter sebenar akan dihantar kepada parameter formal. Walau bagaimanapun, dalam bahasa pengaturcaraan, terdapat dua kes pemindahan dalam proses pemindahan ini, iaitu pemindahan mengikut nilai dan pemindahan melalui rujukan. Mari kita lihat bagaimana lulus mengikut nilai dan lulus melalui rujukan ditakrifkan dan dibezakan dalam bahasa pengaturcaraan.

Lulus nilai bermaksud menyalin parameter sebenar dan menghantarnya ke fungsi apabila memanggil fungsi, supaya jika parameter diubah dalam fungsi, parameter sebenar tidak akan terjejas.
Melalui rujukan merujuk kepada menghantar alamat parameter sebenar terus ke fungsi apabila memanggil fungsi Kemudian pengubahsuaian parameter dalam fungsi akan menjejaskan parameter sebenar.

Dengan konsep di atas, anda boleh menulis kod dan mempraktikkannya. Mari kita lihat sama ada ia lulus mengikut nilai atau lulus melalui rujukan dalam Java Jadi, sekeping kod yang paling mudah keluar:

public static void main( String[] args) {
     ParamTest pt = new ParamTest();
    int i = 10;
    pt.pass(i);
    System.out.println( "print in main , i is " +i);
}
public void pass(int j){
    j = 20;
    system.out.println( "print in pass , j is " + j);
}

Dalam kod di atas, kami mengubah suai nilai parameter j dalam kaedah pas, dan kemudian mencetak nilai parameter dalam kaedah lulus dan kaedah utama masing-masing. Hasil keluaran adalah seperti berikut:

print in pass , j is 20
print in main , i is 10

Dapat dilihat bahawa pengubahsuaian nilai i di dalam kaedah pas tidak mengubah nilai parameter sebenar i. Jadi, mengikut definisi di atas, seseorang membuat kesimpulan: Lulus kaedah Java adalah lulus nilai.
Walau bagaimanapun, beberapa orang tidak lama kemudian menimbulkan soalan (haha, jadi jangan cepat membuat kesimpulan.). Kemudian, mereka akan mengalih keluar kod berikut:

public static void main(String[ ] args) {
    ParamTest pt = new ParamTest();
    User hollis = new User();
    hollis.setName( "Hollis");
    hollis.setGender("Male");
    pt.pass(hollis);
    system.out.println( "print in main , user is " + hollis);}public void pass(User user) {
    user.setName( "hollischuang");
    System.out.println( "print in pass , user is " + user);}

Ia juga merupakan kaedah lulus dan nilai parameter juga diubah suai dalam kaedah pas. Hasil keluaran adalah seperti berikut:

print in pass , user is User{name='hollischuang', gender='Male '}
print in main , user is User{name='hollischuang' , gender='Male '}

Selepas kaedah pas dilaksanakan, nilai parameter sebenar ditukar Mengikut definisi rujukan melalui di atas, nilai parameter sebenar diubah . Bukankah ini dipanggil rujukan? Oleh itu, berdasarkan dua keping kod di atas, seseorang membuat kesimpulan baru: dalam kaedah Java, apabila lulus jenis biasa, ia diluluskan oleh nilai, dan apabila lulus jenis objek, ia diluluskan melalui rujukan.
Walau bagaimanapun, kenyataan ini masih salah. Jika anda tidak percaya saya, lihat pemindahan parameter berikut di mana jenis parameter ialah objek:

public static void main( string[] args) {
    ParamTest pt = new ParamTest();
    string name = "Hollis";
    pt.pass(name ) ;
    System.out.println( "print in main , name is " + name);
}
public void pass(string name) {
    name = "hollischuang";
    system.out.println( "print in pass , name is " + name);
}

Hasil output kod di atas ialah

print in pass , name is hollischuangprint in main , name is Hollis

Apakah penjelasan untuk ini? Objek juga diluluskan, Tetapi nilai parameter asal tidak diubah suai. Mungkinkah objek yang diluluskan telah menjadi nilai semula?

Melalui nilai dalam Java

Di atas, kami memetik tiga Hasilnya berbeza, itulah sebabnya ramai pemula dan juga pengaturcara lanjutan keliru tentang jenis pemindahan Java. Sebenarnya, apa yang saya ingin beritahu anda adalah bahawa konsep di atas tidak salah, tetapi terdapat masalah dengan contoh kod. Ayuh, izinkan saya menggariskan perkara utama konsep untuk anda, dan kemudian memberi anda beberapa contoh yang benar-benar sesuai.

Lulus nilai bermaksud menyalin parameter sebenar dan menghantarnya ke fungsi apabila memanggil fungsi, supaya jika parameter diubah dalam fungsi, parameter sebenar tidak akan terjejas.
Melalui rujukan bermakna apabila memanggil fungsi, alamat parameter sebenar dihantar terus ke fungsi Kemudian pengubahsuaian parameter dalam fungsi akan mempengaruhi parameter sebenar.

Jadi, izinkan saya meringkaskan untuk anda perkara utama perbezaan antara lulus nilai dan lulus rujukan.

我们上面看过的几个pass的例子中,都只关注了实际参数内容是否有改变。如传递的是User对象,我们试着改变他的name属性的值,然后检查是否有改变。其实,在实验方法上就错了,当然得到的结论也就有问题了。

为什么说实验方法错了呢?这里我们来举一个形象的例子。再来深入理解一下值传递和引用传递,然后你就知道为啥错了。

你有一把钥匙,当你的朋友想要去你家的时候,如果你直接把你的钥匙给他了,这就是引用传递。这种情况下,如果他对这把钥匙做了什么事情,比如他在钥匙上刻下了自己名字,那么这把钥匙还给你的时候,你自己的钥匙上也会多出他刻的名字。

你有一把钥匙,当你的朋友想要去你家的时候,你复刻了一把新钥匙给他,自己的还在自己手里,这就是值传递。这种情况下,他对这把钥匙做什么都不会影响你手里的这把钥匙。

但是,不管上面那种情况,你的朋友拿着你给他的钥匙,进到你的家里,把你家的电视砸了。那你说你会不会受到影响?而我们在pass方法中,改变user对象的name属性的值的时候,不就是在“砸电视”么。

还拿上面的一个例子来举例,我们真正的改变参数,看看会发生什么?

public static void main(String[ ] args){
    ParamTest pt = new ParamTest();
    User hollis = new User();
    hollis.setName( "Hollis");
    hollis.setGender("Male" );
    pt.pass(hollis);
    system.out.println("print in main , user is " + hollis);
    public void pass(User user) {
        user = new User();
        user.setName( "hollischuang");
        user.setGender( "Male");
        system.out.println( "print in pass , user is " + user);

上面的代码中,我们在pass方法中,改变了user对象,输出结果如下:

print in pass , user is User{name='hollischuang ' , gender='Male '}
print in main , user is User{name='Hollis', gender= 'Male '}

我们来画一张图,看一下整个过程中发生了什么,然后我再告诉你,为啥Java中只有值传递。

Apakah perbezaan antara lulus dengan nilai dan lulus dengan rujukan dalam java

稍微解释下这张图,当我们在main中创建一个User对象的时候,在堆中开辟一块内存,其中保存了name和gender等数据。然后hollis持有该内存的地址ex123456(图1)。当尝试调用pass方法,并且hollis作为实际参数传递给形式参数user的时候,会把这个地址ex123456交给user,这时,user也指向了这个地址(图2)。然后在pass方法内对参数进行修改的时候,即user = newUser();,会重新开辟一块 eX456789的内存,赋值给user。后面对user的任何修改都不会改变内存eX123456的内容(图3)。

上面这种传递是什么传递?肯定不是引用传递,如果是引用传递的话,在user=new User()的时候,实际参数的引用也应该改为指向eX456789,但是实际上并没有。

通过概念我们也能知道,这里是把实际参数的引用的地址复制了一份,传递给了形式参数。所以,上面的参数其实是值传递,把实参对象引用的地址当做值传递给了形式参数。

我们再来回顾下之前的那个“砸电视”的例子,看那个例子中的传递过程发生了什么。

Apakah perbezaan antara lulus dengan nilai dan lulus dengan rujukan dalam java

同样的,在参数传递的过程中,实际参数的地址eX1213456被拷贝给了形参,只是,在这个方法中,并没有对形参本身进行修改,而是修改的形参持有的地址中存储的内容。

所以,值传递和引用传递的区别并不是传递的内容。而是实参到底有没有被复制一份给形参。在判断实参内容有没有受影响的时候,要看传的的是什么,如果你传递的是个地址,那么就看这个地址的变化会不会有影响,而不是看地址指向的对象的变化。就像钥匙和房子的关系。

那么,既然这样,为啥上面同样是传递对象,传递的String对象和User对象的表现结果不一样呢?我们在pass方法中使用name = “hollischuang”;试着去更改name的值,阴差阳错的直接改变了name的引用的地址。因为这段代码,会new一个String,在把引用交给name,即等价于name =new String(“hollischuang”);。而原来的那个”Hollis”字符串还是由实参持有着的,所以,并没有修改到实际参数的值。

Apakah perbezaan antara lulus dengan nilai dan lulus dengan rujukan dalam java

所以说,Java中其实还是值传递的,只不过对于对象参数,值的内容是对象的引用。

总结

无论是值传递还是引用传递,其实都是一种求值策略(Evaluation strategy)。在求值策略中,还有一种叫做按共享传递。其实Java中的参数传递严格意义上说应该是按共享传递。

Melewati melalui perkongsian bermakna apabila fungsi dipanggil, salinan alamat parameter sebenar dihantar ke fungsi (jika parameter sebenar berada pada timbunan, nilai disalin terus). Apabila mengendalikan parameter di dalam fungsi, anda perlu menyalin alamat untuk mencari nilai tertentu sebelum beroperasi. Jika nilai berada pada timbunan, maka kerana ia adalah salinan langsung nilai, operasi pada parameter dalam fungsi tidak akan menjejaskan pembolehubah luaran. Jika salinan asal ialah alamat nilai asal dalam timbunan, maka anda perlu mencari lokasi yang sepadan dalam timbunan berdasarkan alamat sebelum melakukan operasi. Oleh kerana salinan alamat dihantar, operasi pada nilai dalam fungsi dapat dilihat oleh pembolehubah luaran.

Ringkasnya, pemindahan dalam Java adalah mengikut nilai, dan nilai ini sebenarnya merujuk kepada objek.
Lulus melalui perkongsian sebenarnya hanyalah kes khas lulus dengan nilai. Oleh itu, kita boleh mengatakan bahawa lulus dalam Java adalah lulus dengan perkongsian, atau lulus dalam Java adalah lulus dengan nilai.

Jadi parameter pengendalian di dalam fungsi tidak akan menjejaskan pembolehubah luaran. Jika salinan asal ialah alamat nilai asal dalam timbunan, maka anda perlu mencari lokasi yang sepadan dalam timbunan berdasarkan alamat sebelum melakukan operasi. Oleh kerana salinan alamat dihantar, operasi pada nilai dalam fungsi dapat dilihat oleh pembolehubah luaran.

Ringkasnya, pemindahan dalam Java adalah mengikut nilai, dan nilai ini sebenarnya merujuk kepada objek.

Melalui perkongsian sebenarnya hanyalah kes khas untuk lulus mengikut nilai. Oleh itu, kita boleh mengatakan bahawa lulus dalam Java adalah lulus dengan perkongsian, atau lulus dalam Java adalah lulus dengan nilai.

Untuk lebih banyak pengetahuan berkaitan pengaturcaraan, sila lawati: Pengajaran Pengaturcaraan! !


值传递 引用传递
根本区别 会创建副本 不创建副本
所有 函数中无法改变原始对象 函数中可以改变原始对象
Pass by value Pass by reference
Perbezaan asas Akan membuat salinan Tidak mencipta salinan
Semua Objek asal tidak boleh ditukar dalam fungsi Objek asal boleh ditukar dalam fungsi

Atas ialah kandungan terperinci Apakah perbezaan antara lulus dengan nilai dan lulus dengan rujukan dalam java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn