|
Εισαγωγή
Όπως είδαμε
σε προηγούμενα
κείμενα οι μεταβλητές
αποτελούνε ένα
αναπόσπαστο
κομμάτι, όχι μόνο
της Java αλλά
όλων των γλωσσών
προγραμματισμού.
Αυτές οι μεταβλητές
συνήθως περνάνε
από μέθοδο σε
μέθοδο και από
αντικείμενο σε
αντικείμενο
ώστε να μπορέσει
ένα πρόγραμμα να
εκπληρώσει το
σκοπό του. Υπάρχουνε
δύο τρόποι που
οι μεταβλητές
μπορούνε να διέρχονται
μεταξύ των μεθόδων
και αντικειμένων.
Μεσω της «τιμής
τους» (by-value)
ή «της αναφοράς
τους» (by
reference).
Ορισμός
Πρωτού
αναλύσουμε αν
οι μεταβλητές
στη Java περνούνται by
value ή by reference ας
δούμε πρώτα τι
σημαίνουνε οι
προτάσεις
«pass-by-value»
και «pass-by-reference».Με
τον όρο «pass-by-value»
εννοούμε ότι
περνιέται ένα
αντίγραφο της
μεταβλητής μεταξύ
των μεθόδων. Δηλαδή
η τιμή της μεταβλητής
αντιγράφεται
και το αντίγραφό
της διέρχεται
μεταξύ των καλεσμάτων
των μεθόδων. Οποιαδήποτε
αλλαγή στο
αντίγραφο της
μεταβλητής δεν
έχει αντίκτυπο
στην αρχική μεταβλητή.Με
τον όρο «pass-by-reference»
εννούμε ότι περνιέται
η μεταβλητή αυτή
καθεαυτή. Οποιαδήποτε
μεταβολή στη
μεταβλητή έχει
αντίκτυπο σε
οποιοδήποτε
άλλο μέρος
χρησιμοποιείται
αυτή η μεταβλητή.
Pass
by value
Στη Java όπως ξέρουμε
υπάρχουνε δύο
ειδών μεταβλητές,
οι μεταβλητές
πρωτογενή τύπου
και οι μεταβλητές
τύπου αντικειμένου
(αναφορές). Και
τα δύο είδη μεταβλητών
περνούνται by-value
(αντέγραψε την
τιμή και πέρασε
το αντίγραφο).
Και με τους
πρωτογενείς
τύπους και με
τις αναφορές
παίρνουμε ένα
αντίγραφο του
περιεχομένου.
Είναι ένα συνηθισμένο
λάθος να νομίζεται
ότι οι μεταβλητές
πρωτογενή τύπου
περνούνται by-value
ενώ οι αναφορές
περνούνται by-reference.
Για να
το καταλάβουμε
καλύτερα ας
ρίξουμε μία ματιά
στο παρακάτω
παράδειγμα.
int
number = 10;
System.out.println(number);
incrementNumber(number);
System.out.println(number);
public
void incrementNumber(int anotherNumber){
anotherNumber++;
System.out.println(anotherNumber);
}
Στο παραπάνω
παράδειγμα περνάμε
στη μέθοδο incrementNumber
ένα αντίγραφο της
τιμής της μεταβλητής number.
Οποιαδήποτε
αλλαγή γίνει
στη μεταβλητή anotherNumber
μέσα στη μέθοδο
δε θα έχει αντίκτυπο
στη μεταβλητή number
έξω
από τη μέθοδο. Η
εικονική μηχανή
περνάει ένα αντίγραφο
της τιμής και
οποιαδήποτε
αλλαγή γίνει
στο αντίγραφο
δε θα επηρεάσει
την αρχική τιμή. Έτσι
το αποτέλεσμα,
πριν και μετά
καλέσουμε τη
μέθοδο incrementNumber
θα είναι 10
και 10, ενώ
μέσα στη μέθοδο
η μεταβλητή anotherNumber
παίρνει την τιμή
11. Βλέπουμε ότι
αν και αυξήσαμε
τη μεταβλητή anotherNumber
δεν επηρρέασε
τη μεταβλητή number
διότι άλλαξε μόνο
το αντίγραφο της number.
Το ίδιο
γίνεται και με
τις αναφορές.
Όταν περνιέται μία
αναφορά στην ουσία
περνιέται ένα
αντίγραφο της
αναφοράς και
όχι η ίδια η αναφορά
αυτή καθεαυτή.
Αυτό το αντίγραφο
δείχνει στο ίδιο
όμως αντικείμενο
στη μνήμη στο οποίο
δείχνει και η
αρχική αναφορά
αφού ξέρουμε ότι
οι αναφορές στη Java δεν είναι
τίποτα άλλο παρά
μεταβλητές που
εστιαζούνε σε
συγκεκριμένες
θέσεις της μνήμης,
σε συγκεκριμένα
«κουτάκια».
Οπότε και η αρχική
μεταβλητή και
το αντίγραφό της
στοχεύουνε
στην ίδια τοποθεσία
της μνήμης. Το
παρακάτω παράδειγμα
διευκρινίζει
του πως οι αναφορές
περνούνται από
μέθοδο σε μέθοδο.
StringBuffer
sb1 = new StringBuffer("hello");
System.out.println(sb1.toString());
sayHelloWorld(sb1);
System.out.println(sb1);
public
void sayHelloWorld(StringBuffer buffer){
buffer.append("world");
System.out.println(buffer.toString());
}
Για να
καταλάβουμε
πλήρως το παραπάνω
παράδειγμα ας
κοιτάξουμε στην
παρακάτω απεικόνιση
όπου sb1
και buffer
είναι αναφορές
τύπου StringBuffer
που και οι δύο
αναφέρονται στο
ίδιο αντικείμενο
στη μνήμη το οποίο
περιέχει την τιμή 'hello'. H sb1
είναι η αρχική
αναφορά ενώ η buffer
είναι το αντίγραφό
της.
Όπως είπαμε
μέσα στη μέθοδο
έχει περάσει ένα
αντίγραφο της
αναφοράς sb1.
Λόγω του ότι και
τα δύο αντίγραφα
αναφέρονται στο
ίδιο αντικείμενο,
οποιαδήποτε
αλλαγή κάνει η
αναφορά buffer
στο αντικείμενο
αυτό θα έχει αντίκτυπο
και στην αρχική
μεταβληή (sb1).
Η μεταβλητή buffer
αλλάζει το
αντικείμενο με
το να προσθέσει
την λέξη ' world',
άρα η παραπάνω
απεικόνιση γίνεται:

