Σε προηγούμενη παράγραφο είδαμε την χρήση του τελεστή this. Σε αναλογία με τον τελεστή this, ο τελεστής super δείχνει στο αντικείμενο της γονικής κλάσης.
Επαναλαμβάνοντας τον βασικό κώδικα από το προηγούμενο παράδειγμα του παραλληλογράμμου έχουμε:
class BasicRectangle { int width; int height; public Rectangle(int initWidth, int initHeight) { width = initWidth; height = initHeight; } }
Η κλάση Rectangle περιέχει ένα πεδίο τύπου Point. Την κλάση Point μπορείτε να την βρείτε εδώ.
class Rectangle extends BasicRectangle{ Point origin; public Rectangle(int initWidth, int initHeight, Point initOrigin) { super(initWidth, initHeight); origin = initOrigin; } public Rectangle(int initWidth, int initHeight, int originX, int originY) { super(initWidth, initHeight); origin = new Point(originX,originY); } }
Ο τελεστής super χρησιμοποιείται στην υποκλάση για να προσπελάσει τον κατασκευαστή της γονικής κλάσης και να αρχικοποιήσει με αυτό τον τρόπο τις μεταβλητές που ανήκουν στο γονικό κομμάτι της κλάσης.
Η κλήση του γονικού κατασκευαστή με χρήση της λέξης super πρέπει να βρίσκεται ως πρώτη εντολή στο σώμα κάθε κατασκευαστή.
Στις περιπτώσεις που μία κλάση είναι απόγονος άλλης κλάσης η διαδικασία αρχικοποίησης έχει ως εξής. Αρχικά αρχικοποιείται το τμήμα της κλάσης που αφορά την γονική κλάση καλώντας τον κατασκευαστή αυτής μέσω του τελεστή super και στη συνέχεια αρχικοποιείται η απόγονος κλάση. Εάν κατά την κλήση super η γονική κλάση έχει με τη σειρά της μία άλλη πρόγονο κλάση, οφείλει να καλέσει τον κατασκευαστή αυτής. Η διαδικασία επαναλαμβάνεται μέχρι να κληθεί ο κατασκευαστής της κλάσης java.lang.Object.
Εάν δεν υπάρχει κλήση του κατασκευαστή της γονικής κλάσης μέσω του τελεστή super στον κατασκευαστή της απογόνου κλάσης, τότε ο compiler αναζητά εάν υπάρχει ο default κατασκευαστής για την γονική κλάση (δηλ. κατασκευαστής χωρίς ορίσματα) και καλεί αυτόματα αυτόν. Εάν δεν υπάρχει ούτε default κατασκευαστής εμφανίζει μήνυμα λάθους.
Δείτε το παρακάτω παράδειγμα κώδικα που συμπυκνώνει τη διαδικασία αρχικοποίησης. Ακολουθήστε τα εξής βήματα:
Παρατηρήστε ότι στις περιπτώσεις 2 και 3 ο κώδικας μεταγλωττίζεται. Εκτελέστε και δείτε τα μηνύματα που εκτυπώνονται.
class Animal { private String name; private int age; public Animal(String name, int age) { this.name = name; this.age = age; System. out.println("Animal constructor with args."); } //public Animal() { System. out.println("Default Animal constructor."); } // line 11 } class Cat extends Animal { public Cat() { /*super("",0);*/ } // line 15 } public class ObjectInitializationSequence { public static void main(String []args) { new Cat(); } }
Ξαναγράφουμε τις κλάσεις BasicRectangle
και Rectangle
, προσθέτοντας αυτή τη φορά τον ορισμό της μεθόδου public String toString()
και στις δύο. Η μέθοδος αυτή, όπως έχουμε δει, είναι υπαρκτή σε όλα τα αντικείμενα διότι περιέχεται στην κλάση java.lang.Object.
class BasicRectangle { int width; int height; public BasicRectangle(int initWidth, int initHeight) { width = initWidth; height = initHeight; } public String toString() { return "width: "+width+", height: "+height; } }
class Rectangle extends BasicRectangle{ Point origin; public Rectangle(int initWidth, int initHeight, Point initOrigin) { super(initWidth, initHeight); origin = initOrigin; } public Rectangle(int initWidth, int initHeight, int originX, int originY) { super(initWidth, initHeight); origin = new Point(originX,originY); } public String toString() { return origin.toString() + " " + super.toString(); } public int area() { return width*height; } }
Παρατηρήστε ότι η μέθοδος toString για την κλάση Rectangle χρησιμοποιεί τη μέθοδο toString της κλάσης Point
και της γονικής της κλάσης BasicRectangle
(βλέπε super.toString()
). Ο λόγος που σε αυτό το σημείο είναι απαραίτητη η χρήση του τελεστή super, είναι ότι εάν δεν βάλουμε τη λέξη super. κατά την κλήση της toString(), η συνάρτηση δεν θα καλέσει τη συνάρτηση toString της γονικής κλάσης, αλλά τον εαυτό της. Σε αυτή την περίπτωση, η αναδρομική κλήση είναι ατέρμονη, μοιραία θα οδηγήσει σε υπέρβαση της διαθέσιμης στοίβας εκτέλεσης του προγράμματος, με συνέπεια τον τερματισμό του.
Επιπλέον, στην κλάση Rectangle, ορίσαμε παραπάνω τη μέθοδο area. H μέθοδος μπορεί να γραφεί με τις εξής τρεις (3) ισοδύναμες παραλλαγές.
public int area() { return width * height; }
public int area() { return this.width * this.height; }
public int area() { return super.width * super.height; }
Ο λόγος που μπορούμε να γράψουμε τη συνάρτηση με τους δύο παραπάνω τρόπους είναι ότι το πεδίο width, που κληρονομείται από τη γονική κλάση, ανήκει τόσο στην τρέχουσα κλάση Rectangle
, όσο και στη γονική της BasicRectangle
.
Συμπερασματικά, ο τελεστής super δείχνει στο τμήμα του τρέχοντος αντικειμένου που αφορά τη γονική κλάση και χρησιμοποιείται για να προσπελαστούν πεδία ή μέθοδοι που ανήκουν σε αυτό.
Απαραίτητη προϋπόθεση για την πρόσβαση στα πεδία της γονικής κλάσης μέσω του τελεστη super είναι η κλάση να έχει πρόσβαση στα δεδομένα ή τις μεθόδους της γονικής κλάσης τις οποίες καλείται να προσπελάσει. Για να γίνει αυτό, τα πεδία και οι μέθοδοι της γονικής κλάσης που θέλουμε να προσπελάσουμε ΔΕΝ θα πρέπει α) να έχουν προσδιοριστή πρόσβασης private ή β) δεν θα πρέπει να έχουν προσδιοριστή package private (δηλ. κανένα προσδιοριστή) και να ανήκουν σε διαφορετικά πακέτα.
Προηγούμενο: Κληρονομικότητα πολλαπλών γονικών κλάσεων | Περιεχόμενα | Επόμενο: Η κλάση Object |