Lass sie ein Beispiel mit einer nicht-abstrakten Basisklasse verwenden:
public class Human {
public string getName() {
// ...
}
}
public class Student extends Human {
public void learn(Subject subject) {
// ...
}
}
public class Teacher extends Human {
public void teach(Subject subject) {
// ...
}
}
An jedem Ort, an dem ein Human
erwartet wird, wird genauso gut ein Student
oder Teacher
tun, da sie vollständig den Human
-Schnittstelle implementieren. (In diesem Fall kann das getName()
für sie aufgerufen werden.) Java-Vererbung garantiert, dass dies technisch der Fall ist. Damit es semantisch funktioniert, ist der Job des Klassenautors, so dass sein Code die Liskov substitution principle erfüllt.
Also bedeutet das nicht, dass wir auch Collection<Teacher>
ersetzen können, wo ein Collection<Human>
erwartet wird? Nicht immer. Betrachten Sie die folgende Methode:
public class Human {
// ...
public void join(Set<Human> party) {
party.add(this);
}
}
Nun, wenn Java eine Set<Student>
erlaubt als Partei übergeben werden, alle Versuche der nicht Student
Human
s, dass die Partei beizutreten würde zur Laufzeit zum Scheitern verurteilt.
In der Regel ist ein Container eines Subtyps ungeeignet, wenn der Empfänger (aufgerufen im Falle eines Funktionsarguments, Aufrufer im Falle eines Funktionsrückgabewerts) etwas hineinlegen will, aber akzeptabel wenn der Empfänger wollen nur Sachen rausnehmen und benutzen. Ein Container eines Supertyps ist ungeeignet, wenn der Empfänger Dinge entfernen und benutzen will, aber akzeptabel, wenn der Empfänger nur Sachen hineinlegt. Wenn der Empfänger also sowohl Material aus der Sammlung nimmt als auch Material in die Sammlung legt, müssen sie normalerweise eine Sammlung eines festen Typs benötigen.
Unsere join
Methode setzt nur Human
s in die party
, so konnten wir auch eine Set<Object>
oder eine nicht-generic Set
oder äquivalent ein Set<?>
ermöglichen. Java uns, das zu tun erlaubt mit lower-bounded wildcards:
public class Human {
// ...
public void join(Set<? super Human> party) {
party.add(this);
}
}
Für die Möglichkeiten in Richtung Unterklassen eröffnen, gibt es upper-bounded wildcards:
public class Teacher extends Human {
public void teach(Subject subject, Set<? extends Student> schoolClass) {
for (Student student : class) {
student.learn(subject);
}
}
}
Nun, wenn wir jemals Student
Unterklasse, die übergebene schoolClass
kann ein Set
von seinem dieser Subtyp auch.
Lesen Sie diesen Artikel darüber, warum Java [Generika sind nicht kovariant] (http://www.ibm.com/developerworks/library/j-jtp01255/). – Ralf
'Liste extends Zahl> 'würde funktionieren. Es verhindert 'add'. –