Java UtilityKlassenbibliothek bietet einen ziemlich vollständigen Satz von Containern, die uns bei der Lösung vieler spezifischer Probleme helfen. Weil ich selbst Android-Entwickler bin und viele Android-Entwickler, mich eingeschlossen, die drei Musketiere ListView (RecycleView) + BaseAdapter + ArrayList am besten beherrschen. Die einzigen Container, die ich normalerweise verwende, sind ArrayList und HashMap. Daher ist das Verständnis und die Nutzung des gesamten Java-Containersystems immer noch auf einem sehr oberflächlichen Niveau. Wenn Sie sich nicht sparen und über Verbesserungen nachdenken möchten, folgen Sie mir, um das relevante Wissen über Java-Container zusammenzufassen.
VererbungStruktur der Java-Containerklasse
Detaillierte Einführung
Liste
Satz
Warteschlange
Iteration Gerät
Sammlung
Karte
Einige Vorschläge
Erweitert · Gleichzeitiger Container
CopyOnWriteArrayList und Copy-On-Write-Strategie
ConcurrentLinkedQueue
ConcurrentHashMap- und Sperrsegmentierungstechnologie
Blockierungswarteschlange
Die Java-Containerklassenbibliothek definiert zwei Container mit unterschiedlichen Konzepten: Sammlung und Karte
Sammlung Eine Folge unabhängiger Elemente. Diese Elemente folgen einem oder mehr Regeln. Die Liste muss Elemente in der Reihenfolge des Einfügens enthalten. Set darf keine doppelten Elemente enthalten. Die Warteschlange bestimmt die Reihenfolge, in der Objekte gemäß den Warteschlangenregeln generiert werden.
(Die JDK-Quellcodeversion im Artikel ist jdk1.8.0_101 ohne besondere Anweisungen)
public interface Collection<E> extends Iterable<E> { int size(); boolean isEmpty(); boolean contains(Object o); Iterator<E> iterator(); Object[] toArray(); <T> T[] toArray(T[] a); boolean add(E e); boolean remove(Object o); boolean containsAll(java.util.Collection<?> c); boolean addAll(java.util.Collection<? extends E> c); boolean removeAll(java.util.Collection<?> c); ... //省略了其他方法 }
Wie Sie sehen können, definiert Java die grundlegende Sammlungsschnittstelle und interne Sammlungsoperationsmethode. Sammlung kann standardmäßig Vorgänge wie das Hinzufügen von Elementen am Ende der Sammlung und das Löschen bestimmter Elemente ausführen. List-, Set- und Queue-Schnittstellen erben alle von Collection und definieren unterschiedliche Methoden.
Map Eine Reihe von „Schlüsselwert“-Objekten, die es uns ermöglichen, Werte mithilfe von Schlüsseln nachzuschlagen.
public interface Map<K,V> { int size(); boolean containsKey(Object key); boolean containsValue(Object value); V get(Object key); V put(K key, V value); V remove(Object key); void putAll(java.util.Map<? extends K, ? extends V> m); void clear(); Set<K> keySet(); Collection<V> values(); Set<java.util.Map.Entry<K, V>> entrySet(); interface Entry<K,V> { K getKey(); V getValue(); V setValue(V value); boolean equals(Object o); int hashCode(); ... } boolean equals(Object o); int hashCode(); }
Map-interner Schnittstelleneintrag
Stellen Sie zunächst den Iterator vor. Der Iterator selbst ist ebenfalls ein Entwurfsmuster . Die ursprüngliche Absicht des Entwurfs besteht darin, dass es viele Arten von Containerimplementierungen gibt, und wenn wir den Container durchlaufen möchten, sollte es uns egal sein Erstens über die Container-Implementierung, zweitens sollte der Durchlaufvorgang leichtgewichtig sein. Iteratoren vereinheitlichen den Zugriff auf Container und sind kostengünstig zu erstellen. Es ist zu beachten, dass sich Iteratoren nur in eine Richtung bewegen können.
public interface Iterator<E> { boolean hasNext(); E next(); default void remove() { throw new UnsupportedOperationException("remove"); } default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); } }
Rufen Sie den Iterator des Containers über die iterator()-Methode des Containers ab
Next() des Iterators ruft das nächste Element ab
hasNext() bestimmt, ob es welche gibt beliebige Elemente
remove() löscht das angegebene Element
ListIterator ist eine Erweiterung von Iterator und wird für verschiedene List-Klassenzugriffe verwendet und unterstützt bidirektionale Bewegung.
List verspricht, Elemente in einer bestimmten Reihenfolge beizubehalten. Die List-Schnittstelle fügt eine große Anzahl von Methoden hinzu, die auf Collection basieren und das Einfügen und Entfernen ermöglichen Elemente.
public interface List<E> extends Collection<E> { ... boolean add(E e); boolean remove(Object o); boolean containsAll(Collection<?> c); boolean addAll(Collection<? extends E> c); boolean addAll(int index, Collection<? extends E> c); boolean removeAll(Collection<?> c); boolean retainAll(Collection<?> c); E get(int index); E set(int index, E element); void add(int index, E element); E remove(int index); int indexOf(Object o); int lastIndexOf(Object o); java.util.List<E> subList(int fromIndex, int toIndex); ... }
Es gibt zwei Arten von Listen: ArrayList und LinkedList
Listentyp | Vorteile< /th> | Nachteile | zugrunde liegende Implementierung | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ArrayList | Elemente mit wahlfreiem Zugriff sind schneller | Das Einfügen und Löschen von Zwischenelementen ist langsamer | Array
| ||||||||||||
LinkedList | Einfügen und Löschen von Zwischenelementen, Optimierung des sequentiellen Zugriffs | Elemente mit wahlfreiem Zugriff sind langsamer td> | Doppelt verknüpfte Liste |
Set speichert keine doppelten Elemente und wird normalerweise verwendet zum schnellen Finden von Elementen. Erwähnenswert ist, dass Set genau die gleiche Benutzeroberfläche wie Collection ohne zusätzliche Funktionen hat. Die gespeicherten Elemente müssen die Methode equal()
Set类型 | 使用场景 | 底层实现 |
---|---|---|
HashSet | 快速查找,元素必须定义hashCode() | 链表 |
TreeSet | 保持次序,元素必须实现Comparable接口 | 红-黑树结构 |
LinkedHashSet | 维护次序的HashSet, 元素必须定义hashCode() | 链表 |
除了并发应用,Queue仅有的两个实现是LinkedList和PriorityQueue, 其中LinkedList同时实现了List, Deque接口。它们的差异在于排序行为而不是性能。
public interface Queue<E> extends Collection<E> { boolean add(E e); boolean offer(E e); E remove(); E poll(); E element(); E peek(); }
Map类型 | 使用场景 | 底层实现 |
---|---|---|
HashMap | 快速查询 | 散列表 |
LinkedHashMap | 迭代遍历具有顺序(插入顺序 or 最近最少使用) | 链表 |
TreeMap | 具有排序,唯一可以返回子树的Map(subMap()) | 红-黑树结构 |
WeakHashMap | 弱键映射,映射之外无引用的键,可以被垃圾回收 | 散列表 |
ConcurrentHashMap | 线程安全的Map | 链表 |
IdentityHashMap | 使用==代替equals()对键进行排序,专位解决特殊问题 | 链表 |
Wir können HashMap manuell anpassen, um die Leistung anzupassen, und zwar unter Einbeziehung von Konzepten wie Kapazität, Anfangskapazität, Größe, Auslastungsfaktor usw. Wenn Sie interessiert sind, können Sie einige relevante Informationen lesen.
Verwenden Sie keine veralteten Container wie Vector Enumeration Hashtable Stack (ja, das ist das ursprüngliche schlechte Design von Java. Wenn Sie den Stack in verwenden Übung, LinkedList wird empfohlen)
Ich werde hier nicht auf die detaillierte Implementierung eingehen, sondern nur kurz das Grundwissen vorstellen. Sie können das Buch „Java Concurrent Programming“ Art lesen.
Copy-On-Write, auch COW genannt, ist eine Optimierungsstrategie, die in der Programmierung verwendet wird. Die Grundidee besteht darin, dass jeder den gleichen Inhalt von Anfang an teilt. Wenn jemand den Inhalt ändern möchte, wird er tatsächlich einen neuen Inhalt erstellen und ihn dann ändern. Ab JDK1.5 stellt das Java-Parallelitätspaket zwei gleichzeitige Container bereit, die mithilfe des CopyOnWrite-Mechanismus implementiert werden: CopyOnWriteArrayList und CopyOnWriteArraySet. Der CopyOnWrite-Container ist sehr nützlich und kann in vielen gleichzeitigen Szenarien verwendet werden.
CopyOnWrite-Container ist ein Container, der beim Schreiben kopiert wird. Das gängige Verständnis ist, dass wir beim Hinzufügen von Elementen zu einem Container diese nicht direkt zum aktuellen Container hinzufügen, sondern zuerst den aktuellen Container kopieren, um einen neuen Container zu erstellen, und dann Elemente zum neuen Container hinzufügen. Zeigen Sie dann die Referenz des ursprünglichen Containers auf den neuen Container. Dies hat den Vorteil, dass wir den CopyOnWrite-Container gleichzeitig lesen können, ohne ihn zu sperren, da der aktuelle Container keine Elemente hinzufügt. Daher ist der CopyOnWrite-Container auch eine Idee der Trennung von Lesen und Schreiben, und Lesen und Schreiben sind unterschiedliche Container.
Der CopyOnWrite-Container kann nur die endgültige Konsistenz der Daten garantieren, nicht jedoch die Echtzeitkonsistenz der Daten. Wenn Sie also möchten, dass die geschriebenen Daten sofort gelesen werden, verwenden Sie bitte nicht den CopyOnWrite-Container.
Bei der gleichzeitigen Programmierung müssen Sie manchmal threadsichere Warteschlangen oder Listen verwenden. Normalerweise gibt es zwei Möglichkeiten, Thread-Sicherheit zu erreichen: Eine besteht darin, blockierende Algorithmen zu verwenden, und die andere darin, nicht blockierende Algorithmen zu verwenden. Die Grundlage für die Implementierung des nicht blockierenden Algorithmus ist die Schleife CAS (Compare and Swipe-Vergleich und Austausch).
Die technische Implementierung von ConcurrentLinkedQueue ähnelt CopyOnWriteArrayList und Copy, jedoch kann nur ein Teil des Inhalts des Containers kopiert und geändert werden, anstatt den gesamten Container. ConcurrentLinkedQueue besteht aus einem Kopfknoten und einem Endknoten. Jeder Knoten besteht aus einem Knotenelement (Element) und einer Referenz, die auf den nächsten Knoten (next) zeigt. Die Knoten werden durch Next verknüpft, um eine Warteschlange mit einer verknüpften Listenstruktur zu bilden.
ConcurrentHashMap ist eine threadsichere und effiziente HashMap. In einer Multithread-Umgebung führt die Verwendung einer nicht threadsicheren HashMap zu einer Endlosschleife, und wie im Artikel vorgeschlagen, sind veraltete Container wie HashTable ineffizient (verwenden Sie synchronized, um Thread sicherzustellen Sicherheit). ConcurrentHashMap verwendet die Sperrsegmentierungstechnologie, um die Effizienz der gleichzeitigen Nutzung erheblich zu verbessern.
Sperrsegmentierungstechnologie: Angenommen, der Container verfügt über mehrere Sperren und jede Sperre wird zum Sperren eines Teils der Daten im Container verwendet. Wenn mehrere Threads auf verschiedene Datensegmente des Containers zugreifen, gibt es diese Keine Sperre zwischen Threads, um die Effizienz des gleichzeitigen Zugriffs zu verbessern.
JDK7 bietet 7 Blockierungswarteschlangen, und die Implementierungsprinzipien basieren alle auf dem Produktions-Verbrauchsmodell, das auf einen Benachrichtigungsmechanismus wartet.
Blockierungswarteschlangentyp | Funktionen | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Begrenzte Blockierungswarteschlange bestehend aus einer Array-Struktur | |||||||||||||||||
LinkedBlockingQueue | Begrenzte Blockierungswarteschlange bestehend aus einer verknüpften Listenstruktur | ||||||||||||||||
PriorityBlockingQueue | Unterstützt Priorität
|
||||||||||||||||
DelayQueue | Unbegrenzte Blockierungswarteschlange mithilfe der Prioritätswarteschlange implementiert | ||||||||||||||||
SynchronousQueue | Eine blockierende Warteschlange, die keine Elemente speichert | ||||||||||||||||
LinkedTransferQueue | Eine unbegrenzte blockierende Warteschlange, die aus einer verknüpften Listenstruktur besteht | ||||||||||||||||
LinkedBlockingQueue | Eine bidirektionale Blockierungswarteschlange, die aus einer verknüpften Listenstruktur besteht |
Das obige ist der detaillierte Inhalt vonDetaillierte Einführung in eine umfassende Zusammenfassung des Wissens über Java-Container (Bild). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!