Advantages and disadvantages of arrays and collections
Advantages of arrays | Disadvantages of arrays |
---|---|
Simple definition and quick access | Immutable length after initialization |
After definition, the type is single | |
The methods provided are limited, inconvenient to insert, delete and other operations, and the efficiency is not high | |
There is no method to get the actual elements of the array | |
Continuous storage space is required. For more elements, a large continuous space needs to be opened up |
Advantages of set | |
---|---|
Dynamically save multiple objects with variable length | |
Multiple type elements can be saved | |
Provide methods for operating object elements, such as add, remove, set, get, etc |
Collection
Only common collections are listed here
Collection features
-
collection implementation subclasses store elements that are object objects and will be automatically boxed
-
If you do not use generics, the object object is returned by default
List list = new ArrayList();//Since the interface cannot be instantiated, the ArrayList class is used to implement the interface list.add(1);//Automatic packing, storing integer object list add(new (Integer(1))) list.add("tom"); list.add(true);
Collection common methods
-
Add: add a single element
-
remove: deletes a single element
-
contains: find whether a single element exists
-
size: get the number of elements
-
isEmpty: judge whether it is empty
-
Clear: clear
-
addAll: add multiple elements (first store the elements in the collection, and then use this method to add the collection)
-
containsAll: find whether multiple elements exist (also through collection operation)
-
removeAll: delete multiple elements (through collection operations)
Collection iterative traversal
Iterator object iterator
Iterator object iterator in iteratable, all collections implement this method; Two main methods are used:
- hasNext: judge whether the next element exists
- Next: take out the next element
Before using next, you must call hasNext to determine whether the next element exists. If it is not called and the next piece of data is empty, an exception will be thrown.
Iterator<Object> iterator = list.iterator(); while (iterator.hasNext()){ //Return the element object, Object obj = iterator.next(); System.out.println(obj); }
Enhanced for loop
for (Object obj:list){ System.out.println(obj); }
-
Is the underlying Iterator
-
Can be understood as a simplified version of the iterator
Normal for loop
for (int i=0;i<list.size();i++){ Object obj = list.get(i); System.out.println(obj); }
List
List is also an interface. Here, the ArrayList class is used to implement the interface
characteristic
-
List collection elements are ordered and repeatable
List<Object> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(1); System.out.println(list); Output:[1, 2, 3, 4, 1]
-
Each element of List has a corresponding index, which supports index operation. The index starts from 0
List<Object> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(1); System.out.println(list.get(3)); Output: 4
List common methods
-
Add (object): add an element
-
add (int index, Object obj): insert the element obj where the index is the index
List<Object> list = new ArrayList<>(); list.add(0); list.add(1); list.add(2); list.add(3); list.add(1,100); System.out.println(list); Output:[0, 100, 1, 2, 3]
-
addAll (Collection eles): add multiple elements (first store the elements in the collection, and then use this method to add the collection)
-
addAll (int index, Collection eles): inserts elements in the Collection eles at the index position
-
Get (int index): get the element at the index position
-
indexOf (object obj): returns the position where obj first appears in the collection
-
lastIndexOf (object obj): returns the location of the last occurrence of obj in the collection
-
remove (int index): removes the element at the index position and returns it
-
set (int index, object obj): replace the Suntech element at the index position with obj, and the index must exist
-
subList (int fromIndex, int toIndex): returns a substring, closed on the left and open on the right [fromIndex,toIndex)
ArrayList
characteristic
-
Multiple null s can be placed
List<Object> list = new ArrayList<>(); list.add(null); list.add(null); list.add(2); System.out.println(list); Output:[null, null, 2]
-
The bottom layer is implemented by array
-
ArrayList is basically equivalent to Vector, but ArrayList is thread unsafe and is not decorated with synchronized (high execution efficiency because thread safety is not considered),
-
ArrayList is not recommended for multilinear applications
ArrayList capacity expansion mechanism (key)
-
An array of Object type is used to store objects in ArrayList
transient Object[] elementData; //The transient modifier indicates that the property will not be serialized
-
When creating an ArrayList object, if a parameterless constructor is used, initialize the array size to 0, add elements for the first time, expand the array capacity to 10, and each subsequent expansion is 1.5 times the previous one
List list = new ArrayList();//Initialization size is 0
-
If the parameterized constructor of the specified size is used directly, the initialization array size will be the specified size, and each subsequent expansion will be 1.5 times the previous one
List list = new ArrayList(5);//The initialization size is the specified 5
Nonparametric construction source code
-
Initialize the array and create the elementData array
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//The array is empty, that is, the size is 0
-
Execute add
//Type packing operation. Different types correspond to different packing classes public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
-
First determine whether the array capacity is sufficient
private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }
-
If the capacity is insufficient, call grow to expand the capacity
private void ensureExplicitCapacity(int minCapacity) { modCount++; if (minCapacity - elementData.length > 0) grow(minCapacity); }
private void grow(int minCapacity) { int oldCapacity = elementData.length; //The first oldCapacity=0 int newCapacity = oldCapacity + (oldCapacity >> 1); //1.5x capacity expansion if (newCapacity - minCapacity < 0) //If the first expansion newCapacity=0 newCapacity = minCapacity; //The expansion result is minCapacity=10 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); //When the array is expanded to the size of newCapacity, copyOf will retain the original data }
Vector
characteristic
-
Multiple null s can be placed
-
The bottom layer is also an array
-
Vector is thread synchronization, that is, thread safety (low efficiency). The vector operation method has the synchronized keyword
public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; }
Capacity expansion mechanism
- If the parameterless constructor is used, the initialization array size is 10, and the subsequent capacity expansion is twice that of the previous one. The incremental size can be changed in the constructor
- If you directly use a parameterized constructor of the specified size, the initialization array size is the specified size, and each subsequent expansion is twice the previous size. You can change the incremental size in the constructor
LinkedList
characteristic
- The bottom layer implements two-way linked list and two end queue
- Thread is unsafe and thread synchronization is not implemented
- Adding and deleting does not require array expansion and is efficient
LinkedList underlying operation mechanism
-
The underlying LinkedList maintains a two-way linked list
-
Maintain two nodes, first and last, pointing to the first node and the tail node respectively
-
Each Node (Node object) maintains three attributes: prev, next and item
-
prev goes straight to the previous node, and next points to the next node. Finally, the two-way linked list is realized
LinkedList method
-
add (object): tail interpolation, inserting objects
-
add (int index, object obj): insert the obj element where the index is the subscript
List list = new LinkedList(); list.add(0); list.add(1); list.add(2); list.add(3); list.add(3,10); System.out.println(list); Output:[0, 1, 2, 10, 3]
-
set (int index, object obj): change the location element with index as the subscript to the obj element
List list = new LinkedList(); list.add(0); list.add(1); list.add(2); list.add(3); list.set(2,"obj"); System.out.println(list); Output:[0, 1, obj, 3]
-
remove (int index): delete the element with index as the subscript
-
remove (object obj): delete the element whose object is obj. If there are multiple obj, delete the first one
-
Get (int index): get the element with index as the subscript
-
. . .
ArrayList and LinkedList comparison
Bottom structure | Addition and deletion efficiency | Modification efficiency | |
---|---|---|---|
ArrayList | array | Array expansion, low | higher |
LinkedList | Bidirectional linked list | Operation node pointer, high | Lower |
How to choose
-
Select ArrayList instead of multiple queries
-
To add or delete more, select LinkedList
-
Generally speaking, 80% - 90% are queries, so most of them choose ArrayList
Set
HashSet
characteristic
-
Out of order (inconsistent order of addition and extraction), no index
-
For the same set of data, no matter how the addition order changes, the output order is fixed (sorted internally according to the hash value)
-
Duplicate elements are not allowed, so it can contain at most one null
Set set = new HashSet(); set.add(1); set.add(3); set.add("jack"); set.add("jack"); //The same element cannot be added. There is jack in the constant pool set.add(new Dog("tom")); set.add(4); set.add(new Dog("tom")); // Different objects have different addresses, so they can be added set.add(null); set.add(2); set.add(new String("lucy")); set.add(new String("lucy")); //Cannot add System.out.println(set); Output:[null, 1, 2, 3, Dog{name='tom'}, 4, Dog{name='tom'}, lucy, jack]
-
The bottom layer of HashSet is implemented by HashMap, while the bottom layer of HashMap is implemented by array + linked list + red black tree
public HashSet() { map = new HashMap<>(); }
Set common methods
Like the List interface, the Set interface is also a sub interface of the Collection. Therefore, the common methods are the same as the Collection interface
Iterative method
- You can use iterators
- Enhanced for loop (essentially an iterator)
Set has no index, so it cannot be iterated with ordinary index for loop
Why can't the same element be added
-
The bottom layer of HashSet is HashMap
-
When adding an element, first get the hash value, and then turn it into an index
-
Find the storage data table table and see whether the index position has stored elements. If not, it will be directly added to the index position
-
If there are elements in the index position, the equals comparison will be called. If the comparison results are the same, the addition will be abandoned. Otherwise, the elements will be added after the linked list of the index position
-
In jdk8, if the length of the linked list is equal to 8 and the length of the array table is equal to 64, it will be converted to a red black tree
Add element source code analysis
Set set = new HashSet(); set.add("tom"); set.add("jack"); set.add("jack");
-
Execute HashSet()
public HashSet() { map = new HashMap<>(); }
-
Execute the add () method
public boolean add(E e) { // e = "tom" return map.put(e, PRESENT)==null; //(static) PRESENT=new Object() }
-
Execute the put() method. If the return value is empty, it means that the location is empty and the object can be placed. If the return value is not empty, it means that there is an object in the location and its value is equal to that of the object, and the object cannot be placed
public V put(K key, V value) { //Key = "Tom" value = present (present has no practical meaning and occupies space) return putVal(hash(key), key, value, false, true); }
-
Execute the hash () method to get the hash value corresponding to the key, not the hashcode value.
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); //Get the hashcode value, and then move 16 bits to the right without sign to prevent conflict }
-
Execute the putVal () method to the hash value of the key
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; //Define auxiliary variables //If the current tab is empty or the size is 0, the tab array reaches 16 for the first expansion if ((tab = table) == null || (n = tab.length) == 0) //table is the array length, an attribute of HashMap n = (tab = resize()).length; //According to the hash value obtained from the key, calculate the index position where the key should be placed in the table, and assign this position object to p //If p is empty, it means that there is no data stored in the index location. Create a node and save the value if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); //If p is not empty, it indicates that there is data at the index position else { Node<K,V> e; K k; //If the first element of the linked list corresponding to the current index position is equal to the hash value of the key to be added //In addition, if the current node object and key are the same object, or if equals is equal, equals is rewritten by the programmer //You cannot join if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; //Then judge whether p is a red black tree //If it is a red black tree, call the putTreeVal () method to add else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); //If the location is already a linked list, use the for loop to determine whether there is a repetition else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); //After adding, judge whether the length of the linked list reaches 8. If so, the linked list at this position will be converted to red black tree operation //However, the treeifyBin method will judge whether the length of the table array reaches 64. Otherwise, the table array will be expanded first, and the object will still be placed behind the linked list (at this time, the length of the linked list has exceeded 8) if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; //Determine whether capacity expansion is required if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
HashSet capacity expansion mechanism
- The HashMap is at the bottom of the HashSet. When it is added for the first time, the table array is expanded to 16, and the threshold is 16 * the loadFactor is 0.75 = 12. Here, 12 is not the length of the table, but the total number of elements in the HashSet
- If the number of elements reaches 12, the table array will double to 32, and the new critical value is 32 * 0.75 = 24, and so on
- In jdk8, if the number of elements in a linked list reaches YREEIFY_THRESHOLD (8 by default), the red black tree conversion operation will be started. However, when converting to the red black tree treeifyBin() method, it will first judge whether the table reaches 64. If it reaches 64, it will be converted to the red black tree. Before reaching 64, expand the capacity of the table array first, and the object will still be placed behind the linked list (at this time, the length of the linked list has exceeded 8)
LinkedHashSet
LinkedHashSet features
- LinkedHashSet is a subclass of HashSet. The underlying layer is LinkedHashMap. The underlying layer maintains an array + two-way linked list
- The LinkedHashSet element determines the storage location of the element according to the hashcode value. At the same time, the linked list is used to maintain the element order, so that the element insertion and output order are consistent
- LinkedHashSet does not allow inserting duplicate elements
TreeSet
characteristic
-
The bottom layer is TreeMap
-
When created with a parameterless constructor, dictionary sorting is used by default
TreeSet treeSet = new TreeSet(); treeSet.add("jack"); treeSet.add("tom"); treeSet.add("lucy"); treeSet.add("marry"); System.out.println(treeSet); Output:[jack, lucy, marry, tom]
-
Using the Comparator builder, you can change the collation
TreeSet treeSet = new TreeSet(new Comparator() { @Override public int compare(Object o1, Object o2) { //According to the dictionary from small to large, the sorting order can be changed by changing the order of o1 and o2 return ((String)o2).compareTo((String)o1); } }); treeSet.add("jack"); treeSet.add("tom"); treeSet.add("lucy"); treeSet.add("marry"); System.out.println(treeSet); Output:[tom, marry, lucy, jack]
-
If you sort by string length, you cannot add strings of the same length
TreeSet treeSet = new TreeSet(new Comparator() { @Override public int compare(Object o1, Object o2) { return ((String)o2).length()-((String)o1).length(); } }); treeSet.add("jack"); treeSet.add("tom"); treeSet.add("lucy"); //Same length, cannot add treeSet.add("marry"); System.out.println(treeSet); Output:[marry, jack, tom]
Map
HashMap
HashMap features (JDK8)
-
The Map structure is a key value pair
-
key and value can be data (object s) of any reference type, encapsulated in the node node
Map<Object, Object> map = new HashMap<>();
-
Duplicate keys cannot be added (essentially hashcode). When the same key is added repeatedly, the value in the key will be replaced, so the key can only be null at one time
-
Duplicate value values can be added, so multiple values can be added to be null
-
A pair of k-v is placed in the node node in the HashMap, and the node implements the Entry interface
-
Entry provides getKey () and getValue () methods for traversal convenience
-
Like HashSet, the mapping order is not guaranteed, because the bottom layer is stored in the form of hash table, and the bottom layer of HashMap (array + linked list + red black tree)
-
HashMap does not achieve synchronization, so it is thread unsafe. The method does not perform synchronization and mutual exclusion
Common methods of HashMap interface
- Put (object key, object value): adds a key value pair element
- remove (object key): removes the element whose key value is key and returns the object
- Get (object key): get the object whose key value is key
- Size (): get the map size
- Clear (): clear the map
- containsKey (object key): judge whether the object with key value exists
- containsValue (object value): judge whether the object with value value exists
Six traversal methods of HashMap
Map map = new HashMap(); map.put("A", "a"); map.put("B", "b"); map.put("C", "c"); map.put("D", "d");
-
First take out all the keys, save the keys in the set, and then take out the corresponding value through the key
Set keySet = map.keySet(); //(1) Enhanced for for (Object key : keySet) { System.out.println(map.get(key)); } //(2) Iterator Iterator iterator = keySet.iterator(); while(iterator.hasNext()){ Object next = iterator.next(); System.out.println(next); }
-
Take out all value s and put them in the Collection
Collection values = map.values(); //(1) Enhanced for for (Object value : values) { System.out.println(value); } //(2) Iterator Iterator iterator = values.iterator(); while(iterator.hasNext()){ Object next = iterator.next(); System.out.println(next); }
-
Get k-y through EntrySet
Set entrySet = map.entrySet(); //(1) Enhanced for for (Object entry : entrySet) { //Turn entry down to Map.Entry Map.Entry m = (Map.Entry) entry; System.out.println(m.getKey()); System.out.println(m.getValue()); } //iterator Iterator iterator = entrySet.iterator(); while (iterator.hasNext()) { Object entry = iterator.next(); //Turn entry down to Map.Entry Map.Entry m = (Map.Entry) entry; System.out.println(m.getKey()); System.out.println(m.getValue()); }
The capacity expansion mechanism of HashMap is exactly the same as that of HashSet
Hashtable
Hashtable features
-
Neither key nor value can be empty
public synchronized V put(K key, V value) { // Make sure the value is not null if (value == null) { throw new NullPointerException(); }
-
Thread safety
-
The basic usage is the same as HashMap
-
Underlying structure: array
Hashtable infrastructure
- The bottom layer is an array. The Hashtable internal class Entry [], the initialization size is 11
- threshold=11*0.75=8
Comparison between Hashtable and HashMap
Thread safe (synchronous) | efficiency | Allow null keys and null values | |
---|---|---|---|
Hashtable | security | Lower | not allow |
HashMap | unsafe | high | allow |
Properties
Basic introduction
- The Properties class inherits the Hashtable and implements the Map interface. It also uses key value pairs to save data. Key value pairs cannot be null
- Similar to Hashtable
- Properties can also be used in the xxx.properties file to load data into the properties class object, read and modify it
- xxx.properties is usually used for configuration files
TreeMap
-
When created with a parameterless constructor, dictionary sorting is used by default
TreeMap treeMap = new TreeMap(); treeMap.add("jack"); treeMap.add("tom"); treeMap.add("lucy"); treeMap.add("marry"); System.out.println(treeMap); Output:[jack, lucy, marry, tom]
-
Using the Comparator builder, you can change the collation
TreeMap treeMap = new TreeMap(new Comparator() { @Override public int compare(Object o1, Object o2) { //According to the dictionary from small to large, the sorting order can be changed by changing the order of o1 and o2 return ((String)o2).compareTo((String)o1); } }); treeMap.add("jack"); treeMap.add("tom"); treeMap.add("lucy"); treeMap.add("marry"); System.out.println(treeMap); Output:[tom, marry, lucy, jack]
-
If you sort by string length, you cannot add strings of the same length
TreeMap treeMap = new TreeMap(new Comparator() { @Override public int compare(Object o1, Object o2) { return ((String)o2).length()-((String)o1).length(); } }); treeMap.add("jack"); treeMap.add("tom"); treeMap.add("lucy"); //Same length, cannot add treeMap.add("marry"); System.out.println(treeMap); Output:[marry, jack, tom]
How to select a collection
Collections tool class
Collections is a tool class that operates on collections such as Set, List, and Map
Collections provides a series of static methods to sort, query and modify collection elements
Sorting operations (all static methods)
-
reverse (list): element inversion
List list = new ArrayList(); list.add("tom"); list.add("jack"); list.add("king"); System.out.println(list); Collections.reverse(list); //Element inversion System.out.println(list); Output:[tom, jack, king] [king, jack, tom]
-
Sort (list): sort by dictionary by default
List list = new ArrayList(); list.add("tom"); list.add("jack"); list.add("king"); System.out.println(list); Collections.sort(list); System.out.println(list); Output:[tom, jack, king] [jack, king, tom]
-
Sort (list, Comparator com): custom sort
List list = new ArrayList(); list.add("tom"); list.add("jack"); list.add("kinging"); System.out.println(list); Collections.sort(list, new Comparator() { @Override public int compare(Object o1, Object o2) { //Sort by length return ((String) o2).length() - ((String) o1).length(); } }); System.out.println(list); Output: [tom, jack, kinging] After sorting:[kinging, jack, tom]
-
swap (list, list, int i, int j): exchange the specified two location elements
List list = new ArrayList(); list.add("tom"); list.add("jack"); list.add("king"); System.out.println(list); Collections.swap(list,0,2); System.out.println(list); Output:[tom, jack, king] [king, jack, tom]
Find, replace
-
max (Collection c): the maximum value is given in natural order
List list = new ArrayList(); list.add("tom"); list.add("jack"); list.add("king"); System.out.println(Collections.max(list)); Output: tom
-
max (Collection c, Comparator com): Custom return value
List list = new ArrayList(); list.add("tom"); list.add("jack"); list.add("kinging"); Object max = Collections.max(list, new Comparator() { @Override public int compare(Object o1, Object o2) { //Custom, returns the element with the largest length return ((String) o1).length() - ((String) o2).length(); } }); System.out.println(max); Output: kinging