Heim  >  Artikel  >  Java  >  Was ist eine Sammlungsklasse in Java? Erläuterung der Struktur der Sammlungsklasse anhand grafischer Beispiele

Was ist eine Sammlungsklasse in Java? Erläuterung der Struktur der Sammlungsklasse anhand grafischer Beispiele

伊谢尔伦
伊谢尔伦Original
2017-05-30 11:29:382826Durchsuche

1. Sammlungen in Java

Die Sammlungsklasse in Java ist die am häufigsten verwendete und praktischste Klasse in der Java-Programmierung. Als Containerklasse kann die Sammlungsklasse jede Art von Daten speichern. Natürlich kann sie auch mit Generika kombiniert werden, um bestimmte Typen zu speichern (Generika sind jedoch nur zur Kompilierungszeit gültig und werden zur Laufzeit gelöscht). Was in der Sammlungsklasse gespeichert ist, ist nur eine Referenz auf das Objekt, nicht das Objekt selbst. Die Kapazität der Sammlungsklasse kann zur Laufzeit dynamisch erweitert werden und bietet außerdem viele praktische Methoden, z. B. das Ermitteln der Vereinigungs- und Schnittmenge von Mengen.

2. Sammlungsklassenstruktur

Sammlungen in Java umfassen eine Vielzahl von Datenstrukturen, wie z. B. verknüpfte Listen, Warteschlangen, Hash-Tabelle usw. Aus Sicht der Klassenvererbungsstruktur kann sie in zwei Hauptkategorien unterteilt werden. Eine davon wird von der Sammlungsschnittstelle geerbt. Diese Art von Sammlung umfasst Sammlungsklassen wie List, Set und Queue. Der andere Typ wird von der Map-Schnittstelle geerbt, die hauptsächlich Sammlungsklassen enthält, die sich auf Hash-Tabellen beziehen. Werfen wir einen Blick auf das Vererbungsstrukturdiagramm dieser beiden Kategorien:

1. Liste, Menge und Warteschlange

Die grün gepunktete Linie in der Abbildung stellt die Implementierung dar, die grüne durchgezogene Linie stellt die Vererbung zwischen Schnittstellen dar und die blaue durchgezogene Linie stellt die Vererbung zwischen Klassen dar.

(1) Liste: Wir verwenden mehr Listen, einschließlich ArrayList und LinkedList. Der Unterschied zwischen den beiden ist ebenfalls offensichtlich, was an ihren Namen erkennbar ist. Die unterste Ebene von ArrayList wird über Arrays implementiert, sodass die Direktzugriffsgeschwindigkeit relativ hoch ist. In Situationen, in denen häufige Hinzufügungen und Löschungen erforderlich sind, ist die Effizienz jedoch relativ gering. Bei LinkedList wird die unterste Ebene über eine verknüpfte Liste implementiert, sodass Hinzufügungs- und Löschvorgänge einfacher durchzuführen sind, die Effizienz des Direktzugriffs jedoch relativ gering ist.

Sehen wir uns zunächst die Einfügungseffizienz der beiden an:

package com.paddx.test.collection;
import java.util.ArrayList;
import java.util.LinkedList;
public class ListTest {
public static void main(String[] args) {
for(int i=;i<;i++){
}
long start = System.currentTimeMillis();
LinkedList<Integer> linkedList = new LinkedList<Integer>();
for(int i=;i<;i++){
linkedList.add(,i);
}
long end = System.currentTimeMillis();
System.out.println(end - start);
ArrayList<Integer> arrayList = new ArrayList<Integer>();
for(int i=;i<;i++){
arrayList.add(,i);
}
System.out.println(System.currentTimeMillis() - end);
}
}

Das Folgende ist das Ergebnis der lokalen Ausführung:

23

1227

Es ist ersichtlich, dass in diesem Fall die Einfügungseffizienz von LinkedList viel höher ist als die von ArrayList. Dies ist natürlich relativ extrem Situation. Vergleichen wir die Effizienz des Direktzugriffs zwischen den beiden:

