Introduction and use of java~ collections

Uncle reprint, original address: http://www.700net.com/rewrite.php/read-4491.html 

Linear lists, linked lists, and hash tables are commonly used data structures. When developing Java, JDK has provided us with a series of corresponding classes to implement basic data structures. These classes are in the java.util package. This article attempts to explain to the reader the role of each class and how to use these classes correctly through a simple description. 

Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap

Collection interface
  Collection is the most basic collection interface. A Collection represents a group of Objects, that is, the elements of the Collection. Some Collections allow the same elements while others do not. Some sort and others don't. The Java SDK does not provide classes that inherit directly from Collection. The classes provided by the Java SDK are all "sub-interfaces" that inherit from Collection, such as List and Set.
  All classes that implement the Collection interface must provide two standard constructors: the parameterless constructor is used to create an empty Collection, and the constructor with a Collection parameter is used to create a new Collection, the new Collection and the passed The incoming Collection has the same elements. The latter constructor allows the user to copy a Collection.
  How to iterate through each element in the Collection? Regardless of the actual type of the Collection, it supports an iterator() method that returns an iterator that can be used to access each element in the Collection one by one. Typical usage is as follows:
    Iterator it = collection.iterator(); // get an iterator
    while(it.hasNext()) {
      Object obj = it.next(); // get the next element
    }
  derived from the Collection interface The two interfaces are List and Set.

