User Tools

Site Tools


java:inheritance

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
java:inheritance [2016/02/12 15:47]
gthanos [Προσβασιμότητα των κληρονομούμενων πεδίων]
java:inheritance [2022/03/11 05:21] (current)
gthanos
Line 1: Line 1:
 ====== Κληρονομικότητα ====== ====== Κληρονομικότητα ======
  
-Βασικό χαρακτηριστικό του αντικειμενοστραφούς προγραμματισμού είναι η δυνατότητα να παράγουμε νέες κλάσεις με βάση υφιστάμενες κλάσεις, εξειδικεύοντας και επεκτείνοντας τα χαρακτηριστικά των υφιστάμενων. Η διαδικασία επέκτασης των υφιστάμενων κλάσεων σε νέες ειδικότερες κλάσεις ονομάζεται κληρονομικότητα.+Βασικό χαρακτηριστικό του αντικειμενοστραφούς προγραμματισμού είναι η δυνατότητα να παράγουμε νέες κλάσεις με βάση υφιστάμενες, εξειδικεύοντας και επεκτείνοντας τα χαρακτηριστικά τους. Η διαδικασία επέκτασης των υφιστάμενων κλάσεων σε νέες ειδικότερες κλάσεις ονομάζεται κληρονομικότητα.
  
 Κάθε κλάση που κληρονομεί από μία άλλη κλάση ονομάζεται υποκλάση (//subclass//) της γονικής κλάσης από την οποία κληρονομεί. Αντίστοιχα, η γονική κλάση ονομάζεται υπερκλάση (//superclass//) της κληρονομούμενης κλάσης. Κάθε κλάση που κληρονομεί από μία άλλη κλάση ονομάζεται υποκλάση (//subclass//) της γονικής κλάσης από την οποία κληρονομεί. Αντίστοιχα, η γονική κλάση ονομάζεται υπερκλάση (//superclass//) της κληρονομούμενης κλάσης.
  
-{{  :java:super_sub_class.jpg  | }}+{{  :java:inheritance-1.png  | }}
  
-Όπως φαίνεται και στο παραπάνω σχήμα μία κλάση (//subclass//) μπορεί να κληρονομεί __**ΜΟΝΟ ΜΙΑ**__ άλλη κλάση. Αντίστροφα μία κλάση (//superclass//) μπορεί να κληρονομείται από πολλές διαφορετικές κλάσεις. Παρακάτω δίνουμε ένα παράδειγμα κληρονομικότητας από το site της [[https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html|Oracle]], όπου η κλάση ''MountainBike'' αποτελεί εξειδίκευση της κλάσης ''Bicycle''.+Όπως φαίνεται και στο παραπάνω σχήμα μία κλάση (//subclass//) μπορεί να κληρονομεί __**ΜΟΝΟ ΜΙΑ**__ άλλη κλάση. Αντίστροφα μία κλάση (//superclass//) μπορεί να κληρονομείται από πολλές διαφορετικές κλάσεις. Παρακάτω δίνουμε ένα παράδειγμα κληρονομικότητας ως συνέχεια των προηγούμενων ενοτήτων. Ορίζουμε την κλάση ''BasicRectangle'' η οποία αποτελεί το απλό ορθογώνιο παραλληλόγραμμο που γνωρίσαμε στην αρχή και την κλάση ''Rectangle'' που αποτελεί εξειδίκευση της κλάσης ''BasicRectangle'' ορίζοντας επιπλέον το πεδίο ''origin''.
  
-<code java Bicycle.java> +<code java BasicRectangle.java> 
-public class Bicycle { +public class BasicRectangle {
-         +
-    private int cadence; +
-    private int gear; +
-    private int speed; +
-        +
-    public Bicycle(int startCadence, int startSpeed, int startGear) { +
-        gear = startGear; +
-        cadence = startCadence; +
-        speed = startSpeed; +
-    }+
          
-    public int getCadence() { +  int width; 
-          return cadence+  int height; 
-    }+  
 +  public BasicRectangle(int initWidth, int initHeight) { 
 +    width = initWidth
 +    height = initHeight; 
 +  } 
 + 
 +  public void setWidth(int newWidth ) { 
 +    width = newWidth; 
 +  }
          
-    public int getGear() { +  public void setHeight(int newHeight ) { 
-          return gear+    height = newHeight; 
-    }+  } 
 +   
 +  public int getWidth() { 
 +    return width
 +  }
          
-    public int getSpeed() { +  public int getHeight() { 
-          return speed+    return height; 
-    }+  } 
 +   
 +  public String toString() { 
 +    return "width: "+width+", height: "+height; 
 +  } 
 +
 +</code>
  
-    public void setCadence(int newValue) { +<code java Point.java> 
-        cadence newValue+class Point { 
-    } +  int x;   // x coordinate 
-         +  int y;   // y coordinate 
-    public void setGear(int newValue) { +   
-        gear newValue+  public Point(int xPos, int yPos) { 
-    +    xPos
-         +    y = yPos; 
-    public void applyBrake(int decrement) { +  
-        speed -decrement+   
-    +  int getX() { 
-         +    return x; 
-    public void speedUp(int increment) { +  } 
-        speed += increment+   
-    } +  void setX(int xPos) { 
-        +    xPos
 +  
 +   
 +  int getY() { 
 +    return y; 
 +  } 
 +   
 +  void setY(int yPos) { 
 +    yPos
 +  
 +   
 +  public String toString() { 
 +    return "("+x+","+y+")"
 +  }
 } }
 </code> </code>
  
-<code java MountainBike.java> +<code java Rectangle.java> 
-public class MountainBike extends Bicycle +public class Rectangle extends BasicRectangle 
- +     
-    private int seatHeight; +  Point origin
- +     
-    // the MountainBike subclass has +  public Rectangle(int initWidth, int initHeightPoint initOrigin) { 
-    // one constructor +    super(initWidthinitHeight); 
-    public MountainBike(int startHeight, int startCadence, +    origin initOrigin
-                        int startSpeed, int startGear) { +  
-        super(startCadencestartSpeed, startGear); +   
-        seatHeight startHeight+  public Rectangle(int initWidth, int initHeight, int originX, int originY) { 
-       +    super(initWidth, initHeight)
-         +    origin = new Point(originX,originY); 
-    // the MountainBike subclass has +  }
-    // one method +
-    public void setHeight(int newValue) { +
-        seatHeight = newValue+
-    }+
          
-    public int getSeatHeight() { +  public void setOrigin(Point newOrigin) { 
-        return seatHeight+    origin = newOrigin; 
-    }+  } 
 +   
 +  public Point getOrigin() { 
 +    return origin; 
 +  } 
 +   
 +  int area() { 
 +    return width * height; 
 +  } 
 +    
 +  // Move rectangle origin by dx,dy 
 +  public void moveOrigin(int dx, int dy) { 
 +    origin.setX( origin.getX() + dx ); 
 +    origin.setY( origin.getY() + dy ); 
 +  } 
 +   
 +  public String toString() { 
 +    String str = origin.toString() + " "; 
 +    str = str + super.toString(); 
 +    return str; 
 +  }
 } }
 </code> </code>
  
 +<WRAP tip 80% center round>
 +
 +=== Παρατηρήσεις ===
 +
 +  * Η κλάση //BasicRectangle// έχει τα πεδία //width, height//, ενώ η κλάση //Rectangle// διαθέτει τα πεδία αυτά και επιπλέον το πεδίο //origin//.
 +  * Βασικό χαρακτηριστικό της κληρονομικότητας είναι ότι η κληρονομούμενη κλάση έχει όλα τα  χαρακτηριστικά της γονικής κλάσης. Υπό αυτή την έννοια, τα αντικείμενα της κλάσης //Rectangle// είναι και του τύπου //BasicRectangle//.
 +  * Παρατηρήστε τη δεσμευμένη λέξη //super// ως πρώτη εντολή του κάθε κατασκευαστή. Μέσω της κλήσης //super// καλείται ο κατασκευαστής της γονικής κλάσης.
 +</WRAP>
 ===== Προσβασιμότητα των κληρονομούμενων πεδίων ===== ===== Προσβασιμότητα των κληρονομούμενων πεδίων =====
  
Line 83: Line 128:
  
   * Έχει πρόσβαση στα //**public**// και //**protected**// μέλη της γονικής κλάσης   * Έχει πρόσβαση στα //**public**// και //**protected**// μέλη της γονικής κλάσης
-  * Έχει πρόσβαση στα //package private// μέλη (δηλ. τα μέλη χωρίς προσδιοριστή πρόσβασης) μόνο αν βρίσκεται στο ίδιο πακέτο με την γονική κλάση. +  * Έχει πρόσβαση στα //**package private**// μέλη (δηλ. τα μέλη χωρίς προσδιοριστή πρόσβασης) μόνο αν βρίσκεται στο ίδιο πακέτο με την γονική κλάση. 
-  * Δεν έχει πρόσβαση στα //private// μέλη της κλάσης. +  * Δεν έχει πρόσβαση στα //**private**// μέλη της κλάσης. 
  
-Αν υπάρχουν //public// μέθοδοι οι οποίες επιτρέπουν την πρόσβαση σε //private// πεδία, τότε αυτές μπορούν να χρησιμοποιηθούν για τον ορισμό ή για την λήψη της τιμής τους.+Αν υπάρχουν //**public**// μέθοδοι οι οποίες επιτρέπουν την πρόσβαση σε //**private**// πεδία, τότε αυτές μπορούν να χρησιμοποιηθούν για τον ορισμό ή για την λήψη της τιμής τους.
  
 ===== Τι μπορούμε να κάνουμε σε μία υποκλάση... ===== ===== Τι μπορούμε να κάνουμε σε μία υποκλάση... =====
Line 92: Line 137:
   * Να χρησιμοποιήσουμε τα πεδία της γονικής κλάσης στα οποία έχουμε πρόσβαση (public, protected, package-private στο ίδιο package).   * Να χρησιμοποιήσουμε τα πεδία της γονικής κλάσης στα οποία έχουμε πρόσβαση (public, protected, package-private στο ίδιο package).
   * Να ορίσουμε νέα πεδία.   * Να ορίσουμε νέα πεδία.
-  * Να ορίσουμε νέα πεδία που να έχουν ίδιο όνομα με πεδία της γονικής κλάσης. Σε αυτή την περίπτωση "κρύβουμε" τα πεδία της γονικής κλάσης. Η συγκεκριμένη πρακτική δεν συνίσταται και παραπέμπει σε λανθασμένη σχεδίαση κώδικα. 
   * Να χρησιμοποιήσουμε τις μεθόδους της γονικής κλάσης στις οποίες έχουμε πρόσβαση (public, protected, package-private στο ίδιο package).   * Να χρησιμοποιήσουμε τις μεθόδους της γονικής κλάσης στις οποίες έχουμε πρόσβαση (public, protected, package-private στο ίδιο package).
   * Μπορούμε να γράψουμε νέες στατικές ή μη στατικές μεθόδους για τη υποκλάση.   * Μπορούμε να γράψουμε νέες στατικές ή μη στατικές μεθόδους για τη υποκλάση.
Line 99: Line 143:
   * Μπορούμε να γράψουμε κατασκευαστές της υποκλάσης που χρησιμοποιούν κατασκευαστές της γονικής κλάσης.   * Μπορούμε να γράψουμε κατασκευαστές της υποκλάσης που χρησιμοποιούν κατασκευαστές της γονικής κλάσης.
  
-===== Implicit και Explicit Casting of Objects ===== +===== ΔΕΝ συνιστάται να κάνουμε σε μία υποκλάση... ===== 
- +  * Να ορίσουμε νέα πεδία που να έχουν ίδιο όνομα με πεδία της γονικής κλάσης. Σε αυτή την περίπτωση "κρύβουμετα πεδία της γονικής κλάσης. Η συγκεκριμένη πρακτική δεν συνίσταται και παραπέμπει σε λανθασμένη σχεδίαση κώδικα.
-Σε συνέχεια του προηγούμενου παραδείγματος κληρονομικότητας μπορούμε να γράψουμε +
- +
-<code java> +
-MountainBike myBike = new MountainBike(); +
-</code> +
- +
-Από την παραπάνω δήλωση η μεταβλητή ''myBike'' είναι τύπου ''MountainBike''. Επειδή όμως ο τύπος ''MountainBike'' κληρονομεί από την μεταβλητή ''Bicycle'' η συγκεκριμένη μεταβλητή είναι και τύπου BicycleΕπομένως θα μπορούσαμε να γράψουμε +
- +
-<code java> +
-Bicycle myBicycle myBike; +
-   //ή +
-Βicycle yourBicycle new MountainBike(); +
-</code> +
- +
-Την παραπάνω ανάθεση την ονομάζουμε //Implicit Casting// διότι αναθέτουμε μία μεταβλητή ενός τύπου δεδομένων (''myBike'') σε μία μεταβλητή γονικού τύπου δεδομένων (''myBicycle''), χωρίς type casting. +
- +
-Ας δοκιμάσουμε το ανάποδο παράδειγμα τώρα +
- +
-<code java> +
-Bycycle myBicycle = new Bicycle(); +
-MountainBike myBike = myBicycle; +
-</code> +
- +
-Σε αυτή την περίπτωση ο compiler διαμαρτύρεται, διότι η μεταβλητή ''myBicycle'' είναι τύπου ''Bicycle'' και δεν είναι απαραίτητο ότι είναι και τύπου ''MountainBike''. Αν θέλουμε να ξεπεράσουμε το παραπάνω πρόβλημα θα πρέπει να γράψουμε το εξής+
- +
-<code java> +
-Bycycle myBicycle = new Bicycle(); +
-MountainBike myBike = (MountainBike) myBicycle; +
-</code> +
- +
-Εδώ ενημερώνουμε τον compiler ότι η μεταβλητή ''myBicycle'' είναι και τύπου ''MountainBike'', λαμβάνοντας ο προγραμματιστής την ευθύνη ότι κάτι τέτοιο ισχύειΕάν δεν ισχύει κάτι τέτοιο κατά την εκτέλεση του προγράμματος θα παραχθεί μία εξαίρεση (exception)*. Θα δούμε πιο κάτω τι είναι και πως διαχειριζόμαστε τις εξαιρέσεις. +
- +
-Ένας πιο ασφαλής τρόπος για να επαναλάβουμε τον παραπάνω κώδικα, χωρίς να παραχθεί εξαίρεση είναι ο εξής: +
- +
-<code java> +
-Bycycle myBicycle = new Bicycle(); +
-MountainBike myBike; +
-if (myBicycle instanceof MountainBike) { +
-    myBike = (MountainBike)myBicycle; +
-+
-</code> +
- +
-===== Final Κλάσεις και Μέθοδοι ===== +
- +
-Μπορείτε να δηλώσετε μία ή περισσότερες μεθόδους μία κλάσης ως //final//. Δηλώνοντας μία μέθοδο ως final η μέθοδος αυτή δεν μπορεί να επαναοριστεί σε μία υποκλάση της κλάσης αυτής. Ο συχνότερος λόγος για να δηλώσετε μία μέθοδο ως //final// είναι αν η υλοποίηση της μεθόδου δεν πρέπει να αλλάξει. Ένα παράδειγμα είναι το παρακάτω: +
- +
-<code java> +
-class ChessAlgorithm { +
-    enum ChessPlayer { WHITE, BLACK } +
-    ... +
-    final ChessPlayer getFirstPlayer() { +
-        return ChessPlayer.WHITE; +
-    } +
-    ... +
-+
-</code> +
- +
-Γενικότερα, μέθοδοι που καλούνται από τους κατασκευαστές της κλάσης __θα πρέπει__ να ορίζονται ως //final// καθώς αν αλλάζουν την υλοποίηση τους σε υποκλάσεις μπορούν να δημιουργηθούν προβλήματα ως προς την ορθή αρχικοποίηση των μεταβλητών της κλάσης. +
- +
-Τέλος, μπορείτε να προσδιορίσετε μία κλάση ως //final//, όταν θέλετε να δηλώσετε ότι η συγκεκριμένη κλάση δεν πρέπει να έχει υποκλάσεις. Ένα παράδειγμα τέτοια κλάσης είναι η κλάση [[http://docs.oracle.com/javase/7/docs/api/java/lang/String.html | String]] της standard βιβλιοθήκης της Java.+
  
-|Προηγούμενο: [[ :java:interfaces Διεπαφές ]] | Επόμενο: [[ :java:multiple_inheritance Κληρονομικότητα πολλαπλών γονικών κλάσεων ]]|+|Προηγούμενο: [[ :java:access_modifiers Περιοριστές Πρόσβασης ]] | Επόμενο: [[ :java:type_casting Ρητές (explicit) και άρρητες (implicit) μετατροπές τύπων ]]|
  
java/inheritance.1455292032.txt.gz · Last modified: 2016/02/12 15:47 by gthanos