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

Κληρονομικότητα στην Java, Μέρος 2: Αντικείμενο και μέθοδοι του

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

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

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

λήψη Λήψη του κώδικα Λήψη του πηγαίου κώδικα για παράδειγμα εφαρμογές σε αυτό το σεμινάριο. Δημιουργήθηκε από τον Jeff Friesen για το JavaWorld.

Αντικείμενο: superclass της Java

Αντικείμενο είναι η κατηγορία root, ή το απόλυτο superclass, όλων των άλλων κλάσεων Java. Αποθηκεύτηκε στο java.lang πακέτο, Αντικείμενο δηλώνει τις ακόλουθες μεθόδους, τις οποίες κληρονομούν όλες οι άλλες κατηγορίες:

  • προστατευμένος κλώνος αντικειμένου ()
  • boolean ισούται με (αντικείμενο obj)
  • προστατευμένο κενό οριστικοποιείται ()
  • Κατηγορία getClass ()
  • int hashCode ()
  • άκυρη ειδοποίηση ()
  • άκυρη ειδοποίησηΌλα ()
  • String toString ()
  • άκυρη αναμονή ()
  • άκυρη αναμονή (μεγάλο χρονικό όριο)
  • άκυρη αναμονή (μεγάλο χρονικό όριο, int nanos)

Μια κλάση Java κληρονομεί αυτές τις μεθόδους και μπορεί να παρακάμψει οποιαδήποτε μέθοδο που δεν έχει δηλωθεί τελικός. Για παράδειγμα, οι μητελικόςtoString () μέθοδος μπορεί να παρακαμφθεί, ενώ το τελικόςΠερίμενε() οι μέθοδοι δεν μπορούν.

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

Γενικοί τύποι

Στην παραπάνω λίστα, μπορεί να έχετε παρατηρήσει getClass (), του οποίου Τάξη ο τύπος επιστροφής είναι ένα παράδειγμα ενός γενικός τύπος. Θα συζητήσω γενικούς τύπους σε μελλοντικό άρθρο.

Επέκταση αντικειμένου: Ένα παράδειγμα

Μια τάξη μπορεί να επεκταθεί ρητά Αντικείμενο, όπως αποδεικνύεται στην καταχώριση 1.

Λίστα 1. Επεκτείνεται εκτενώς το αντικείμενο

δημόσια τάξη Ο υπάλληλος επεκτείνει το αντικείμενο {private String name; δημόσιος υπάλληλος (όνομα συμβολοσειράς) {this.name = name; } δημόσια συμβολοσειρά getName () {return name; } public static void main (String [] args) {Employee emp = new Employee ("John Doe"); System.out.println (emp.getName ()); }}

Επειδή μπορείτε να επεκτείνετε το πολύ μια άλλη τάξη (θυμηθείτε από το Μέρος 1 ότι η Java δεν υποστηρίζει πολλαπλή κληρονομιά που βασίζεται σε τάξη), δεν είστε υποχρεωμένοι να επεκτείνετε Αντικείμενο; Διαφορετικά, δεν θα μπορούσατε να επεκτείνετε οποιαδήποτε άλλη τάξη. Επομένως, θα επεκτείνατε Αντικείμενο σιωπηρά, όπως καταδεικνύεται στη Λίστα 2.

Λίστα 2. Αντικείμενο επέκτασης σιωπηρά

Δημόσιος υπάλληλος κατηγορίας {private String name; δημόσιος υπάλληλος (όνομα συμβολοσειράς) {this.name = name; } δημόσια συμβολοσειρά getName () {return name; } public static void main (String [] args) {Employee emp = new Employee ("John Doe"); System.out.println (emp.getName ()); }}

Μεταγλώττιση καταχώρισης 1 ή καταχώρισης 2 ως εξής:

javac Employee.java

Εκτελέστε την εφαρμογή που προκύπτει:

java Υπάλληλος

Πρέπει να παρατηρήσετε την ακόλουθη έξοδο:

Τζον Ντο

Μάθετε για μια τάξη: getClass ()

ο getClass () Η μέθοδος επιστρέφει την κλάση χρόνου εκτέλεσης οποιουδήποτε αντικειμένου στο οποίο καλείται. ο τάξη χρόνου εκτέλεσης αντιπροσωπεύεται από ένα Τάξη αντικείμενο, το οποίο βρίσκεται στο java.lang πακέτο. Τάξη είναι το σημείο εισόδου στο Java Reflection API, για το οποίο θα μάθετε πότε μπαίνουμε σε πιο προηγμένα θέματα στον προγραμματισμό Java. Προς το παρόν, γνωρίζετε ότι χρησιμοποιεί μια εφαρμογή Java Τάξη και το υπόλοιπο του Java Reflection API για να μάθετε για τη δική του δομή.