List interface
  List is an ordered Collection, using this interface can precisely control the insertion position of each element. The user can use the index (the element's position in the List, similar to the array subscript) to access the elements in the List, which is similar to the Java array.
Unlike Set, which will be mentioned below, List is allowed to have the same elements.
  In addition to the iterator() method that is necessary for the Collection interface, List also provides a listIterator() method that returns a ListIterator interface. Compared with the standard Iterator interface, ListIterator has some add() and other methods that allow adding, Delete, set elements, and traverse forward or backward.
  Common classes that implement the List interface are LinkedList, ArrayList, Vector and Stack.

The LinkedList class
  LinkedList implements the List interface, allowing null elements. In addition, LinkedList provides additional get, remove, and insert methods at the head or tail of LinkedList. These operations allow LinkedList to be used as a stack, queue or deque.
  Note that LinkedList has no synchronized methods. If multiple threads access a List at the same time, you must implement access synchronization yourself. A workaround is to construct a synchronized List when the List is created:
    List list = Collections.synchronizedList(new LinkedList(...));

ArrayList class
  ArrayList implements variable size arrays. It allows all elements, including null. ArrayList is not synchronized.
The running time of size, isEmpty, get, set methods is constant. However, the overhead of the add method is amortized constant, and adding n elements takes O(n) time. Other methods run linearly.
  Each ArrayList instance has a capacity (Capacity), which is the size of the array used to store elements. This capacity can be automatically increased as new elements are added, but the growth algorithm is not defined. When a large number of elements need to be inserted, the ensureCapacity method can be called before insertion to increase the capacity of the ArrayList to improve the insertion efficiency.
  Like LinkedList, ArrayList is also unsynchronized.

The Vector class
  Vector is very similar to ArrayList, but Vector is synchronized. The Iterator created by Vector is the same interface as the Iterator created by ArrayList, but because Vector is synchronous, when an Iterator is created and is being used, another thread changes the state of the Vector (for example, adding or removing some element), a ConcurrentModificationException will be thrown when the method of the Iterator is called, so this exception must be caught.

The Stack class
  Stack inherits from Vector and implements a LIFO stack. Stack provides 5 additional methods that allow Vector to be used as a stack. The basic push and pop methods, as well as the peek method, get the element at the top of the stack, the empty method tests whether the stack is empty, and the search method checks the position of an element on the stack. The stack is an empty stack just after it is created.

Set interface
  Set is a Collection that does not contain duplicate elements, that is, any two elements e1 and e2 have e1.equals(e2)=false, and Set has at most one null element.
  Obviously, the constructor of Set has a constraint that the incoming Collection parameter cannot contain duplicate elements.
  Note: Mutable Objects must be handled with care. If a mutable element in a Set changes its state causing Object.equals(Object)=true will cause some problems.

Map interface
  Please note that Map does not inherit the Collection interface, Map provides key to value mapping. A Map cannot contain the same key, and each key can only map one value. The Map interface provides three sets of views. The contents of the Map can be regarded as a set of key sets, a set of value sets, or a set of key-value mappings.

The Hashtable class
  Hashtable inherits the Map interface and implements a hash table with key-value mapping. Any non-null object can be used as key or value.
  Use put(key, value) to add data and get(key) to retrieve data. The time overhead of these two basic operations is constant.
Hashtable adjusts performance through two parameters, initial capacity and load factor. Usually the default load factor of 0.75 achieves a better balance between time and space. Increasing the load factor can save space but the corresponding lookup time will increase, which affects operations like get and put.
A simple example of using Hashtable is as follows, put 1, 2, and 3 into Hashtable, and their keys are "one", "two", "three":
    Hashtable numbers = new Hashtable();
    numbers.put("one" , new Integer(1));
    numbers.put("two", new Integer(2));
    numbers.put("three", new Integer(3));
  To take out a number, such as 2, use the corresponding key :
    Integer n = (Integer)numbers.get("two");
    System.out.println("two = " + n);
  Since the object used as the key will determine the location of the value corresponding to it by calculating its hash function, any object used as the key must implement the hashCode and equals methods. The hashCode and equals methods are inherited from the root class Object. If you use a custom class as the key, be very careful. According to the definition of the hash function, if the two objects are the same, that is, obj1.equals(obj2)=true, then Their hashCode must be the same, but if the two objects are different, their hashCode is not necessarily different. If the hashCode of two different objects is the same, this phenomenon is called conflict, and the conflict will increase the time overhead of operating the hash table. So try to define a good hashCode() method to speed up the operation of the hash table.
  If the same object has different hashCode, the operation of the hash table will have unexpected results (the expected get method returns null). To avoid this problem, you only need to keep one thing in mind: to override the equals method and the hashCode method at the same time, And don't just write one of them.
  Hashtable is synchronous.

HashMap class
  HashMap is similar to Hashtable, the difference is that HashMap is asynchronous and allows null, that is, null value and null key. , but when HashMap is regarded as a Collection (the values() method can return a Collection), the time overhead of its iteration sub-operation is proportional to the capacity of HashMap. Therefore, if the performance of the iterative operation is very important, do not set the initialization capacity of the HashMap too high, or the load factor is too low.

WeakHashMap class
  WeakHashMap is an improved HashMap, which implements a "weak reference" to the key. If a key is no longer externally referenced, the key can be recycled by GC.

Summary
  If operations such as stacks and queues are involved, you should consider using List. If you need to insert and delete elements quickly, you should use LinkedList. If you need to access elements quickly and randomly, you should use ArrayList.
  If the program is in a single-threaded environment, or the access is only performed in one thread, consider the asynchronous class, which is more efficient. If multiple threads may operate a class at the same time, the synchronized class should be used.
  Special attention should be paid to the operation of the hash table, and the equals and hashCode methods should be correctly overridden for the key object.
  Try to return the interface instead of the actual type, such as returning List instead of ArrayList, so that if you need to replace ArrayList with LinkedList in the future, the client code does not need to be changed. This is programming for abstraction.

Synchronization
Vectors are synchronized. Several methods in this class ensure that objects in Vector are thread-safe. The ArrayList is asynchronous, so the objects in the ArrayList are not thread-safe. Because synchronization requirements affect the efficiency of execution, using ArrayList is a good choice if you don't need thread-safe collections, which avoids unnecessary performance overhead due to synchronization.

Data growth
From the internal implementation mechanism, ArrayList and Vector both use an array (Array) to control the objects in the collection. When you add elements to these two types, if the number of elements exceeds the current length of the internal array, they all need to expand the length of the internal array. Vector automatically doubles the length of the original array by default. ArrayList is the original 50%, so you end up with this set that always takes up more space than you actually need. So if you're going to hold a lot of data in a collection then using a Vector has some advantages because you can avoid unnecessary resource overhead by setting the initial size of the collection.

Usage pattern
In ArrayList and Vector, it takes the same amount of time to find data from a specified position (by index) or to add or remove an element from the end of the collection, which we express as O(1). However, adding or removing elements elsewhere in the collection takes a linear increase in time: O(ni), where n is the number of elements in the collection and i is the index position at which the element was added or removed. Why is this so? It is thought that when the above operation is performed, all elements after the i-th and i-th elements in the collection must perform the displacement operation. What does all this mean?

This means, if you're just looking for elements at a specific position or just adding and removing elements at the end of the collection, either a Vector or an ArrayList will work. For other operations, you'd better choose another collection operation class. For example, the LinkList collection class takes the same amount of time to add or remove an element anywhere in the collection - O(1), but it is slower to index an element - O(i), where i is The position of the index. Using an ArrayList is also easy because you can simply use the index instead of creating an iterator object. LinkList also creates objects for each inserted element, so you have to understand that it also brings additional overhead.

Finally, in Practical Java, Peter Haggar suggests using a simple Array instead of Vector or ArrayList. This is especially true for programs that require high execution efficiency. Because using an Array avoids synchronization, extra method calls, and unnecessary reallocations.

In-depth analysis of the use of Vector, ArrayList, and List in Java - Programmer Sought

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324865634&siteId=291194637