Κληρονομικότητα παραμετρικών τύπων δεδομένων

public void boxTest(Box<Number> n) { /* ... */ }  //line 1
 
Box<Number> box = new Box<Number>();  //line 3
box.add(new Integer(10));             //line 4
box.add(new Double(10.1));            //line 5
 
Box<Double> doubleBox = new Box<Double>(); // line 7
doubleBox.add(new Double(10.1));           // line 8
 
box.boxTest(doubleBox); // line 10. Μπορούμε να γράψουμε?

Ο παραπάνω κώδικας είναι σωστός στις γραμμές 3 έως και 8. Στις γραμμές 3-5 οι κλάσεις Integer και Double είναι υποκλάσεις της κλάσης Number, ενώ στις γραμμές 7-8 το αντικείμενο doubleBox αποθηκευει ένα αντικείμενο τύπου Double. Δεν ισχύει όμως το ίδιο για την γραμμή 10 καθώς η μέθοδος boxText λαμβάνει ως όρισμα ένα αντικείμενο τύπου Box<Number>. Η κλάση Box<Double> δεν είναι υποκλάση της κλάσης Box<Number>, όπως δείχνει το παρακάτω σχήμα.

Η έννοια της κληρονομικότητας σε αυτή την παράγραφο δεν έχει την αυστηρή έννοια της κληρονομικότητας μεταξύ τύπων δεδομένων που ορίσαμε σε προηγούμενες ενότητες. Περισσότερο εστιάζει στο πρακτικό ερώτημα κατά πόσο μπορούμε να χρησιμοποιήσουμε ένα τύπο δεδομένων στην θέση ενός άλλου τύπου (π.χ. ως όρισμα σε μία μέθοδο).

Οι σχέσεις κληρονομικότητας μεταξύ παραμετρικών τύπων μπορούν να οριστούν ως εξής:

  Collection<E>                Collection<String>                Collection<Number>
      |                               |                                Χ
      v          π.χ.                 v            όχι όμως και        v
    List<E>                       List<String>                      List<Integer>
  HashSet<E>                HashSet<String>                   HashSet<Number>
      |                          |                                  Χ
      v          π.χ.            v             όχι όμως και         v
LinkedHashSet<E>         LinkedHashSet<String>               LinkedHashSet<Integer>
    List<E>                   List<String>                      List<Number>
      |           π.χ.             |           όχι όμως και         X
      v                            v                                V
  ArrayList<E>             ArrayList<String>                 ArrayList<Integer>