Dieser Artikel stellt hauptsächlich relevante Informationen zu den detaillierten Beispielen des zusammengesetzten Mechanismus in Java vor. Ich hoffe, dass jeder durch diesen Artikel den Unterschied zwischen Vererbung und Zusammensetzung verstehen und den Mechanismus der Zusammensetzung anwenden kann
Detaillierte Erläuterung von Beispielen für zusammengesetzte Mechanismen in Java
Die Mängel der Vererbung
Die Mängel der Vererbung sind verursacht durch seine übermäßig leistungsstarke Funktion. Die Vererbung macht die Unterklasse von der Implementierung der Oberklasse abhängig. Unter diesem Gesichtspunkt entspricht sie nicht dem Prinzip der Kapselung.
Sobald sich die Oberklasse mit einer Veröffentlichung ändert, kann die Unterklasse kaputt gehen, auch wenn sich ihr Code überhaupt nicht geändert hat.
Um es genauer zu erklären, müssen wir unter der Annahme, dass wir HashSet jetzt in unserem Programm verwenden, eine Funktion hinzufügen, um zu zählen, wie viele Elemente diesem HashSet seit seiner Erstellung hinzugefügt wurden.
Ohne die Mängel der Vererbung zu kennen, haben wir eine Klasse entworfen, die HashSet geerbt, ein Attribut addCount für Statistiken hinzugefügt und die Methoden add und addAll überschrieben. In der Methode Ändern Sie den Wert von addCount,
Der Code lautet wie folgt:
public class InstrumentedHashSet<E> extends HashSet<E> { // The number of attempted element insertions private int addCount = 0; public InstrumentedHashSet() { } public InstrumentedHashSet(int initCap, float loadFactor) { super(initCap, loadFactor); } @Override public boolean add(E e) { addCount++; return super.add(e); } @Override public boolean addAll(Collection<? extends E> c) { addCount += c.size(); return super.addAll(c); } public int getAddCount() { return addCount; } }
Diese Klasse sieht vernünftig aus, funktioniert aber nicht ordnungsgemäß. Führen Sie diesen Code aus:
public static void main(String[] args) { InstrumentedHashSet<String> s = new InstrumentedHashSet<String>(); s.addAll(Arrays.asList("Snap", "Crackle", "Pop")); System.out.println(s.getAddCount()); // expect 3 but 6 }
Da nur drei Elemente eingefügt wurden, erwarteten wir, dass die getAddCount-Methode 3 zurückgeben sollte, aber tatsächlich gab sie 6 zurück. Was ist schief gelaufen?
Tatsächlich wird in HashSet die addAll-Methode basierend auf der add-Methode implementiert. Wenn Sie also addAll zum Hinzufügen von drei Elementen verwenden, wird addAll einmal aufgerufen und dreimal hinzugefügt.
Wenn wir uns unsere überschreibende Methode ansehen, werden wir verstehen, warum getAddCount 6 zurückgibt.
Natürlich werden Sie sagen, dass wir die addAll-Methode nicht überschreiben müssen, da HashSet so implementiert ist. Ja, das stimmt.
Obwohl dies normal funktionieren kann, hängt seine Richtigkeit davon ab, dass die addll-Methode von HashSet in der add-Methode implementiert ist.
Sobald die Superklasse die Implementierungsdetails ändert, kann dies Auswirkungen auf unsere Funktionalität haben.
Im Allgemeinen weist die Vererbung drei natürliche Mängel auf, die die Software sehr anfällig machen:
1) Wenn die Unterklasse die Methode der übergeordneten Klasse aufruft, wird sie gebildet eine Abhängigkeit von der übergeordneten Klasse. Sobald die übergeordnete Klasse geändert wird, funktioniert die Unterklasse möglicherweise nicht ordnungsgemäß.
2) Wenn die übergeordnete Klasse eine neue Methode hinzufügt und die Unterklasse bereits eine Methode mit derselben Signatur, aber einem anderen Rückgabewert bereitstellt, kann die Unterklasse nicht kompiliert werden.
3) Durch die Verwendung der Vererbung, wenn sie nicht durchgeführt werden sollte, werden unnötige APIs für Unterklassen verfügbar gemacht. In dieser Hinsicht hat die Java-Plattform einen Fehler gemacht: Eigenschaften erben HashTable, was unzumutbar ist, aber die Eigenschaften im Java-Code erben Erstellt eine Properties-Instanz, es gibt zwei Methoden: setProperties und getProperties. Die Put- und Get-Methoden sollten Benutzern nicht zugänglich gemacht werden.
Denn in den Eigenschaften sollten sowohl Schlüssel als auch Wert String sein, während HashMap andere Typen oder sogar Objekte sein kann.
public class TestProperty { public static void main(String[] args) { Properties properties = new Properties(); properties.setProperty("aaa", "aaa"); properties.put("aaa", new TestPropertyObj()); System.out.println(properties.getProperty("aaa")); // null System.out.println(properties.get("aaa")); // com.hzy.effjava.chp3.item16.TestProperty$TestPropertyObj@5f4fcc96 } static class TestPropertyObj { } }
Zusammengesetzte Alternativen zur Vererbung
Im vorherigen Abschnitt ging es um die Mängel der Vererbung. In diesem Abschnitt werfen wir einen Blick auf die Lösung dieses Problems – die Aufzinsung.
Zuerst benötigen wir eine Klasse, die ein Set-Objekt enthält. Die Implementierungsmethode ruft die entsprechende Methode des Set-Objekts auf, daher nennen wir sie auch Weiterleitung 🎜>
public class ForwardingSet<E> implements Set<E> { private final Set<E> s; public ForwardingSet(Set<E> s) { this.s = s; } public void clear() { s.clear(); } public boolean contains(Object o) { return s.contains(o); } public boolean isEmpty() { return s.isEmpty(); } public int size() { return s.size(); } public Iterator<E> iterator() { return s.iterator(); } public boolean add(E e) { return s.add(e); } public boolean remove(Object o) { return s.remove(o); } public boolean containsAll(Collection<?> c) { return s.containsAll(c); } public boolean addAll(Collection<? extends E> c) { return s.addAll(c); } public boolean removeAll(Collection<?> c) { return s.removeAll(c); } public boolean retainAll(Collection<?> c) { return s.retainAll(c); } public Object[] toArray() { return s.toArray(); } public <T> T[] toArray(T[] a) { return s.toArray(a); } @Override public boolean equals(Object o) { return s.equals(o); } @Override public int hashCode() { return s.hashCode(); } @Override public String toString() { return s.toString(); } }
public class InstrumentedSet<E> extends ForwardingSet<E> { private int addCount = 0; public InstrumentedSet(Set<E> s) { super(s); } @Override public boolean add(E e) { addCount++; return super.add(e); } @Override public boolean addAll(Collection<? extends E> c) { addCount += c.size(); return super.addAll(c); } public int getAddCount() { return addCount; } public static void main(String[] args) { InstrumentedSet<String> s = new InstrumentedSet<String>(new HashSet<String>()); s.addAll(Arrays.asList("Snap", "Crackle", "Pop")); System.out.println(s.getAddCount()); } }
Zusammenfassung
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des zusammengesetzten Mechanismus in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!