package com.paddx.test.collection;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Random;
public class ListTest {
public static void main(String[] args) {
Random random = new Random();
for(int i=;i<;i++){
}
LinkedList<Integer> linkedList = new LinkedList<Integer>();
for(int i=;i<;i++){
linkedList.add(i);
}
ArrayList<Integer> arrayList = new ArrayList<Integer>();
for(int i=;i<;i++){
arrayList.add(i);
}
long start = System.currentTimeMillis();
for(int i=;i<;i++){
int j = random.nextInt(i+);
int k = linkedList.get(j);
}
long end = System.currentTimeMillis();
System.out.println(end - start);
for(int i=;i<;i++){
int j = random.nextInt(i+);
int k = arrayList.get(j);
}
System.out.println(System.currentTimeMillis() - end);
}
}

Das Folgende ist das Ergebnis meiner lokalen Ausführung:

5277

6

Es ist offensichtlich, dass die Direktzugriffseffizienz von ArrayList um mehrere Größenordnungen höher ist als die von LinkedList. Durch diese beiden Codeteile sollten wir in der Lage sein, die Unterschiede zwischen LinkedList und ArrayList sowie die anwendbaren Szenarien klar zu verstehen. Bei Vector handelt es sich um eine Thread-sichere Version von ArrayList, während Stack der Stack-Datenstruktur entspricht. Diese beiden werden selten verwendet, daher werde ich hier kein Beispiel geben.

  (2) Warteschlange: Im Allgemeinen kann LinkedList direkt mit LinkedList vervollständigt werden. Wie aus dem obigen Klassendiagramm ersichtlich ist, erbt LinkedList von Deque, sodass LinkedList die Funktion einer doppelendigen Warteschlange hat . Das Merkmal von PriorityQueue besteht darin, jedem Element eine Priorität zuzuweisen, und Elemente mit hoher Priorität werden zuerst aus der Warteschlange entfernt.

 (3) Set: Der Hauptunterschied zwischen Set und List besteht darin, dass Set die Wiederholung von Elementen nicht zulässt, während List die Wiederholung von Elementen zulässt. Die Bestimmung der Duplizierung von Elementen muss auf der Grundlage der Hash-Methode und der Equals-Methode des Objekts erfolgen. Aus diesem Grund überschreiben wir normalerweise die Methode hashCode und die Methode equal für die Elementklassen in der Sammlung. Schauen wir uns anhand eines Beispiels den Unterschied zwischen Set und List sowie die Funktionen der Hashcode-Methode und der Equals-Methode an:

package com.paddx.test.collection;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
public class SetTest {
public static void main(String[] args) {
Person p1 = new Person("lxp",10);
Person p2 = new Person("lxp",10);
Person p3 = new Person("lxp",20);
ArrayList<Person> list = new ArrayList<Person>();
list.add(p1);
System.out.println("---------");
list.add(p2);
System.out.println("---------");
list.add(p3);
System.out.println("List size=" + list.size());
System.out.println("----分割线-----");
Set<Person> set = new HashSet<Person>();
set.add(p1);
System.out.println("---------");
set.add(p2);
System.out.println("---------");
set.add(p3);
System.out.println("Set size="+set.size());
}
static class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
System.out.println("Call equals();name="+name);
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return name.equals(person.name);
}
@Override
public int hashCode() {
System.out.println("Call hashCode(),age="+age);
return age;
}
}
}

Die Ausführungsergebnisse des obigen Codes lauten wie folgt:

---------
---------
List size=3
----分割线-----
Call hashCode(),age=10
---------
Call hashCode(),age=10
Call equals();name=lxp
---------
Call hashCode(),age=20
Set size=2

