java:type_casting

This is an old revision of the document!


Ρητές (explicit) και άρρητες (implicit) μετατροπές τύπων

Σε συνέχεια του παραδείγματος κληρονομικότητας της προηγούμενης ενότητας μπορούμε να γράψουμε

MountainBike myBike = new MountainBike();

Από την παραπάνω δήλωση η μεταβλητή myBike είναι τύπου MountainBike. Επειδή όμως ο τύπος MountainBike κληρονομεί από την μεταβλητή Bicycle η συγκεκριμένη μεταβλητή είναι και τύπου Bicycle. Επομένως, θα μπορούσαμε να γράψουμε

Bicycle myBicycle = myBike;
   //ή
Βicycle yourBicycle = new MountainBike();

Την παραπάνω ανάθεση την ονομάζουμε άρρητη μετατροπή (implicit casting) διότι αναθέτουμε μία μεταβλητή ενός τύπου δεδομένων (myBike) σε μία μεταβλητή γονικού τύπου δεδομένων (myBicycle), χωρίς να ορίζουμε μία μετατροπή τύπου (type cast).

Ας δοκιμάσουμε το ανάποδο παράδειγμα τώρα

Bycycle myBicycle = new Bicycle();
MountainBike myBike = myBicycle;

Σε αυτή την περίπτωση ο compiler διαμαρτύρεται, διότι η μεταβλητή myBicycle είναι τύπου Bicycle και δεν είναι απαραίτητο ότι είναι και τύπου MountainBike. Αν θέλουμε να ξεπεράσουμε το παραπάνω μήνυμα λάθους του compiler θα πρέπει να γράψουμε το εξής:

Bycycle myBicycle = new Bicycle();
MountainBike myBike = (MountainBike) myBicycle;

Εδώ ενημερώνουμε τον compiler ότι η μεταβλητή myBicycle είναι και τύπου MountainBike, λαμβάνοντας ο προγραμματιστής την ευθύνη ότι αυτό ισχύει. Εάν δεν ισχύει, κατά την εκτέλεση του προγράμματος θα παραχθεί μία εξαίρεση (exception)*. Θα δούμε πιο κάτω τι είναι και πως διαχειριζόμαστε τις εξαιρέσεις.

Ένας πιο ασφαλής τρόπος για να επαναλάβουμε τον παραπάνω κώδικα, χωρίς να παραχθεί εξαίρεση είναι ο εξής:

Bycycle myBicycle = new Bicycle();
MountainBike myBike;
if (myBicycle instanceof MountainBike) {
    myBike = (MountainBike)myBicycle;
}

Κριτήρια χρήσης της κληρονομικότητας ως εργαλείο ανάπτυξης λογισμικού

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

Πριν ξεκινήσουμε την υλοποίηση θα πρέπει να αποφασίσουμε εάν θέλουμε να δημιουργήσουμε το κυβοειδές χρησιμοποιώντας ως μεταβλητή της νέας κλάσης ένα αντικείμενο της κλάσης Rectangle ή επιθυμούμε να επεκτείνουμε την κλάση Rectangle μέσω της νέας κλάσης. Δείτε παρακάτω τις δύο παραλλαγές της κλάσης Cuboid με και χωρίς κληρονομικότητα.

Cuboid.java
public class Cuboid {
  Rectangle rec;
  int length;
 
  public Cuboid(int l, int w, int h) {
    rec = new Rectangle(w,h);
    length = l;
  }
 
  public int getLength() { return length; }
  public void setLength(int l) { length = l; }
 
  public int volume() { return length * rec.area(); }
}

ή

Cuboid.java
public class Cuboid extends Rectangle {
  int length;
 
  public Cuboid(int l, int w, int h) {
    super(w,h);
    length = l;
  }
 
  public int getLength() { return length; }
  public void setLength(int l) { length = l; }
 
  public int volume() { return length * area(); }
}

Και οι δύο κλάσεις μεταγλωττίζονται και λειτουργικά παράγουν το ίδιο αποτέλεσμα. Το ερώτημα είναι ποια από τις δύο μεθόδους θα προτιμήσουμε. Η απάντηση είναι απλή και συνίσταται στο εξής: Εάν ο νέος τύπος δεδομένων που προκύπτει είναι της ίδιας κατηγορίας με τον τύπο δεδομένων της αρχικής κλάσης τότε μπορούμε να χρησιμοποιήσουμε κληρονομικότητα. Εάν όμως ο νέος τύπος δεδομένων δεν είναι της ίδιας κατηγορίας με τον προηγούμενο τότε η 1η επιλογή είναι η βελτιστη.

Για παράδειγμα, στο αρχικό παράδειγμα της κληρονομικότητας, από την κλάση Bicycle προκύπτουην οι κλάσεις MountainBike, RoadBike, TandemBike. Και οι 3 νέες κλάσεις είναι τύπου Bicycle, καθώς αποτελούν εξειδικεύσεις της γενικής κλάσης του ποδηλάτου.

Στην περίπτωση που περιγράψαμε παραπάνω κάτι τέτοιο δεν ισχύει. Αν και το κυβοειδές χρειάζεται ένα ορθογώνιο παραλληλόγραμμο για να περιγραφεί, το κυβοειδές δεν είναι και ορθογώνιο παραλληλόγραμμο. Δεν μπορούμε να πάμε δηλαδή από το κυβοειδές προς το ορθογώνιο παραλληλόγραμμο διατηρώντας τις βασικές ιδιότητες του κυβοειδούς, καθώς το κυβοειδές είναι ένα τρισδιάστατο σχήμα, ενώ το ορθογώνιο παραλληλόγραμμο διδιάστατο.

java/type_casting.1455515086.txt.gz · Last modified: 2016/02/26 11:15 (external edit)