Kürzlich habe ich eine sehr gute Beschreibung des Sammlungsframeworks in einem J2EE-Buch gesehen. Nachdem ich es gefiltert habe, stellt es Schnittstellen und Klassen für die Verwaltung von Objektsammlungen bereit Das Folgende ist eine Beschreibung seiner verschiedenen Komponenten.
Collection-Schnittstelle
Collection ist die grundlegendste Collection-Schnittstelle, die eine Gruppe von Objekten darstellt, also die Elemente der Collection. Einige Sammlungen erlauben identische Elemente, andere nicht. Manche sortieren, andere nicht. Das Java SDK stellt keine Klassen bereit, die direkt von Collection erben. Die vom Java SDK bereitgestellten Klassen sind alle „Unterschnittstellen“, die von Collection erben, wie z. B. List und Set.
Alle Klassen, die die Collection-Schnittstelle implementieren, müssen zwei Standardkonstruktoren bereitstellen: Der parameterlose Konstruktor wird zum Erstellen einer leeren Collection verwendet, und der Konstruktor mit einem Collection-Parameter wird zum Erstellen einer neuen Collection verwendet. Diese neue Collection enthält dieselben Elemente wie die übergebene Sammlung. Der letztere Konstruktor ermöglicht dem Benutzer das Kopieren einer Sammlung.
Wie durchläuft man jedes Element in der Sammlung? Unabhängig vom tatsächlichen Typ der Sammlung unterstützt sie eine iterator()-Methode, die einen Iterator zurückgibt, mit dem nacheinander auf jedes Element in der Sammlung zugegriffen werden kann. Typische Verwendung ist wie folgt:
Iterator it = collection.iterator(); // 获得一个迭代子 while(it.hasNext()) { Object obj = it.next(); // 得到下一个元素 }
Die beiden von der Collection-Schnittstelle abgeleiteten Schnittstellen sind List und Set.
Listenschnittstelle
Liste ist eine geordnete Sammlung. Mit dieser Schnittstelle können Sie die Einfügeposition jedes Elements genau steuern. Benutzer können über den Index (die Position des Elements in der Liste, ähnlich einem Array-Index), der dem Java-Array ähnelt, auf Elemente in der Liste zugreifen.
Im Gegensatz zum unten erwähnten Set erlaubt List die gleichen Elemente.
Zusätzlich zu der für die Collection-Schnittstelle erforderlichen iterator()-Methode bietet List auch eine listIterator()-Methode, die eine ListIterator-Schnittstelle zurückgibt. Im Vergleich zur Standard-Iterator-Schnittstelle verfügt ListIterator über einige weitere Methoden wie add(). Ermöglicht das Hinzufügen, Löschen und Festlegen von Elementen sowie das Vorwärts- und Rückwärtsfahren.
Zu den gängigen Klassen, die die List-Schnittstelle implementieren, gehören LinkedList, ArrayList, Vector und Stack.
LinkedList-Klasse
LinkedList implementiert die List-Schnittstelle und lässt Nullelemente zu. Darüber hinaus stellt LinkedList zusätzliche Get-, Remove- und Insert-Methoden am Anfang oder Ende von LinkedList bereit. Diese Operationen ermöglichen die Verwendung von LinkedList als Stack, Warteschlange oder Deque.
Beachten Sie, dass LinkedList keine Synchronisierungsmethoden hat. Wenn mehrere Threads gleichzeitig auf eine Liste zugreifen, müssen sie die Zugriffssynchronisierung selbst implementieren. Eine Lösung besteht darin, beim Erstellen der Liste eine synchronisierte Liste zu erstellen:
List list = Collections.synchronizedList(new LinkedList(...));
ArrayList class
ArrayList implementiert ein Array variabler Größe. Es erlaubt alle Elemente, einschließlich null. ArrayList ist nicht synchronisiert.
Die Laufzeit der Methoden size, isEmpty, get und set ist konstant. Allerdings sind die Kosten der Add-Methode eine amortisierte Konstante, und das Addieren von n Elementen erfordert O(n) Zeit. Andere Methoden haben eine lineare Laufzeit.
Jede ArrayList-Instanz verfügt über eine Kapazität (Capacity), die der Größe des Arrays entspricht, das zum Speichern von Elementen verwendet wird. Diese Kapazität erhöht sich automatisch, wenn neue Elemente hinzugefügt werden, der Wachstumsalgorithmus ist jedoch nicht definiert. Wenn eine große Anzahl von Elementen eingefügt werden muss, kann die Methode „sichsureCapacity“ aufgerufen werden, um die Kapazität der ArrayList vor dem Einfügen zu erhöhen und so die Einfügeeffizienz zu verbessern.
Wie LinkedList ist auch ArrayList nicht synchronisiert.
Vector-Klasse
Vector ist ArrayList sehr ähnlich, aber Vector ist synchronisiert. Obwohl der von Vector erstellte Iterator dieselbe Schnittstelle hat wie der von ArrayList erstellte Iterator, da Vector synchronisiert ist, ändert ein anderer Thread den Status des Vectors, wenn ein Iterator erstellt und verwendet wird (z. B. indem ein Element hinzugefügt oder entfernt wird). , ConcurrentModificationException wird beim Aufruf der Iterator-Methode ausgelöst, daher muss die Ausnahme abgefangen werden.
Stack-Klasse
Stack erbt von Vector und implementiert einen Last-In-First-Out-Stack. Stack bietet 5 zusätzliche Methoden, mit denen Vector als Stack verwendet werden kann. Die grundlegenden Push- und Pop-Methoden sowie die Peek-Methode holen sich das Element oben im Stapel, die leere Methode testet, ob der Stapel leer ist, und die Suchmethode erkennt die Position eines Elements im Stapel. Der Stapel ist nach seiner Erstellung ein leerer Stapel.
Set-Schnittstelle
Set ist eine Sammlung, die keine doppelten Elemente enthält, d. h. zwei beliebige Elemente e1 und e2 haben e1.equals(e2)=false und Set hat höchstens ein Nullelement.
Offensichtlich unterliegt der Set-Konstruktor der Einschränkung, dass der übergebene Collection-Parameter keine doppelten Elemente enthalten darf.
Bitte beachten Sie: Mit veränderlichen Objekten muss vorsichtig umgegangen werden. Wenn ein veränderliches Element in einem Set seinen Zustand ändert und Object.equals(Object)=true verursacht, führt dies zu einigen Problemen.
Map-Schnittstelle
Bitte beachten Sie, dass Map nicht die Collection Map erbt, die den Schlüssel zur Wertezuordnung bereitstellt. Eine Map kann nicht denselben Schlüssel enthalten und jeder Schlüssel kann nur einen Wert zuordnen. Die Map-Schnittstelle bietet drei Arten von Satzansichten. Der Inhalt der Karte kann als Satz von Schlüsselsätzen, als Satz von Wertsätzen oder als Satz von Schlüsselwertzuordnungen betrachtet werden.
Hashtable-Klasse
Hashtable erbt die Map-Schnittstelle und implementiert eine Hash-Tabelle für die Schlüsselwertzuordnung. Als Schlüssel oder Wert kann jedes Nicht-Null-Objekt verwendet werden.
Um Daten hinzuzufügen, verwenden Sie put(key, value) und um Daten zu entfernen, verwenden Sie get(key). Der Zeitaufwand dieser beiden Grundoperationen ist konstant.
Hashtable passt die Leistung über zwei Parameter an: Anfangskapazität und Auslastungsfaktor. Normalerweise erreicht der Standardlastfaktor 0,75 ein besseres Gleichgewicht zwischen Zeit und Raum. Durch Erhöhen des Auslastungsfaktors kann Platz gespart werden, die entsprechende Suchzeit erhöht sich jedoch, was sich auf Vorgänge wie „Abrufen“ und „Put“ auswirkt.
Ein einfaches Beispiel für die Verwendung von Hashtable ist wie folgt: Geben Sie 1, 2 und 3 in die Hashtable ein, und ihre Schlüssel sind jeweils „eins“, „zwei“ und „drei“:
Hashtable numbers = new Hashtable(); numbers.put(“one”, new Integer(1)); numbers.put(“two”, new Integer(2)); numbers.put(“three”, new Integer(3));
要取出一个数,比如2,用相应的key:
Integer n = (Integer)numbers.get(“two”);
System.out.println(“two = ” + n);
由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作为key的对象都必须实现hashCode和equals方法。hashCode和equals方法继承自根类Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希表的操作。
如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个。
Hashtable是同步的。
HashMap类
HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key。,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。
WeakHashMap类
WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。
总结
如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。
如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。
要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。
尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象编程。
更多java集合框架的体系结构详细说明相关文章请关注PHP中文网!