java:generics

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:generics [2015/03/19 13:29]
gthanos [Παραμετρικοί τύποι δεδομένων (Generics)]
java:generics [2017/02/17 15:01] (current)
gthanos
Line 1: Line 1:
 ====== Παραμετρικοί τύποι δεδομένων (Generics) ====== ====== Παραμετρικοί τύποι δεδομένων (Generics) ======
  
-Ένας ​//generic// (γενικός) τύπος δεδομένων είναι ένας τύπος δεδομένων ο οποίος μπορεί να λαμβάνει ως παραμέτρους άλλους τύπους δεδομένων. ​Γενικότερα όταν θέλουμε να χρησιμοποιήσουμε κλάσεις που μπορούν να αποθηκεύσουν αντικείμενα οποιασδήποτε κλάσης (π.χ. ​για αν δημιουργήσουμε μία διασυνδεδεμένη λίστα) τότε θα πρέπει τις κλάσεις αυτές να τις κάνουμε τόσο γενικές ώστε να μπορούν να λαμβάνουν ως όρισμα οποιονδήποτε τύπο δεδομένων. Η υιοθέτηση γενικών κλάσεων έχει το πλεονέκτημα ότι μπορεί ​να αποθηκεύσει οποιαδήποτε ​κλάση, όμως απαιτεί αρκετά type-casts και ενέχει κινδύνους ως προς την ορθή διαχείριση των δεδομένων ​από τους προγραμματιστές.+Ένας ​παραμετρικός ​(//​generic//​) τύπος δεδομένων είναι ένας τύπος δεδομένων ο οποίος μπορεί να λαμβάνει ως παραμέτρους άλλους τύπους δεδομένων. ​Όταν θέλουμε να δημιουργήσουμε κλάσεις που μπορούν να αποθηκεύσουν αντικείμενα οποιασδήποτε κλάσης (π.χ. ​εάν θέλουμε να δημιουργήσουμε μία διασυνδεδεμένη λίστα ή μία στοίβα) τότε θα πρέπει τις κλάσεις αυτές να τις κάνουμε τόσο γενικές ώστε να μπορούν να αποθηκεύουν οποιονδήποτε τύπο ​αντικειμένων. ​
  
-Δείτε το παρακάτω παράδειγμα της κλάσης Box, η οποία θέλουμε να μπορεί να αποθηκεύσει οποιονδήποτε τύπο δεδομένων.+Η υιοθέτηση γενικών κλάσεων έχει το πλεονέκτημα ότι μπορεί να αποθηκεύσει αντικείμενα οποιασδήποτε κλάσης,​ όμως απαιτεί αρκετές μετατροπές τύπων (typecasts). Οι μετατροπές τύπων όταν γίνονται από τον προγραμματιστή και όχι από τον compiler ενέχουν κινδύνους ως προς την ορθή μετατροπή. 
 + 
 +===== Παράδειγμα γενικής κλάσης για την αποθήκευση δεδομένων ===== 
 + 
 +Δείτε το παρακάτω παράδειγμα της κλάσης ​**Box**, η οποία θέλουμε να μπορεί να αποθηκεύσει οποιονδήποτε τύπο δεδομένων.
  
 <code java Box.java>​ <code java Box.java>​
Line 14: Line 18:
 </​code>​ </​code>​
  
-Στο παραπάνω παράδειγμα ​επειδή όλες οι κλάσεις στη ​Java κληρονομούν ​την κλάση ​Object, μπορείτε να περάσετε ως όρισμα στις μεθόδους της συγκεκριμένης κλάσης ​οποιοδήποτε ​τύπο ​δεδομένωνΔείτε το παρακάτω παράδειγμα κώδικα που χρησιμοποιεί την κλάση Box.+Ας υποθέσουμε ότι έχετε ​το παρακάτω παράδειγμα ​κώδικα που ​λειτουργεί σωστά αποθηκεύοντας στην κλάση ​Box και ​επιστρέφοντας την ​τιμή ενός αντικείμενου τύπου [[https://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​Integer.html|Integer]].
  
 <code java BoxUsage.java>​ <code java BoxUsage.java>​
Line 22: Line 26:
      ​Integer n = new Integer(5);      ​Integer n = new Integer(5);
      ​b.set(n);​      ​b.set(n);​
-     String ​s = (String)b.get();+     Integer ​s = (Integer)b.get();
    }    }
 } }
 </​code>​ </​code>​
  