Κατηγορία αντικειμένων και στατικές συγχρονισμένες μεθόδους

Οι επιστρεφόμενοι Τάξη αντικείμενο είναι το αντικείμενο που είναι κλειδωμένο από στατικό συγχρονισμένο μέθοδοι της αντιπροσωπευόμενης τάξης · για παράδειγμα, στατικό συγχρονισμένο κενό vo () {}. (Θα παρουσιάσω συγχρονισμό Java σε μελλοντικό σεμινάριο.)

Αντίγραφα αντικειμένων: κλώνος ()

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

Λίστα 3. Κλωνοποίηση ενός αντικειμένου

η κλάση CloneDemo υλοποιεί το Cloneable {int x; public static void main (String [] args) ρίχνει το CloneNotSupportedException {CloneDemo cd = νέο CloneDemo (); cd.x = 5; System.out.println ("cd.x =" + cd.x); CloneDemo cd2 = (CloneDemo) cd.clone (); System.out.println ("cd2.x =" + cd2.x); }}

Λίστα 3's CloneDemo τάξη εφαρμόζει το Κλωνοποιήσιμο διεπαφή, η οποία βρίσκεται στο java.lang πακέτο. Κλωνοποιήσιμο υλοποιείται από την τάξη (μέσω του υλοποιεί λέξη-κλειδί) για την πρόληψη Αντικείμενο'μικρό κλώνος () μέθοδος από τη ρίψη μιας παρουσίας του CloneNotSupportedException τάξη (βρέθηκε επίσης στο java.lang).

CloneDemo δηλώνει ένα intμε βάση το πεδίο παρουσίας με όνομα Χ και ένα κύριος() μέθοδος που ασκεί αυτήν την τάξη. κύριος() δηλώνεται με ένα ρίχνει ρήτρα που περνά CloneNotSupportedException επάνω στη στοίβα μεθόδου-κλήσης.

κύριος() πρώτοι CloneDemo και αρχικοποιεί το αντίγραφο του στιγμιότυπου που προκύπτει Χ προς την 5. Στη συνέχεια εξάγει την παρουσία Χ αξία και κλήσεις κλώνος () σε αυτήν την περίπτωση, μεταδίδοντας το αντικείμενο που επιστράφηκε CloneDemo πριν αποθηκεύσετε την αναφορά του. Τέλος, εξάγει τον κλώνο Χ τιμή πεδίου.

Συλλογή καταχώρισης 3 (javac CloneDemo.java) και εκτελέστε την εφαρμογή (java CloneDemo). Πρέπει να παρατηρήσετε την ακόλουθη έξοδο:

cd.x = 5 cd2.x = 5

Παράκαμψη κλώνου ()

Το προηγούμενο παράδειγμα δεν χρειάστηκε να παρακάμψει κλώνος () γιατί ο κωδικός που καλεί κλώνος () βρίσκεται στην κλάση που κλωνοποιείται (CloneDemo). Εάν η κλήση προς κλώνος () βρίσκονταν σε διαφορετική τάξη, ωστόσο, τότε θα πρέπει να παρακάμψετε κλώνος (). Επειδή κλώνος () δηλώνεται προστατευμένο, θα λάβετε ένα "Το clone έχει προστατευμένη πρόσβαση στο Object"Μήνυμα εάν δεν το παρακάμψατε πριν από τη μεταγλώττιση της τάξης. Η λίστα 4 παρουσιάζει μια αναθεωρημένη καταχώριση 3 που δείχνει παράκαμψη κλώνος ().

Λίστα 4. Κλωνοποίηση ενός αντικειμένου από άλλη τάξη

class class εφαρμόζει Cloneable {int x; Το @Override public Object clone () ρίχνει το CloneNotSupportedException {return super.clone (); }} class CloneDemo {public static void main (String [] args) ρίχνει το CloneNotSupportedException {Data data = new Data (); data.x = 5; System.out.println ("data.x =" + data.x); Data data2 = (Data) data.clone (); System.out.println ("data2.x =" + data2.x); }}

