ΕΙΣΑΓΩΓΗ
Στο σημερινό
δωρεάν μάθημα Java, θα δούμε τους τρόπους με τους οποίους μπορούμε να κάνουμε αντίγραφα
αντικειμένων (clones), τι σημαίνει shallow cloning και τι deep cloning, και
γιατί πρέπει να προτιμάμε το copy constructor αντί της clone( ) μεθόδου.
clone( ) METHOD
Η Java δεν μας προσφέρει κάποιο αυτόματο
μηχανισμό για να δημιουργήσει πιστό αντίγραφο ενός αντικειμένου. Μην ξεχνάτε
ότι όταν αναθέτουμε το reference variable σε ένα άλλο reference variable δεν έχουμε δύο αντικείμενα αλλά δύο references που δείχνουν στο ίδιο αντικείμενο.
Όταν μιλάμε για cloning εννοούμε να αντιγράψουμε τα περιεχόμενα ενός αντικειμένου στοιχείο προς
στοιχείο σε ένα καινούργιο αντικείμενο. Για να πραγματοποιήσουμε μια τέτοια
πράξη, θα πρέπει να γράψουμε κώδικα για την μέθοδο clone( ). Ας δούμε όμως πιο συγκεκριμένα τα
βήματα που πρέπει να υλοποιήσουμε.
Για αρχή θα
πρέπει να κάνουμε implements το interface Cloneable στην κλάση μας. Δεν έχουμε μιλήσει ακόμα για interfaces αλλά θεωρείστε τα σαν ένα είδος κλάσης
από τα οποία κληρονομούμε μεθόδους. Για να μπορέσει η κλάση μας να κληρονομήσει
τις μεθόδους ενός interface χρησιμοποιήσουμε τη λέξη κλειδί implements αντί για extends όπως συνηθίζουμε να κάνουμε στις
κλάσεις. Θα μιλήσουμε για το πώς κληρονομούμε από interfaces, και τις διαφορές τους από τις
κλάσεις σε μελλοντικό δωρεάν μάθημα Java. Για τώρα μας είναι αρκετό να
γνωρίζουμε ότι το interface, όταν κληρονομούμε από αυτό, μας προσφέρει κάποιες μεθόδους
για τις οποίες θα πρέπει εμείς να γράψουμε κώδικα, δηλαδή να τις κάνουμε override. Αρχικά ο κώδικας του Employee
αλλάζει ως εξής:
Employee.java
Το δεύτερο
βήμα είναι να κάνουμε override την μέθοδο clone( ) που κληρονομούμε από το interface Cloneable. Επειδή όμως το return type της clone( ) είναι Object θα πρέπει να κάνουμε casting το αντικείμενο μας στην κλάση μέσα
στην οποία υλοποιείται η clone( ) - δηλαδή την Employee. Επίσης, θα πρέπει να προστατέψουμε
τον κώδικα μας από τυχόν λάθη τοποθετώντας τον μέσα σε ένα try-catch. Το πώς χρησιμοποιούμε το try-catch θα το δούμε και αυτό σε μελλοντικό
δωρεάν μάθημα Java. Για τώρα απλά θεωρείστε αναγκαίο ότι ο κώδικας πρέπει να προστατευτεί
γιατί υπάρχει περίπτωση να μας παρουσιάσει CloneNotSupportedException. Ο κώδικας της Employee τώρα είναι ο εξής:
Employee.java
Τώρα ας
γράψουμε το κώδικα της EmployeeDemo μέσα από την οποία θα επιβεβαιώσουμε την cloning διαδικασία. Για αρχή δημιουργούμε ένα
αντικείμενο είδος Employee και αφού αναθέσουμε ένα όνομα στην instance variable name, πραγματοποιούμε cloning στο αντικείμενο. Το αποτέλεσμα είναι
ότι και τα δύο αντικείμενα έχουν την ίδια τιμή για την μεταβλητή name. Μετά αλλάζουμε το όνομα σε ένα από
τα αντικείμενα. Επιβεβαιώνουμε ότι ενώ η τιμή του ενός αντικειμένου αλλάζει, το
δεύτερο αντικείμενο δεν επηρεάζεται.
EmployeeDemo.java
Output
Original:Michail
Clone:Michail
Original:George
Clone:Michail
Shallow Cloning
Αν και
φαίνεται ότι η cloning διαδικασία δουλεύει χωρίς κανένα πρόβλημα, αυτός ο τρόπος θεωρείται
αναξιόπιστος και για αυτό τον αποφεύγουμε και δεν τον χρησιμοποιούμε. Πρέπει
όμως πριν δείτε το σωστό τρόπο να καταλάβετε που ακριβώς υπάρχει το πρόβλημα
και γιατί μετά την εκτέλεση του cloning έχουμε ένα shallow cloning αντί για deep cloning.
Η κλάση Employee στο προηγούμενο πρόγραμμα περιέχει instance μεταβλητές είδος int και String. Τώρα ας θεωρήσουμε ότι έχουμε μια ακόμα
κλάση με το όνομα Manager.
Manager.java
Τώρα δηλώνουμε
στην Employee ένα instance variable είδος Manager. Ο κώδικας του Employee αλλάζει ως εξής:
Employee.java
Τώρα αν
εκτελέσουμε την clone( ) θα δημιουργήσουμε ένα πραγματικό κλώνο της Employee αλλά όχι της Manager. Μόνο το reference αντιγράφεται. Όταν λοιπόν δεν αντιγράφονται
όλα τα αντικείμενα στοιχείο προς στοιχείο αλλά μερικά μόνο αυτό ονομάζεται shallow cloning.
EmployeeDemo.java
Output
Original:Director
Clone:Director
Original:Global
Clone:Global
Το
αποτέλεσμα νομίζω μιλάει από μόνο του. Δεν έγινε deep cloning στο manager αλλά αντιγράφτηκε μόνο το reference. Για αυτό και κάθε αλλαγή στo manager reference επηρεάζει και τα δύο αντικείμενα. Σε
αυτή τη περίπτωση θα πρέπει να κάνουμε cloning σε όλα τα reference instance variables για να λειτουργήσει σωστά το
πρόγραμμα μας. Αλλά δεν θα προχωρήσουμε σε αυτή τη λύση γιατί όπως ήδη
αναφέραμε είναι αναξιόπιστη και χρονοβόρα αφού πρέπει να γράψουμε πολύ κώδικα,
να κάνουμε αρκετά casting και να κάνουμε implements το interface Cloneable.
Copy Constructor
Για να
γλυτώσουμε όλα τα παραπάνω έξτρα βήματα αλλά και ταυτόχρονα για να
δημιουργήσουμε ένα πραγματικά deep cloning αντικείμενο χρησιμοποιούμε την
τεχνική του copy constructor.
Αυτή η
τεχνική απαιτεί να δημιουργήσουμε ένα constructor που δέχεται σαν παράμετρο αντικείμενο
της ίδιας κλάσης. Για να το καταλάβετε καλύτερα θα αφαιρέσουμε την Manager απλοποιώντας το παράδειγμα μας.
Employee.java
EmployeeDemo.java
Output
Original:Michail
Clone:Michail
Original:George
Clone:Michail
Μην ξεχάσετε να κάνετε ένα μικρό donation έτσι ώστε αυτό το blog να μεγαλώσει ακόμα πιο πολύ και να έχει περισσότερες δυνατότητες στην online παράδοση δωρεάν μαθημάτων.
full-width
0 Comments
Η γνώμη σας είναι σημαντική.