-Ο παραπάνω ​κώδικας αφού μεταγλωττιστεί και επιχειρήσουμε να το τρέξουμε παράγει το παρακάτω ​exception ​καθώς ​επιχειρούμε να αναθέσουμε μία μεταβλητή τύπου ​String ένα αντικείμενο τύπου ​Integer+Στο ​παραπάνω ​παράδειγμα επειδή όλες οι κλάσεις κληρονομούν την κλάση [[https://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​Object.html|Object]], ​μπορείτε  
-<code+  * να περάσετε ​ως όρισμα στη μέθοδο //set// οποιοδήποτε τύπο δεδομένων ή  
-Exception in thread "​main" ​java.lang.ClassCastException: ​java.lang.Integer cannot be cast to java.lang.String +  * να αναθέσετε την επιστρεφόμενη τιμή της μεθόδου //get// σε οποιοδήποτε τύπο δεδομένων.  
-        ​at ​BoxUsage.main(BoxUsage.java:7)+ 
 +Παρατηρήστε ότι στην τελευταία γραμμή είμαστε υποχρεωμένοι να κάνουμε ​typecast την επιστρεφόμενη τιμή της μεθόδου get() από [[https://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​Object.html|Object]] στον τύπο δεδομένων που τελικά έχει αποθηκεύσει η κλάση Box. Εάν δεν κάνουμε typecast ο μεταγλωττιστής διαμαρτύρεται. Εάν το typecast είναι σωστό ο κώδικας λειτουργεί σωστά, ενώ εάν το typecast είναι λάθος δημιουργείται ένα //​Exception//​ που περιγράφεται ​παρακάτω.  
 + 
 +Δείτε τώρα το παρακάτω παράδειγμα κώδικα που χρησιμοποιεί την κλάση Box για να αποθηκεύσει ​ένα Integer και στη ​συνέχεια λαμβάνει το περιεχόμενο του ακεραίου και επιχειρεί ​να το αποθηκεύει σε μία μεταβλητή ​τύπου ​String. 
 + 
 +<code java BoxUsage.java> 
 +public class BoxUsage ​
 +   ​public static void main(String args[]) { 
 +     Box b = new Box(); 
 +     ​Integer n = new Integer(5);​ 
 +     b.set(n)
 +     ​String s = (String)b.get();​ 
 +   } 
 +}
 </​code>​ </​code>​
  
-Παρατηρήστε επίσης, ότι ​στην τελευταία γραμμή είμαστε υποχρεωμένοι να κάνουμε cast την επιστρεφόμενη τιμή της μεθόδου get() από Object σε String. ​Προκειμένου να αποφύγουμε τα παραπάνω προβλήματα και να είμαστε σίγουροι ότι ο κώδικας που γράφουμε δεν περιέχει λάθη στη χρήση τύπων δεδομένων η Java εισάγει τους παραμετρικούς τύπους δεδομένων,​ γνωστούς ως Generics. Η κλάση Box με χρήση ​Generics ​θα μπορούσε να γραφεί ως εξής:+Η μετατροπή τύπου στην τελευταία γραμμή είναι προφανώς λάθος. Ο παραπάνω κώδικας αφού μεταγλωττιστεί και ​επιχειρήσουμε να το τρέξουμε παράγει ένα [[https://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​ClassCastException.html|java.lang.ClassCastException]],​ διότι επιχειρούμε να αναθέσουμε μία μεταβλητή τύπου [[https://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​String.html|String]] ένα αντικείμενο τύπου [[https://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​Integer.html|Integer]]. 
 + 
 +===== Παράδειγμα παραμετρικής κλάσης ===== 
 + 
 +Προκειμένου να αποφύγουμε τα παραπάνω προβλήματα και να είμαστε σίγουροι ότι ο κώδικας που γράφουμε δεν περιέχει λάθη στη χρήση τύπων δεδομένων η Java εισάγει τους παραμετρικούς τύπους δεδομένων,​ γνωστούς ​και ​ως Generics. Η κλάση Box με χρήση ​//​generics// ​θα μπορούσε να γραφεί ως εξής:
  
 <code java Box.java>​ <code java Box.java>​
Line 50: Line 71:
  
 Η παραπάνω δήλωση της κλάσης //Box// σημαίνει ότι κατά τον ορισμό αντικειμένων της κλάσης αυτά θα πρέπει να προσδιορίζεται ανάμεσα στους χαρακτήρες '<',​ ΄>'​ ένας επιπλέον reference τύπος δεδομένων,​ δηλ μπορούμε να γράψουμε Η παραπάνω δήλωση της κλάσης //Box// σημαίνει ότι κατά τον ορισμό αντικειμένων της κλάσης αυτά θα πρέπει να προσδιορίζεται ανάμεσα στους χαρακτήρες '<',​ ΄>'​ ένας επιπλέον reference τύπος δεδομένων,​ δηλ μπορούμε να γράψουμε
 +
 <code java> <code java>
 Box<​String>​ b1 = new Box<​String>​();​ Box<​String>​ b1 = new Box<​String>​();​
Line 55: Line 77:
 Box<​Student>​ b3 = new Box<​Student>​();​ // όπου Student μία κλάση που έχουμε κατασκευάσει. ​ Box<​Student>​ b3 = new Box<​Student>​();​ // όπου Student μία κλάση που έχουμε κατασκευάσει. ​
 </​code>​ </​code>​
 +
 Ο τύπος δεδομένων που χρησιμοποιούμε ανάμεσα στους χαρακτήρες '<',​ ΄>'​ είναι ο τύπος δεδομένων που επιτρέπεται να αποθηκευθεί στην κλάση //Box// κάθε φορά. ​ Ο τύπος δεδομένων που χρησιμοποιούμε ανάμεσα στους χαρακτήρες '<',​ ΄>'​ είναι ο τύπος δεδομένων που επιτρέπεται να αποθηκευθεί στην κλάση //Box// κάθε φορά. ​
  
-Αντικείμενα της κλάσης Box ορίζονται συνήθως σε συνδυασμό με ένα reference τύπο δεδομένων,​ όπως δείξαμε προηγούμενα. Υπάρχει η δυνατότητα να ορίσετε ένα αντικείμενο της κλάσης //Box// χωρίς την χρήση της επιπλέον παραμέτρου,​ δηλ  +===== Συνήθης ονοματολογία παραμέτρων =====
-<code java> +
-Box b new Box() +
-</​code>​ +
-Σε αυτή την περίπτωση ο compiler δεν είναι σε θέση να γνωρίζει τον τύπο δεδομένων που θα τοποθετήσετε στο συγκεκριμένο αντικείμενο. Ουσιαστικά η παραπάνω δήλωση ισοδυναμεί με μία δήλωση της μορφής +
-<code java> +
-Box<​Object>​ b = new Box<​Object>​();​ +
-</​code>​ +
-Η προσπάθεια μεταγλώττισης του παρακάτω κώδικα καταδεικνύει το παραπάνω +
-<code java BoxUsage.java>​ +
-public class BoxUsage { +
-   ​public static void main(String args[]) { +
-     Box b = new Box(5); +
- Box<​Number>​ bn = new Box<​Number>​();​ +
- bn.set(b.get()); ​     +
-   } +
-+
-</​code>​ +
-Αν αλλάξετε την γραμμή ''​Box<​Number>​ bn = new Box<​Number>​();''​ σε ''​Box<​Object>​ bn = new Box<​Object>​();''​ το compilation error εξαφανίζεται και εμφανίζεται ένα warning. +
- +
-===== Ονοματολογία παραμέτρων =====+
  
   * E - Element (χρησιμοποείται στο Java Collections Framework)   * E - Element (χρησιμοποείται στο Java Collections Framework)
Line 86: Line 89:
   * S,U,V etc. - 2nd, 3rd, 4th types   * S,U,V etc. - 2nd, 3rd, 4th types
  
-===== Δημιουργία και χρήση αντικειμένων ενός ​γενικού τύπου δεδομένων =====+===== Δημιουργία και χρήση αντικειμένων ενός ​παραμετρικού τύπου δεδομένων =====
  
 <code java> <code java>
Line 110: Line 113:
 </​code>​ </​code>​
  
-===== Παραμετρικοί τύποι δεδομένων με πολλές παραμέτρους ===== +Προηγούμενο: ​[[:java:class_file | Αρχεία ​]] | [[:toc | Περιεχόμενα ​]] | Επόμενο: [[:​java:​generic_interfaces | Interfaces ​ως παραμετρικοί τύποι δεδομένων ]] |
- +
-<code java Pair.java>​ +
-public interface Pair<K, V> { +
-    public K getKey(); +
-    public V getValue();​ +
-    public void setKey(K key); +
-    public void setValue(V value); +
-+
-</​code>​ +
-public class OrderedPair<​K,​ V> implements Pair<​K,​V>​ { +
- +
-    private K key; +
-    private V value; +
- +
-    public OrderedPair(K key, V value) { +
-        this.key = key; +
-        this.value = value; +
-    } +
- +
-    public void setKey(K key) { this.key = key; } +
-    public void setValue(V value) { this.value = value; } +
-    public K getKey() ​  { return key; } +
-    public V getValue() { return value; } +
-+
-<code java OrderedPair.java>​ +
- +
-</​code>​ +
- +
-Με βάση τον παραπάνω κώδικα ​μπορείτε να δημιουργήσετε αντικείμενα επιμέρους τύπων ως εξής: +
-<​code ​java OrderedPairUsage.java>​ +
-public class OrderedPairUsage { +
-  public static void main(String args[]) { +
-    Pair<​String,​ Integer> p1 = new OrderedPair<​String,​ Integer>​("​Even",​ 8); +
-    Pair<​String,​ String> ​ p2 = new OrderedPair<​String,​ String>​("​hello",​ "​world"​);​ +
-    OrderedPair<​String,​ Box<​Integer>>​ p = new OrderedPair<>​("​primes",​ new Box<​Integer>​());​ +
-    // the following is not allowed +
-    Pair<​String,​ Integer> p1 = new OrderedPair<>​("​hello",​ "​world"​);​ +
-  } +
-+
-</​code>​ +
- +
-===== Απλοί παραμετρικοί τύποι δεδομένων (Raw Generic Types) ===== +
- +
-Εάν δεν ​χρησιμοποιήσουμε καμία παράμετρο τότε καταλήγουμε να έχουμε έναν "απλό" παραμετρικό τύπο δεδομένων γνωστό ​ως **Raw types**. Η χρήση των τύπων αυτών δυσκολεύει τον compiler να αποφασίσει για την ασφαλή ή μη χρήση δεδομένων αυτού του τύπου, ειδικά όταν τα δεδομένα αυτά χρησιμοποιούνται μαζί με παραμετρικούς τύπους δεδομένων. Δείτε τα παρακάτω παραδείγματα κώδικα +
- +
-<code java> +
-Box<​String>​ stringBox = new Box<>​();​ +
-Box rawBox = stringBox; ​              // Safe - OK +
-</​code>​ +
- +
-<code java> +
-Box rawBox = new Box(); ​          // rawBox is a raw type of Box<​T>​ +
-Box<​Integer>​ intBox = rawBox; ​    // warning: unchecked conversion +
-</​code>​ +
- +
-<code java> +
-Box<​String>​ stringBox = new Box<>​();​ +
-Box rawBox = stringBox;​ +
-rawBox.set(8); ​             // warning: unchecked invocation to set(T) +
-</​code>​ +
- +
-==== Unchecked Error Messages ==== +
- +
-Όπως είπαμε προηγούμενα η μίξη generics με raw types μπορεί να δημιουργήσει warnings κατά την μεταγλώττιση της μορφής +
-<​code>​ +
-Note: Example.java uses unchecked or unsafe operations. +
-Note: Recompile with -Xlint:​unchecked for details. +
-</​code>​ +
-όπως παρακάτω +
-<code java WarningDemo.java>​ +
-public class WarningDemo { +
-    public static void main(String[args){ +
-        Box<​Integer>​ bi; +
-        bi = createBox();​ +
-    } +
- +
-    static Box createBox(){ +
-        return new Box(); +
-    } +
-+
-</​code>​ +
-Μεταγλωττίζοντας με το flag ''​-Xlint:​unchecked''​ εμφανίζει την παραπάνω χρήση +
-<​code>​ +
-WarningDemo.java:​4:​ warning: [uncheckedunchecked conversion +
-found   : Box +
-required: Box<​java.lang.Integer>​ +
-        bi = createBox();​ +
-                      ^ +
-1 warning +
-</​code>​ +
  
  
java/generics.1426771742.txt.gz · Last modified: 2016/02/26 11:15 (external edit)