Η λίστα 4 δηλώνει α Δεδομένα τάξη των οποίων οι παρουσίες πρόκειται να κλωνοποιηθούν. Δεδομένα εφαρμόζει το Κλωνοποιήσιμο διεπαφή για την αποτροπή α CloneNotSupportedException από τη ρίψη όταν το κλώνος () καλείται μέθοδος. Στη συνέχεια δηλώνει int- βασισμένο πεδίο παρουσίας Χ, και παρακάμπτει το κλώνος () μέθοδος. ο κλώνος () εκτελείται η μέθοδος super.clone () να καλέσουμε το superclass του (δηλαδή, Αντικείμενο'μικρό) κλώνος () μέθοδος. Το υπερισχύον κλώνος () μέθοδος προσδιορίζει CloneNotSupportedException μέσα στο ρίχνει ρήτρα.

Η λίστα 4 δηλώνει επίσης α CloneDemo τάξη που: δημιουργεί Δεδομένα, αρχικοποιεί το πεδίο εμφάνισης, εξάγει την τιμή του πεδίου παρουσίας, κλωνοποιεί το Δεδομένα αντικείμενο και εξάγει την τιμή πεδίου εμφάνισης.

Συλλογή καταχώρισης 4 (javac CloneDemo.java) και εκτελέστε την εφαρμογή (java CloneDemo). Πρέπει να παρατηρήσετε την ακόλουθη έξοδο:

data.x = 5 data2.x = 5

Ρηχή κλωνοποίηση

Ρηχή κλωνοποίηση (επίσης γνωστός ως ρηχή αντιγραφή) αναφέρεται στην αναπαραγωγή των πεδίων ενός αντικειμένου χωρίς την αναπαραγωγή αντικειμένων που αναφέρονται από τα πεδία αναφοράς του αντικειμένου (εάν υπάρχουν πεδία αναφοράς). Οι λίστες 3 και 4 απέδειξαν πραγματικά ρηχή κλωνοποίηση. Κάθε ένα από CD-, cd2-, δεδομένα-, και δεδομένα2-αναφερόμενα πεδία προσδιορίζει ένα αντικείμενο που έχει το δικό του αντίγραφο του int-με βάση Χ πεδίο.

Η ρηχή κλωνοποίηση λειτουργεί καλά όταν όλα τα πεδία είναι πρωτόγονου τύπου και (σε ​​πολλές περιπτώσεις) όταν αναφέρονται τα πεδία αναφοράς αμετάβλητος (αμετάβλητα) αντικείμενα. Ωστόσο, εάν οποιαδήποτε αντικείμενα που αναφέρονται είναι μεταβλητά, οι αλλαγές που γίνονται σε οποιοδήποτε από αυτά τα αντικείμενα μπορούν να φανούν από το αρχικό αντικείμενο και τον κλώνο του. Η λίστα 5 δείχνει.

Λίστα 5. Το πρόβλημα με τη ρηχή κλωνοποίηση σε ένα πεδίο αναφοράς

Ο υπάλληλος της τάξης εφαρμόζει το Cloneable {private String name; ιδιωτική ηλικία ιδιωτική διεύθυνση Διεύθυνση; Υπάλληλος (Όνομα συμβολοσειράς, int ηλικία, Διεύθυνση διεύθυνσης) {this.name = name; this.age = ηλικία; this.address = διεύθυνση; } Το @Override public Object clone () ρίχνει το CloneNotSupportedException {return super.clone (); } Διεύθυνση getAddress () {διεύθυνση επιστροφής; } String getName () {όνομα επιστροφής; } int getAge () {ηλικία επιστροφής; }} διεύθυνση τάξης {ιδιωτική πόλη String; Διεύθυνση (String city) {this.city = city; } String getCity () {επιστροφή πόλης; } void setCity (String city) {this.city = city; }} class CloneDemo {public static void main (String [] args) ρίχνει το CloneNotSupportedException {Employee e = new Employee ("John Doe", 49, νέα διεύθυνση ("Denver")); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); Υπάλληλος e2 = (Υπάλληλος) e.clone (); System.out.println (e2.getName () + ":" + e2.getAge () + ":" + e2.getAddress (). GetCity ()); e.getAddress (). setCity ("Σικάγο"); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); System.out.println (e2.getName () + ":" + e2.getAge () + ":" + e2.getAddress (). GetCity ()); }}

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

CloneDemo'μικρό κύριος() η μέθοδος δημιουργεί ένα Υπάλληλος αντικείμενο και κλωνοποιεί αυτό το αντικείμενο. Στη συνέχεια αλλάζει το όνομα της πόλης στο πρωτότυπο Υπάλληλος αντικείμενο διεύθυνση πεδίο. Επειδή και τα δύο Υπάλληλος τα αντικείμενα αναφέρονται στο ίδιο Διεύθυνση αντικείμενο, η αλλαγμένη πόλη φαίνεται και από τα δύο αντικείμενα.

