Προγραμματισμός

Περνά η Java με αναφορά ή μεταβιβάζεται με τιμή;

Πολλές γλώσσες προγραμματισμού επιτρέπουν παραμέτρους μετάδοσης με αναφορά ή αξία. Στην Java, μπορούμε να περάσουμε μόνο παραμέτρους κατά αξία. Αυτό επιβάλλει ορισμένα όρια και θέτει επίσης ερωτήματα. Για παράδειγμα, εάν η τιμή της παραμέτρου αλλάξει στη μέθοδο, τι συμβαίνει με την τιμή μετά την εκτέλεση της μεθόδου; Μπορεί επίσης να αναρωτιέστε πώς η Java διαχειρίζεται τις τιμές αντικειμένων στο σωρό μνήμης. Αυτό Java Challenger σας βοηθά να επιλύσετε αυτές και άλλες συνήθεις ερωτήσεις σχετικά με αναφορές αντικειμένων στην Java.

Λάβετε τον πηγαίο κώδικα

Λάβετε τον κωδικό για αυτό το Java Challenger. Μπορείτε να εκτελέσετε τις δικές σας δοκιμές ενώ ακολουθείτε τα παραδείγματα.

Οι αναφορές αντικειμένων μεταβιβάζονται κατά τιμή

Όλες οι αναφορές αντικειμένων στην Java περνούν από την τιμή. Αυτό σημαίνει ότι ένα αντίγραφο της τιμής θα μεταδοθεί σε μια μέθοδο. Αλλά το κόλπο είναι ότι η παράδοση ενός αντιγράφου της τιμής αλλάζει επίσης την πραγματική τιμή του αντικειμένου. Για να καταλάβετε γιατί, ξεκινήστε με αυτό το παράδειγμα:

 δημόσια τάξη ObjectReferenceExample {public static void main (String ... doYourBest) {Simpson simpson = νέο Simpson (); transformIntoHomer (simpson); System.out.println (simpson.name); } static void transformIntoHomer (Simpson simpson) {simpson.name = "Όμηρος"; }} τάξη Simpson {Όνομα συμβολοσειράς; } 

Τι νομίζετε ότι το simpson.name θα είναι μετά το transformIntoHomer η μέθοδος εκτελείται;

Σε αυτήν την περίπτωση, θα είναι ο Όμηρος! Ο λόγος είναι ότι οι μεταβλητές αντικειμένων Java είναι απλώς αναφορές που δείχνουν σε πραγματικά αντικείμενα στο σωρό μνήμης. Επομένως, παρόλο που η Java μεταβιβάζει παραμέτρους σε μεθόδους ανά τιμή, εάν η μεταβλητή δείχνει μια αναφορά αντικειμένου, το πραγματικό αντικείμενο θα αλλάξει επίσης.

Εάν δεν είστε ακόμα αρκετά ξεκάθαροι πώς λειτουργεί, ρίξτε μια ματιά στο παρακάτω σχήμα.

Rafael Chinelato Del Nero

Οι πρωτόγονοι τύποι περνούν από την τιμή;

Όπως και οι τύποι αντικειμένων, οι πρωτόγονοι τύποι περνούν επίσης από την τιμή. Μπορείτε να συμπεράνετε τι θα συμβεί στους πρωτόγονους τύπους στο ακόλουθο παράδειγμα κώδικα;

 δημόσια τάξη PrimitiveByValueExample {public static void main (String ... primitiveByValue) {int homerAge = 30; αλλαγήHomerAge (homerAge); System.out.println (homerAge); } στατική κενή αλλαγήHomerAge (int homerAge) {homerAge = 35; }} 

Εάν αποφασίσατε ότι η τιμή θα αλλάξει σε 30, έχετε δίκιο. Είναι 30 επειδή (και πάλι) η Java μεταβιβάζει τις παραμέτρους αντικειμένων κατά τιμή. Ο αριθμός 30 είναι απλώς ένα αντίγραφο της τιμής, όχι η πραγματική τιμή. Πρωτόγονοι τύποι κατανέμονται στη μνήμη στοίβας, επομένως μόνο η τοπική τιμή θα αλλάξει. Σε αυτήν την περίπτωση, δεν υπάρχει αναφορά αντικειμένου.