Aus den Ergebnissen ist ersichtlich, dass beim Hinzufügen von Elementen zur Liste keine zusätzlichen Vorgänge ausgeführt werden und wiederholt werden können. Bevor Sie den Satz hinzufügen, müssen Sie zuerst die Methode hashCode ausführen. Wenn der zurückgegebene Wert bereits im Satz vorhanden ist, müssen Sie mit der Ausführung der Methode „equals“ fortfahren. Wenn das von der Methode „equals“ zurückgegebene Ergebnis ebenfalls wahr ist, beweist dies, dass das Element vorhanden ist Ist bereits vorhanden und wird vom neuen Element überschrieben, wenn die zurückgegebenen HashCode-Werte unterschiedlich sind, werden sie direkt zur Sammlung hinzugefügt. Denken Sie hier daran, dass für Elemente in der Sammlung Elemente mit unterschiedlichen HashCode-Werten nicht gleich sein dürfen, ungleiche Elemente jedoch möglicherweise denselben HashCode-Wert haben.

Der Unterschied zwischen HashSet und LinkedHashSet besteht darin, dass letzteres sicherstellen kann, dass die Reihenfolge der in den Satz eingefügten Elemente mit der Ausgabereihenfolge übereinstimmt. Der Unterschied zwischen TresSet besteht darin, dass es nach Comparator sortiert ist. Standardmäßig ist es in aufsteigender Reihenfolge entsprechend der natürlichen Reihenfolge der Zeichen angeordnet.

 (4)Iterable: Aus diesem Bild können Sie ersehen, dass die Collection-Klasse von Iterable erbt. Die Funktion dieser Schnittstelle besteht darin, die Funktion der Elementdurchquerung, also aller Collection-Klassen, bereitzustellen (außer der kartenbezogenen Klasse) bieten alle die Funktion der Elementdurchquerung. Iterable enthält den Iterator von Iterator. Wenn Sie mit dem Iteratormuster vertraut sind, sollte es leicht zu verstehen sein.

public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}

2. Karte:

Map类型的集合最大的优点在于其查找效率比较高,理想情况下可以实现O(1)的时间复杂度。Map中最常用的是HashMap,LinkedHashMap与HashMap的区别在于前者能够保证插入集合的元素顺序与输出顺序一致。这两者与TreeMap的区别在于TreeMap是根据键值进行排序的,当然其底层的实现也有本质的区别,如HashMap底层是一个哈希表,而TreeMap的底层数据结构是一棵树。我们现在看下TreeMap与LinkedHashMap的区别:

package com.paddx.test.collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
public class MapTest {
public static void main(String[] args) {
Map<String,String> treeMap = new TreeMap<String,String>();
Map<String,String> linkedMap = new LinkedHashMap<String, String>();
treeMap.put("b",null);
treeMap.put("c",null);
treeMap.put("a",null);
for (Iterator<String> iter = treeMap.keySet().iterator();iter.hasNext();){
System.out.println("TreeMap="+iter.next());
}
System.out.println("----------分割线---------");
linkedMap.put("b",null);
linkedMap.put("c",null);
linkedMap.put("a",null);
for (Iterator<String> iter = linkedMap.keySet().iterator();iter.hasNext();){
System.out.println("LinkedHashMap="+iter.next());
}
}
}

运行上述代码,执行结果如下:

TreeMap=a
TreeMap=b
TreeMap=c
----------分割线---------
LinkedHashMap=b
LinkedHashMap=c
LinkedHashMap=a

  从运行结果可以很明显的看出这TreeMap和LinkedHashMap的区别,前者是按字符串排序进行输出的,而后者是根据插入顺序进行输出的。细心的读者可以发现,HashMap与TreeMap的区别,与之前提到的HashSet与TreeSet的区别是一致的,在后续进行源码分析的时候,我们可以看到HashSet和TreeSet本质上分别是通过HashMap和TreeMap来实现的,所以它们的区别自然也是相同的。HashTable现在已经很少使用了,与HashMap的主要区别是HashTable是线程安全的,不过由于其效率比较低,所以通常使用HashMap,在多线程环境下,通常用CurrentHashMap来代替。

三、总结

  本文只是从整体上介绍了Java集合框架及其继承关系。除了上述类,集合还提供Collections和Arrays两个工具类,此外,集合中排序跟Comparable和Comparator紧密相关。

Das obige ist der detaillierte Inhalt vonWas ist eine Sammlungsklasse in Java? Erläuterung der Struktur der Sammlungsklasse anhand grafischer Beispiele. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn