Récemment, j'ai vu une très bonne description du framework de collection dans un livre J2EE. Après l'avoir filtré, je l'ai posté pour le partager avec tout le monde. Le framework de collection fournit des interfaces et des classes pour gérer les collections d'objets. , Ce qui suit est une description de ses différents composants.
Interface de collection
Collection est l'interface de collection la plus basique. Une collection représente un groupe d'objets, c'est-à-dire les éléments de la collection. Certaines collections autorisent des éléments identiques et d’autres non. Certains le font et d'autres non. Le SDK Java ne fournit pas de classes héritant directement de Collection. Les classes fournies par le SDK Java sont toutes des « sous-interfaces » qui héritent de Collection, telles que List et Set.
Toutes les classes qui implémentent l'interface Collection doivent fournir deux constructeurs standards : le constructeur sans paramètre est utilisé pour créer une Collection vide, et le constructeur avec un paramètre Collection est utilisé pour créer une nouvelle Collection. Cette nouvelle Collection a les mêmes éléments que. la collection passée. Ce dernier constructeur permet à l'utilisateur de copier une collection.
Comment parcourir chaque élément dans Collection ? Quel que soit le type réel de Collection, il prend en charge une méthode iterator(), qui renvoie un itérateur pouvant être utilisé pour accéder à chaque élément de la Collection un par un. L'utilisation typique est la suivante :
Iterator it = collection.iterator(); // 获得一个迭代子 while(it.hasNext()) { Object obj = it.next(); // 得到下一个元素 }
Les deux interfaces dérivées de l'interface Collection sont List et Set.
Interface de liste
La liste est une collection ordonnée En utilisant cette interface, vous pouvez contrôler avec précision la position d'insertion de chaque élément. Les utilisateurs peuvent accéder aux éléments de la liste à l'aide de l'index (la position de l'élément dans la liste, similaire à un indice de tableau), qui est similaire à un tableau Java.
Contrairement au Set mentionné ci-dessous, List autorise les mêmes éléments.
En plus de la méthode iterator() nécessaire à l'interface Collection, List fournit également une méthode listIterator(), qui renvoie une interface ListIterator. Par rapport à l'interface Iterator standard, ListIterator a quelques méthodes supplémentaires telles que add(). Permet d'ajouter, de supprimer, de définir des éléments et de se déplacer vers l'avant ou vers l'arrière.
Les classes courantes qui implémentent l'interface List incluent LinkedList, ArrayList, Vector et Stack.
Classe LinkedList
LinkedList implémente l'interface List et autorise les éléments nuls. De plus, LinkedList fournit des méthodes supplémentaires d'obtention, de suppression et d'insertion en tête ou à la fin de LinkedList. Ces opérations permettent à LinkedList d'être utilisée comme pile, file d'attente ou deque.
Notez que LinkedList n'a pas de méthodes de synchronisation. Si plusieurs threads accèdent à une liste en même temps, ils doivent implémenter eux-mêmes la synchronisation des accès. Une solution consiste à construire une liste synchronisée lors de la création de la liste :
List list = Collections.synchronizedList(new LinkedList(...));
ArrayList class
ArrayList implémente un tableau de taille variable. Il autorise tous les éléments, y compris null. ArrayList n'est pas synchronisé.
Le temps d'exécution des méthodes size, isEmpty, get et set est constant. Cependant, le coût de la méthode add est une constante amortie et l’ajout de n éléments nécessite un temps O(n). D'autres méthodes ont une durée d'exécution linéaire.
Chaque instance d'ArrayList a une capacité (Capacity), qui est la taille du tableau utilisé pour stocker les éléments. Cette capacité augmente automatiquement à mesure que de nouveaux éléments sont ajoutés, mais l'algorithme de croissance n'est pas défini. Lorsqu'un grand nombre d'éléments doivent être insérés, la méthode EnsureCapacity peut être appelée pour augmenter la capacité de l'ArrayList avant l'insertion afin d'améliorer l'efficacité de l'insertion.
Comme LinkedList, ArrayList est également non synchronisée.
Classe Vector
Vector est très similaire à ArrayList, mais Vector est synchronisé. Bien que l'itérateur créé par Vector ait la même interface que l'itérateur créé par ArrayList, étant donné que Vector est synchronisé, lorsqu'un itérateur est créé et utilisé, un autre thread modifie l'état du vecteur (par exemple, en ajoutant ou en supprimant un élément). , ConcurrentModificationException sera levée lors de l'appel de la méthode Iterator, l'exception doit donc être interceptée.
Classe Stack
Stack hérite de Vector et implémente une pile dernier entré, premier sorti. Stack fournit 5 méthodes supplémentaires qui permettent d'utiliser Vector comme pile. Les méthodes de base push et pop, ainsi que la méthode peek, placent l'élément en haut de la pile, la méthode vide teste si la pile est vide et la méthode de recherche détecte la position d'un élément dans la pile. La pile est une pile vide après sa création.
Interface Set
Set est une collection qui ne contient pas d'éléments en double, c'est-à-dire que deux éléments e1 et e2 ont e1.equals(e2)=false et Set a au plus un élément nul.
Évidemment, le constructeur Set a une contrainte selon laquelle le paramètre Collection transmis ne peut pas contenir d'éléments en double.
Veuillez noter : les objets mutables doivent être manipulés avec soin. Si un élément mutable dans un Set change d'état, provoquant Object.equals(Object)=true, cela entraînera des problèmes.
Interface Map
Veuillez noter que Map n'hérite pas de l'interface Collection Map fournit un mappage clé-valeur. Une Map ne peut pas contenir la même clé et chaque clé ne peut mapper qu’une seule valeur. L'interface Map propose trois types de vues d'ensemble. Le contenu de la carte peut être considéré comme un ensemble d'ensembles de clés, un ensemble d'ensembles de valeurs ou un ensemble de mappages clé-valeur.
Classe Hashtable
Hashtable hérite de l'interface Map et implémente une table de hachage de mappage clé-valeur. Tout objet non nul peut être utilisé comme clé ou valeur.
Pour ajouter des données, utilisez put(key, value) et pour supprimer des données, utilisez get(key). Le coût en temps de ces deux opérations de base est constant.
Hashtable ajuste les performances via deux paramètres : la capacité initiale et le facteur de charge. Habituellement, le facteur de charge par défaut de 0,75 permet d'obtenir un meilleur équilibre entre le temps et l'espace. L'augmentation du facteur de charge peut économiser de l'espace, mais le temps de recherche correspondant augmentera, ce qui affectera les opérations telles que l'extraction et la mise en place.
Un exemple simple d'utilisation de Hashtable est le suivant. Mettez 1, 2 et 3 dans la table de hachage, et leurs clés sont respectivement "un", "deux" et "trois" :
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中文网!