Περνώντας αμετάβλητες αναφορές αντικειμένων

Τι γίνεται αν κάναμε το ίδιο τεστ με αμετάβλητο Σειρά αντικείμενο?

Το JDK περιέχει πολλές αμετάβλητες τάξεις. Παραδείγματα περιλαμβάνουν τους τύπους περιτυλίγματος Ακέραιος αριθμός, Διπλό, Φλοτέρ, Μακρύς, Boolean, Μεγάλο Δεκαδικό, και φυσικά το πολύ γνωστό Σειρά τάξη.

Στο επόμενο παράδειγμα, παρατηρήστε τι συμβαίνει όταν αλλάζουμε την τιμή του a Σειρά.

 δημόσια τάξη StringValueChange {public static void main (String ... doYourBest) {String name = ""; changeToHomer (όνομα); System.out.println (όνομα); } static void changeToHomer (Όνομα συμβολοσειράς) {name = "Homer"; }} 

Ποια πιστεύετε ότι θα είναι η παραγωγή; Αν μαντέψατε "" τότε συγχαρητήρια! Αυτό συμβαίνει επειδή Σειρά αντικείμενο είναι αμετάβλητο, πράγμα που σημαίνει ότι τα πεδία μέσα στο Σειρά είναι οριστικά και δεν μπορούν να αλλάξουν.

Κάνοντας το Σειρά Αμετάβλητη κλάση μας δίνει καλύτερο έλεγχο σε ένα από τα πιο χρησιμοποιημένα αντικείμενα της Java. Εάν η τιμή του Σειρά θα μπορούσε να αλλάξει, θα δημιουργούσε πολλά σφάλματα. Σημειώστε επίσης ότι δεν αλλάζουμε ένα χαρακτηριστικό του Σειρά τάξη; Αντ 'αυτού, απλώς αναθέτουμε ένα νέο Σειρά αξία σε αυτό. Σε αυτήν την περίπτωση, η τιμή "Όμηρος" θα μεταδοθεί στο όνομα στο αλλαγήToHomer μέθοδος. ο Σειρά Ο "Όμηρος" θα είναι επιλέξιμος για συλλογή απορριμμάτων μόλις το αλλαγήToHomer η μέθοδος ολοκληρώνει την εκτέλεση. Παρόλο που το αντικείμενο δεν μπορεί να αλλάξει, η τοπική μεταβλητή θα είναι.

Χορδές και άλλα

Μάθετε περισσότερα για τα Java Σειρά τάξη και πολλά άλλα: Δείτε όλες τις αναρτήσεις του Rafael στη σειρά Java Challengers.

Περνώντας μεταβλητές αναφορές αντικειμένων

Διαφορετικός Σειρά, τα περισσότερα αντικείμενα στο JDK είναι μεταβλητά, όπως το StringBuilder τάξη. Το παρακάτω παράδειγμα είναι παρόμοιο με το προηγούμενο, αλλά διαθέτει χαρακτηριστικά StringBuilder προκειμένου Σειρά:

 static class MutableObjectReference {public static void main (String ... mutableObjectExample) {StringBuilder name = new StringBuilder ("Όμηρος"); addSureName (όνομα); System.out.println (όνομα); } static void addSureName (όνομα StringBuilder) {name.append ("Simpson"); }} 

Μπορείτε να συμπεράνετε την έξοδο για αυτό το παράδειγμα; Σε αυτήν την περίπτωση, επειδή εργαζόμαστε με ένα μεταβλητό αντικείμενο, η έξοδος θα είναι "Homer Simpson". Θα μπορούσατε να περιμένετε την ίδια συμπεριφορά από οποιοδήποτε άλλο μεταβλητό αντικείμενο στην Java.

Έχετε ήδη μάθει ότι οι μεταβλητές Java μεταβιβάζονται κατά τιμή, πράγμα που σημαίνει ότι μεταδίδεται ένα αντίγραφο της τιμής. Απλώς θυμηθείτε ότι η αντιγραμμένη τιμή δείχνει ένα πραγματικό αντικείμενο στο σωρό μνήμης Java. Το πέρασμα από την τιμή αλλάζει ακόμα την τιμή του πραγματικού αντικειμένου.

