Adakah Java melalui rujukan atau lulus dengan nilai?

Banyak bahasa pengaturcaraan membenarkan melewati parameter dengan merujuk atau berdasarkan nilai . Di Jawa, kita hanya dapat melewati parameter dengan nilai . Ini membebankan beberapa had dan juga menimbulkan persoalan. Sebagai contoh, jika nilai parameter diubah dalam metode, apa yang terjadi pada nilai setelah pelaksanaan metode? Anda juga mungkin tertanya-tanya bagaimana Java menguruskan nilai objek di timbunan memori. Ini Java Challenger membantu anda menyelesaikan ini dan soalan lain yang biasa tentang rujukan objek di Jawa.

Dapatkan kod sumber

Dapatkan kod untuk Java Challenger ini. Anda boleh menjalankan ujian anda sendiri semasa anda mengikuti contohnya.

Rujukan objek dilalui mengikut nilai

Semua rujukan objek di Java diteruskan berdasarkan nilai. Ini bermaksud bahawa salinan nilai akan diteruskan ke kaedah. Tetapi muslihatnya adalah dengan memberikan salinan nilai juga mengubah nilai sebenar objek. Untuk memahami mengapa, mulakan dengan contoh ini:

 public class ObjectReferenceExample { public static void main(String... doYourBest) { Simpson simpson = new Simpson(); transformIntoHomer(simpson); System.out.println(simpson.name); } static void transformIntoHomer(Simpson simpson) { simpson.name = "Homer"; } } class Simpson { String name; } 

Apa pendapat anda tentang simpson.namekehendak setelah transformIntoHomerkaedah dijalankan?

Dalam kes ini, ia akan menjadi Homer! Sebabnya adalah bahawa pemboleh ubah objek Java hanyalah rujukan yang menunjuk ke objek nyata di timbunan memori. Oleh itu, walaupun Java meneruskan parameter ke metode dengan nilai, jika pemboleh ubah menunjuk ke rujukan objek, objek yang sebenarnya juga akan diubah.

Sekiranya anda masih belum jelas bagaimana ini berfungsi, lihat gambar di bawah.

Rafael Chinelato Del Nero

Adakah jenis primitif dilalui nilai?

Seperti jenis objek, jenis primitif juga dilalui oleh nilai. Bolehkah anda menyimpulkan apa yang akan berlaku pada jenis primitif dalam contoh kod berikut?

 public class PrimitiveByValueExample { public static void main(String... primitiveByValue) { int homerAge = 30; changeHomerAge(homerAge); System.out.println(homerAge); } static void changeHomerAge(int homerAge) { homerAge = 35; } } 

Sekiranya anda menentukan bahawa nilainya akan berubah menjadi 30, anda betul. Ini 30 kerana (sekali lagi) Java melewati parameter objek dengan nilai. Nombor 30 hanyalah salinan nilai, bukan nilai sebenarnya. Jenis primitif diperuntukkan dalam memori timbunan, jadi hanya nilai tempatan yang akan diubah. Dalam kes ini, tidak ada rujukan objek.

Melewati rujukan objek yang tidak berubah

Bagaimana jika kita melakukan ujian yang sama dengan Stringobjek yang tidak berubah ?

JDK mengandungi banyak kelas yang tidak berubah. Contohnya termasuk jenis pembungkus Integer, Double, Float, Long, Boolean, BigDecimal, dan sudah tentu sangat terkenal Stringkelas.

Dalam contoh seterusnya, perhatikan apa yang berlaku apabila kita mengubah nilai a String.

 public class StringValueChange { public static void main(String... doYourBest) { String name = ""; changeToHomer(name); System.out.println(name); } static void changeToHomer(String name) { name = "Homer"; } } 

Apa yang anda fikir outputnya? Sekiranya anda meneka "" maka selamat! Itu berlaku kerana Stringobjek tidak dapat diubah, yang bermaksud bahawa medan di dalamnya Stringadalah final dan tidak dapat diubah.

Membuat Stringkelas tidak berubah memberi kita kawalan yang lebih baik terhadap salah satu objek Java yang paling sering digunakan. Sekiranya nilai a Stringdapat diubah, ia akan menghasilkan banyak pepijat. Perhatikan juga bahawa kami tidak mengubah atribut Stringkelas; sebaliknya, kita hanya memberikan Stringnilai baru kepadanya. Dalam kes ini, nilai "Homer" akan diteruskan namedalam changeToHomerkaedah. The String"Homer" akan layak untuk sampah dikumpulkan sebaik sahaja changeToHomerkaedah melengkapkan pelaksanaan. Walaupun objek tidak dapat diubah, pemboleh ubah tempatan akan.

Rentetan dan banyak lagi

Ketahui lebih lanjut mengenai Stringkelas Java dan banyak lagi: Lihat semua catatan Rafael dalam siri Java Challengers.

Melewati rujukan objek yang boleh berubah