Οπότε το
αποτέλεσμα του
προγράμματος
θα είναι:
hello
hello
world
hello
world
αφού και
η αρχική μεταβλητή
και το αντίγραφό
της αναφέρονται
στο ίδιο αντικείμενο.
Οποιαδήποτε
αλλαγή κάνει το
αντίγραφο της
μεταβλητής θα
έχει αντίκτυπο
και στην αρχική
μεταβλητή. Το
αντίθετο βέβαια
δε συμβαίνει.
Μπορούμε να αλλάξουμε
το αντικείενο
στο οποίο οι
μεταβλητές sb1
και buffer αναφέρονται,
αλλά δεν κάνουμε
τίποτα στις μεταβλητές
τις ίδιες. Αν όμως
χειριστούμε τη
μεταβλητή buffer
και κάνουμε κάτι
σαν:
public
void sayHelloWorld(StringBuffer buffer){
buffer
= new StringBuffer("hey");
buffer.append("world");
System.out.println(buffer.toString());
}
τότε
το
αποτέλεσμα θα
είναι:
hello
hey
world
hello
Αλλάξαμε
τη μεταβλητή buffer
αλλά αυτό δεν
επηρρέασε τη
μεταβλητή sb1
διότι η buffer είναι
ένα αντίγραφο της sb1. Και το
αντίθετο φυσικά
ισχύει. Οποιαδήποτε
αλλαγή στη μεταβλητή sb1 δεν έχει
αντίκτυπο στη
μεταβλητή buffer.
Aποστολόπουλος
Πάρις
Κωνσταντινίδης Πάνος
|