Πάρτε την πρόκληση για τις αναφορές αντικειμένων!

Σε αυτό το Java Challenger θα δοκιμάσουμε τι έχετε μάθει για τις αναφορές αντικειμένων. Στο παρακάτω παράδειγμα κώδικα, βλέπετε το αμετάβλητο Σειρά και το μεταβλητό StringBuilder τάξη. Κάθε μεταδίδεται ως παράμετρος σε μια μέθοδο. Γνωρίζοντας ότι η Java περνά μόνο από την τιμή, τι πιστεύετε ότι θα είναι η έξοδος μόλις εκτελεστεί η κύρια μέθοδος από αυτήν την τάξη;

 δημόσια τάξη DragonWarriorReferenceChallenger {public static void main (String ... doYourBest) {StringBuilder warriorProfession = νέο StringBuilder ("Dragon"); String warriorWeapon = "Sword"; changeWarriorClass (πολεμιστής επαγγελματίας, πολεμιστής όπλο); System.out.println ("Warrior =" + warriorProfession + "Weapon =" + warriorWeapon); } static void changeWarriorClass (StringBuilder warriorProfession, String όπλο) {warriorProfession.append ("Ιππότης"); όπλο = "Δράκος" + όπλο; όπλο = μηδέν; πολεμιστήςProfession = null; }} 

Εδώ είναι οι επιλογές, ελέγξτε το τέλος αυτού του άρθρου για το κλειδί απάντησης.

ΕΝΑ: Warrior = null Όπλο = null

σι: Warrior = Dragon Weapon = Dragon

ντο: Warrior = Dragon Knight Weapon = Dragon Sword

ρε: Warrior = Dragon Knight Weapon = Sword

Τι ακριβώς συνέβη;

Η πρώτη παράμετρος στο παραπάνω παράδειγμα είναι το πολεμιστής επαγγέλματος μεταβλητή, που είναι ένα μεταβλητό αντικείμενο. Η δεύτερη παράμετρος, το όπλο, είναι αμετάβλητη Σειρά:

 static void changeWarriorClass (StringBuilder warriorProfession, String όπλο) {...} 

Τώρα ας αναλύσουμε τι συμβαίνει μέσα σε αυτήν τη μέθοδο. Στην πρώτη γραμμή αυτής της μεθόδου, προσαρτάμε το ιππότης τιμή στο πολεμιστής επαγγέλματος μεταβλητός. Να θυμάστε ότι πολεμιστής επαγγέλματος είναι ένα μεταβλητό αντικείμενο? Ως εκ τούτου, το πραγματικό αντικείμενο θα αλλάξει και η τιμή από αυτό θα είναι "Dragon Knight".

 warriorProfession.append ("Ιππότης"); 

Στη δεύτερη οδηγία, το αμετάβλητο τοπικό Σειρά η μεταβλητή θα αλλάξει σε "Dragon Sword". Ωστόσο, το πραγματικό αντικείμενο δεν θα αλλάξει ποτέ Σειρά είναι αμετάβλητο και τα χαρακτηριστικά του είναι οριστικά:

 όπλο = "Δράκος" + όπλο; 

Τέλος, περνάμε μηδενικό στις μεταβλητές εδώ, αλλά όχι στα αντικείμενα. Τα αντικείμενα θα παραμείνουν τα ίδια όσο είναι ακόμη προσβάσιμα εξωτερικά - στην περίπτωση αυτή μέσω της κύριας μεθόδου. Και, παρόλο που οι τοπικές μεταβλητές θα είναι μηδενικές, τίποτα δεν θα συμβεί στα αντικείμενα:

 όπλο = μηδέν; ΠολεμιστήςProfession = null; 

Από όλα αυτά μπορούμε να συμπεράνουμε ότι οι τελικές τιμές από τη μεταβλητή μας StringBuilder και αμετάβλητο Σειρά θα είναι:

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