Tidak seperti String, kebanyakan objek di JDK boleh berubah, seperti StringBuilderkelas. Contoh di bawah ini serupa dengan yang sebelumnya, tetapi mempunyai ciri StringBuilderdan bukannya String:

 static class MutableObjectReference { public static void main(String... mutableObjectExample) { StringBuilder name = new StringBuilder("Homer "); addSureName(name); System.out.println(name); } static void addSureName(StringBuilder name) { name.append("Simpson"); } } 

Bolehkah anda menyimpulkan output untuk contoh ini? Dalam kes ini, kerana kami bekerja dengan objek yang dapat diubah, outputnya adalah "Homer Simpson." Anda boleh mengharapkan kelakuan yang sama dari objek lain yang dapat diubah di Java.

Anda telah mengetahui bahawa pemboleh ubah Java dilewatkan oleh nilai, yang bermaksud bahawa salinan nilai dilalui. Ingatlah bahawa nilai yang disalin menunjukkan objek sebenar di timbunan memori Java. Melewati nilai tetap mengubah nilai objek sebenar.

Ikuti cabaran rujukan objek!

In this Java Challenger we’ll test what you’ve learned about object references. In the code example below, you see the immutable String and the mutable StringBuilder class. Each is being passed as a parameter to a method. Knowing that Java only passes by value, what do you believe will be the output once the main method from this class is executed?

 public class DragonWarriorReferenceChallenger { public static void main(String... doYourBest) { StringBuilder warriorProfession = new StringBuilder("Dragon "); String warriorWeapon = "Sword "; changeWarriorClass(warriorProfession, warriorWeapon); System.out.println("Warrior=" + warriorProfession + " Weapon=" + warriorWeapon); } static void changeWarriorClass(StringBuilder warriorProfession, String weapon) { warriorProfession.append("Knight"); weapon = "Dragon " + weapon; weapon = null; warriorProfession = null; } } 

Here are the options, check the end of this article for the answer key.

A: Warrior=null Weapon=null

B: Warrior=Dragon Weapon=Dragon

C: Warrior=Dragon Knight Weapon=Dragon Sword

D: Warrior=Dragon Knight Weapon=Sword

What’s just happened?

The first parameter in the above example is the warriorProfession variable, which is a mutable object. The second parameter, weapon, is an immutable String:

 static void changeWarriorClass(StringBuilder warriorProfession, String weapon) { ... } 

Now let’s analyze what is happening inside this method. At the first line of this method, we append the Knight value to the warriorProfession variable. Remember that warriorProfession is a mutable object; therefore the real object will be changed, and the value from it will be “Dragon Knight.”

 warriorProfession.append("Knight"); 

In the second instruction, the immutable local String variable will be changed to “Dragon Sword.” The real object will never be changed, however, since String is immutable and its attributes are final:

 weapon = "Dragon " + weapon; 

Finally, we pass null to the variables here, but not to the objects. The objects will remain the same as long as they are still accessible externally--in this case through the main method. And, although the local variables will be null, nothing will happen to the objects:

 weapon = null; warriorProfession = null; 

From all of this we can conclude that the final values from our mutable StringBuilder and immutable String will be:

 System.out.println("Warrior=" + warriorProfession + " Weapon=" + warriorWeapon); 

The only value that changed in the changeWarriorClass method was warriorProfession, because it’s a mutable StringBuilder object. Note that warriorWeapon did not change because it’s an immutable String object.

The correct output from our Challenger code would be:

D: Warrior=Dragon Knight Weapon=Sword.

Video challenge! Debugging object references in Java

Debugging is one of the easiest ways to fully absorb programming concepts while also improving your code. In this video you can follow along while I debug and explain object references in Java.

Common mistakes with object references

  • Trying to change an immutable value by reference.
  • Trying to change a primitive variable by reference.
  • Expecting the real object won't change when you change a mutable object parameter in a method.

What to remember about object references

  • Java always passes parameter variables by value.
  • Object variables in Java always point to the real object in the memory heap.
  • A mutable object’s value can be changed when it is passed to a method.
  • An immutable object’s value cannot be changed, even if it is passed a new value.
  • “Passing by value” refers to passing a copy of the value.
  • “Passing by reference” refers to passing the real reference of the variable in memory.

Learn more about Java

  • Get more quick code tips: Read all of Rafael's posts in the JavaWorld Java Challengers series.
  • Learn more about mutable and immutable Java objects (such as String and StringBuffer) and how to use them in your code.
  • Anda mungkin terkejut mengetahui bahawa jenis primitif Java kontroversial. Dalam ciri ini, John I. Moore memberikan alasan untuk menjaganya, dan belajar menggunakannya dengan baik.
  • Terus membina kemahiran pengaturcaraan Java anda di Java Dev Gym.
  • Jika anda menyukai debug warisan Java, lihat lebih banyak video dalam senarai main video Rafael's Java Challenges (video dalam siri ini tidak berafiliasi dengan JavaWorld).
  • Ingin mengusahakan projek bebas tekanan dan menulis kod bebas pepijat? Pergi ke NoBugsProject untuk salinan No Bugs, No Stress - Buat Perisian yang Mengubah Hidup Tanpa Menghancurkan Hidup Anda .

Cerita ini, "Apakah Java melewati rujukan atau melewati nilai?" pada asalnya diterbitkan oleh JavaWorld.