Συλλογή καταχώρισης 5 (javac CloneDemo.java) και εκτελέστε αυτήν την εφαρμογή (java CloneDemo). Πρέπει να παρατηρήσετε την ακόλουθη έξοδο:

John Doe: 49: Denver John Doe: 49: Denver John Doe: 49: Chicago John Doe: 49: Σικάγο

Βαθιά κλωνοποίηση

Βαθιά κλωνοποίηση (επίσης γνωστός ως βαθιά αντιγραφή) αναφέρεται στην αναπαραγωγή πεδίων ενός αντικειμένου έτσι ώστε να αντιγράφονται τυχόν αντικείμενα που αναφέρονται. Επιπλέον, τα αντικείμενα αναφοράς των αντικειμένων που αναφέρονται αναφέρονται διπλά και ούτω καθεξής. Λίστα 6 αντιδραστήρων Λίστα 5 για επίδειξη βαθιάς κλωνοποίησης.

Λίστα 6. Βαθιά κλωνοποίηση του πεδίου διεύθυνσης

Ο υπάλληλος της τάξης εφαρμόζει το Cloneable {private String name; ιδιωτική ηλικία ιδιωτική διεύθυνση Διεύθυνση; Υπάλληλος (Όνομα συμβολοσειράς, int ηλικία, Διεύθυνση διεύθυνσης) {this.name = name; this.age = ηλικία; this.address = διεύθυνση; } @Override public Object clone () ρίχνει CloneNotSupportedException {Employee e = (Employee) super.clone (); e.address = (Διεύθυνση) address.clone (); επιστροφή e; } Διεύθυνση getAddress () {διεύθυνση επιστροφής; } String getName () {όνομα επιστροφής; } int getAge () {ηλικία επιστροφής; }} διεύθυνση τάξης {ιδιωτική πόλη String; Διεύθυνση (String city) {this.city = city; } @Override public Object clone () {return new Address (new String (city)); } String getCity () {επιστροφή πόλης; } void setCity (String city) {this.city = city; }} class CloneDemo {public static void main (String [] args) ρίχνει το CloneNotSupportedException {Employee e = new Employee ("John Doe", 49, νέα διεύθυνση ("Denver")); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); Υπάλληλος e2 = (Υπάλληλος) e.clone (); System.out.println (e2.getName () + ":" + e2.getAge () + ":" + e2.getAddress (). GetCity ()); e.getAddress (). setCity ("Σικάγο"); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); System.out.println (e2.getName () + ":" + e2.getAge () + ":" + e2.getAddress (). GetCity ()); }}

Η λίστα 6 δείχνει ότι Υπάλληλος'μικρό κλώνος () μέθοδος πρώτων κλήσεων super.clone (), το οποίο αντιγράφει ρηχά το όνομα, ηλικία, και διεύθυνση πεδία. Στη συνέχεια καλεί κλώνος () στο διεύθυνση πεδίο για να δημιουργήσετε ένα αντίγραφο του αναφερόμενου Διεύθυνση αντικείμενο. Διεύθυνση παρακάμπτει το κλώνος () μέθοδος και αποκαλύπτει μερικές διαφορές από προηγούμενες τάξεις που παρακάμπτουν αυτήν τη μέθοδο:

  • Διεύθυνση δεν εφαρμόζει Κλωνοποιήσιμο. Δεν είναι απαραίτητο γιατί μόνο Αντικείμενο'μικρό κλώνος () μέθοδος απαιτεί μια κλάση να εφαρμόσει αυτήν τη διεπαφή, και αυτό κλώνος () δεν καλείται μέθοδος.
  • Το υπερισχύον κλώνος () η μέθοδος δεν ρίχνει CloneNotSupportedException. Αυτή η εξαίρεση απορρίπτεται μόνο από Αντικείμενο'μικρό κλώνος () μέθοδος, η οποία δεν καλείται. Επομένως, η εξαίρεση δεν χρειάζεται να χειριστεί ή να μεταβιβάσει τη στοίβα κλήσης μεθόδου μέσω ενός όρου ρίψης.
  • Αντικείμενο'μικρό κλώνος () η μέθοδος δεν καλείται (δεν υπάρχει super.clone () κλήση) επειδή δεν απαιτείται ρηχή αντιγραφή για το Διεύθυνση τάξη - υπάρχει μόνο ένα πεδίο για αντιγραφή.