Η μόνη τιμή που άλλαξε στο αλλαγήWarriorClass η μέθοδος ήταν πολεμιστής επαγγέλματος, επειδή είναι μεταβλητή StringBuilder αντικείμενο. Σημειώστε ότι πολεμιστής όπλο δεν άλλαξε γιατί είναι αμετάβλητο Σειρά αντικείμενο.

Η σωστή έξοδος από τον κώδικα Challenger θα ήταν:

ρε: Warrior = Dragon Knight Weapon = Sword.

Πρόκληση βίντεο! Εντοπισμός σφαλμάτων αναφορών αντικειμένων στην Java

Ο εντοπισμός σφαλμάτων είναι ένας από τους ευκολότερους τρόπους για να απορροφήσετε πλήρως τις έννοιες προγραμματισμού, βελτιώνοντας παράλληλα τον κώδικά σας. Σε αυτό το βίντεο μπορείτε να ακολουθήσετε ενώ εντοπίζω το σφάλμα και εξηγώ τις αναφορές αντικειμένων στην Java.

Συνηθισμένα λάθη με αναφορές αντικειμένων

  • Προσπαθώντας να αλλάξετε μια αμετάβλητη τιμή με αναφορά.
  • Προσπαθώντας να αλλάξετε μια αρχική μεταβλητή με αναφορά.
  • Η αναμονή του πραγματικού αντικειμένου δεν θα αλλάξει όταν αλλάζετε μια μεταβλητή παράμετρο αντικειμένου σε μια μέθοδο.

Τι πρέπει να θυμάστε για τις αναφορές αντικειμένων

  • Η Java περνά πάντα τις μεταβλητές παραμέτρων ανά τιμή.
  • Οι μεταβλητές αντικειμένων στην Java δείχνουν πάντα το πραγματικό αντικείμενο στο σωρό μνήμης.
  • Η τιμή ενός μεταβλητού αντικειμένου μπορεί να αλλάξει όταν μεταβιβάζεται σε μια μέθοδο.
  • Η τιμή ενός αμετάβλητου αντικειμένου δεν μπορεί να αλλάξει, ακόμα κι αν περάσει μια νέα τιμή.
  • Το "Passing by value" αναφέρεται στη διαβίβαση ενός αντιγράφου της τιμής.
  • «Περνώντας με αναφορά» αναφέρεται στο πέρασμα της πραγματικής αναφοράς της μεταβλητής στη μνήμη.

Μάθετε περισσότερα για την Java

  • Λάβετε περισσότερες γρήγορες συμβουλές κώδικα: Διαβάστε όλες τις αναρτήσεις του Rafael στη σειρά JavaWorld Java Challengers.
  • Μάθετε περισσότερα σχετικά με μεταβλητά και αμετάβλητα αντικείμενα Java (όπως Σειρά και StringBuffer) και πώς να τα χρησιμοποιήσετε στον κώδικά σας.
  • Μπορεί να εκπλαγείτε να μάθετε ότι οι πρωτόγονοι τύποι της Java είναι αμφιλεγόμενοι. Σε αυτό το χαρακτηριστικό, ο Ιωάννης Ι. Μουρ κάνει την υπόθεση για τη διατήρησή τους και την εκμάθηση να τα χρησιμοποιεί καλά.
  • Συνεχίστε να αναπτύσσετε τις ικανότητές σας προγραμματισμού Java στο Java Dev Gym.
  • Αν σας άρεσε το σφάλμα εντοπισμού κληρονομιάς Java, ρίξτε μια ματιά σε περισσότερα βίντεο στη λίστα αναπαραγωγής βίντεο του Rafael's Java Challenges (τα βίντεο αυτής της σειράς δεν σχετίζονται με το JavaWorld).
  • Θέλετε να εργαστείτε σε έργα χωρίς άγχος και να γράψετε κώδικα χωρίς σφάλματα; Προχωρήστε στο NoBugsProject για το αντίγραφο του Χωρίς σφάλματα, χωρίς άγχος - Δημιουργήστε λογισμικό που αλλάζει τη ζωή χωρίς να καταστρέψετε τη ζωή σας.

Αυτή η ιστορία, "Μήπως η Java περνάει με αναφορά ή περνά από αξία;" δημοσιεύθηκε αρχικά από το JavaWorld.