This is an old revision of the document!
Table of Contents
Κληρονομικότητα
Βασικό χαρακτηριστικό του αντικειμενοστραφούς προγραμματισμού είναι η δυνατότητα να παράγουμε νέες κλάσεις με βάση υφιστάμενες, εξειδικεύοντας και επεκτείνοντας τα χαρακτηριστικά τους. Η διαδικασία επέκτασης των υφιστάμενων κλάσεων σε νέες ειδικότερες κλάσεις ονομάζεται κληρονομικότητα.
Κάθε κλάση που κληρονομεί από μία άλλη κλάση ονομάζεται υποκλάση (subclass) της γονικής κλάσης από την οποία κληρονομεί. Αντίστοιχα, η γονική κλάση ονομάζεται υπερκλάση (superclass) της κληρονομούμενης κλάσης.
Όπως φαίνεται και στο παραπάνω σχήμα μία κλάση (subclass) μπορεί να κληρονομεί ΜΟΝΟ ΜΙΑ άλλη κλάση. Αντίστροφα μία κλάση (superclass) μπορεί να κληρονομείται από πολλές διαφορετικές κλάσεις. Παρακάτω δίνουμε ένα παράδειγμα κληρονομικότητας ως συνέχεια των προηγούμενων ενοτήτων. Ορίζουμε την κλάση BasicRectangle
η οποία αποτελεί το απλό ορθογώνιο παραλληλόγραμμο που γνωρίσαμε στην αρχή και την κλάση Rectangle
που αποτελεί εξειδίκευση της κλάσης BasicRectangle
ορίζοντας επιπλέον το πεδίο origin
.
- BasicRectangle.java
class BasicRectangle { int width; int height; public Rectangle(int initWidth, int initHeight) { width = initWidth; height = initHeight; } void setWidth(int newWidth ) { width = newWidth; } void setHeight(int newHeight ) { height = newHeight; } int getWidth() { return width; } int getHeight() { return height; } int area() { return width * height; } }
- Point.java
class Point { int x; // x coordinate int y; // y coordinate public Point(int xPos, int yPos) { x = xPos; y = yPos; } int getX() { return x; } void setX(int xPos) { x = xPos; } int getY() { return y; } void setY(int yPos) { y = yPos; } }
- Rectangle.java
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); } void setOrigin(Point newOrigin) { origin = newOrigin; } Point getOrigin() { return origin; } // Move rectangle origin by dx,dy void moveOrigin(int dx, int dy) { origin.setX( origin.getX() + dx ); origin.setY( origin.getY() + dy ); } }
Παρατηρήσεις
- Η κλάση Bicycle έχει τα τρία πεδία frameSize, gearsNumber και color ενώ η κλάση MountainBike διαθέτει τα πεδία αυτά και επιπλέον το πεδίο suspension.
- Τα πεδία της κλάσης Bicycle είναι private. H πρόσβαση στα πεδία αυτά μπορεί να γίνει μόνο μέσω των public μεθόδων που διαθέτει η κλάση και έχοντας πρόσβαση απευθείας πάνω στα συγκεκριμένα πεδία.
- Βασικό χαρακτηριστικό της κληρονομικότητας είναι ότι η κληρονομούμενη κλάση έχει όλα τα protected, package private (αν οι δύο κλάσεις βρίσκονται στο ίδιο πακέτο) και public χαρακτηριστικά της γονικής κλάσης. Μπορεί να πει κανείς ότι η κλάση MountainBike είναι και Bicycle.
Προσβασιμότητα των κληρονομούμενων πεδίων
Μία κλάση η οποία κληρονομεί μία άλλη κλάση έχει πρόσβαση στα μέλη (πεδία και μεθόδους) της κλάσης αυτής ως εξής:
- Έχει πρόσβαση στα public και protected μέλη της γονικής κλάσης
- Έχει πρόσβαση στα package private μέλη (δηλ. τα μέλη χωρίς προσδιοριστή πρόσβασης) μόνο αν βρίσκεται στο ίδιο πακέτο με την γονική κλάση.
- Δεν έχει πρόσβαση στα private μέλη της κλάσης.
Αν υπάρχουν public μέθοδοι οι οποίες επιτρέπουν την πρόσβαση σε private πεδία, τότε αυτές μπορούν να χρησιμοποιηθούν για τον ορισμό ή για την λήψη της τιμής τους.
Τι μπορούμε να κάνουμε σε μία υποκλάση...
- Να χρησιμοποιήσουμε τα πεδία της γονικής κλάσης στα οποία έχουμε πρόσβαση (public, protected, package-private στο ίδιο package).
- Να ορίσουμε νέα πεδία.
- Να χρησιμοποιήσουμε τις μεθόδους της γονικής κλάσης στις οποίες έχουμε πρόσβαση (public, protected, package-private στο ίδιο package).
- Μπορούμε να γράψουμε νέες στατικές ή μη στατικές μεθόδους για τη υποκλάση.
- Μπορούμε να γράψουμε νέες μεθόδους που έχουν το ίδιο signature (ίδιο όνομα, ίδιο αριθμό και ίδιο τύπο ορισμάτων), ώστε να επαναορίσουμε (override) τις μεθόδους αυτές στην υποκλάση. Η πρακτική αυτή είναι συνήθης.
- Μπορούμε να γράψουμε νέες στατικές (static) μεθόδους που έχουν το ίδιο signature, ώστε να επαναορίσουμε (override) τις μεθόδους αυτές στην υποκλάση. Επαναορίζοντας στατικές μεθόδους, κρύβουμε τις αντίστοιχες μεθόδους της γονικής κλάσης.
- Μπορούμε να γράψουμε κατασκευαστές της υποκλάσης που χρησιμοποιούν κατασκευαστές της γονικής κλάσης.
ΔΕΝ συνιστάται να κάνουμε σε μία υποκλάση...
- Να ορίσουμε νέα πεδία που να έχουν ίδιο όνομα με πεδία της γονικής κλάσης. Σε αυτή την περίπτωση “κρύβουμε” τα πεδία της γονικής κλάσης. Η συγκεκριμένη πρακτική δεν συνίσταται και παραπέμπει σε λανθασμένη σχεδίαση κώδικα.
Προηγούμενο: Περιοριστές Πρόσβασης | Επόμενο: Ρητές (explicit) και άρρητες (implicit) μετατροπές τύπων |