Overview of the collection framework
Collection and array are structures that store multiple data, which are referred to as Java containers for short.
Storage at this time mainly refers to memory level storage and does not involve persistent storage (such as. txt,. jpg, database, etc.)
The characteristics of arrays in storing multiple data
- Once initialized, the length is determined
- When defining an array, you need to specify the element type of the array (you must store what type of data you declare)
For example: String[] arr; int[] arri;
Array has the disadvantage of storing multiple data
- Once the length is determined, it cannot be modified
- Only a single type of data can be stored (advantages (more strict control of data) and disadvantages (inconvenient when there are multiple types of data), depending on the demand)
- The methods provided in the array are relatively limited. It is very inconvenient and inefficient to add, delete and insert data
- The requirement to obtain the number of actual elements in the array (for example, there are several available elements in an array with a length of 10). The array has no ready-made properties or methods to use
- The characteristics of array storage data: orderly and repeatable; For requirements that are out of order and cannot be repeated, arrays cannot be implemented
Java collection classes can be used to store multiple objects with different numbers, and can also be used to store associative arrays with mapping relationships
Java collections can be divided into Collection and Map systems
Collection interface
Single column data, single column collection, used to store objects one by one
-
List: store ordered and repeatable data (common: ArrayList, LinkedList, Vector)
-
Set: store unordered and non repeatable data (common: HashSet, LinkedHashSet, ThreeSet)
Map interface
A two column set is used to store a pair of key value and a pair of key value data
Common: HashMap, LinkedHashMap, ThreeMap, Hashtable, Properties
Use of Collection interface
explain
- The Collection interface is the parent interface of the List, Set and Queue interfaces. The methods defined in this interface can be used to operate both Set sets and List and Queue sets.
- JDK does not provide any direct implementation of this interface, but provides more specific implementation of sub interfaces (such as Set and List).
- Before JDK5, Java collections will lose the data types of all objects in the container and treat all objects as Object types; After adding generics to JDK 5.0, Java collections can remember the data types of objects in containers.
common method
method | effect |
---|---|
add(Object obj) | Adds the specified element to the specified collection (using auto boxing) |
addAll(Collection coll) | Adds elements from the specified collection to the current collection |
int size() | Gets the number of elements in the specified collection |
void clear() | Clears all elements in the specified collection |
boolean isEmpty() | Judge whether the current collection is empty |
boolean contains(Object obj) | Determine whether the current collection contains an element |
boolean containsAll(Collection coll) | Judge whether all elements in the formal parameter coll exist in the current collection |
boolean remove(Object obj) | To delete obj elements from the current collection, return true for success and false for failure |
boolean removeAll(Collection coll) | Removes all elements in the coll from the current collection |
boolean retainAll(Collection coll) | Intersection, get the intersection of the current set and the coll set, and return it to the current set |
boolean equals(Object obj) | To return true, the elements of the current collection and the parameter collection need to be the same |
Object[] toArray() | Convert a collection to an array of objects |
hashCode() | Gets the hash value of the specified collection object |
iterator() | Returns an instance of the Iterator interface for traversing collection elements |
-
When you call contains, containsAll, remove and removeAll, you call the equals method to find the corresponding value
-
Array to collection: Arrays.asList();
-
Collection to array: toArray()
Case 1
package com.laoyang.test.day1; import org.junit.Test; import java.util.ArrayList; import java.util.Collection; /** * @ClassName CollectionTest * @Description: Use of collection framework * @Author Laoyang * @Date 2021/9/28 15:42 */ public class CollectionTest { /** * Collection Method usage in interface */ @Test public void testOne() { Collection collection = new ArrayList(); // add(Object e): adds the specified element to the corresponding collection (auto boxing) collection.add("Xiaobai"); collection.add(123); // addAll(Collection coll): adds the elements in the specified collection to the current collection (it can be used to integrate multiple collections in some requirements) Collection coll = new ArrayList(); coll.add("AAa"); coll.addAll(collection); //Collection collection1 = new ArrayList(); //collection1.addAll(coll); // Xiaobai 123 AAA // size(): gets the number of elements in the specified collection System.out.println(collection.size()); // 2 // isEmpty(): judge whether the current collection is empty System.out.println(coll.isEmpty()); // false // clear(): clear all elements in the specified collection System.out.println(collection); // [Xiaobai, 123] collection.clear(); System.out.println(collection); // [] } }
Case 2
Note: when adding obj data to the object of the implementation class of the Collection interface, the class of obj is required to override the equals method
package com.laoyang.test.day1; import org.junit.Test; import java.util.*; /** * @ClassName CollectionMethod * @Description: Collection common method * @Author Laoyang * @Date 2021/9/30 10:15 */ public class CollectionMethod { @Test public void testOne() { Collection collection = new ArrayList(); collection.add("AAA"); collection.add(123); collection.add("ABC"); collection.add(new String("QQ")); Person person = new Person(); collection.add(person); collection.add(new Person("Laoyang", 20)); // contains(Object obj): determines whether the current collection contains an element System.out.println(collection.contains("ABC")); // true System.out.println(collection.contains("CCC")); // false /* be careful String The equals method is rewritten internally, so when using the contains method, the rewritten equals method will be called automatically for judgment. Therefore, the comparison of two classes with the same value is true If the equals method is not overridden in some classes, the equals method in Object will be called by default, and the equals method in Object class uses the = = sign to judge (that is, to judge the address value). Therefore, the comparison between two classes with the same value is false Ps: If you want two classes with the same value to be true, you need to override equals manually */ System.out.println(collection.contains(new String("QQ"))); // true System.out.println(collection.contains(person)); // true System.out.println(collection.contains(new Person("Laoyang", 20))); // false (true after overriding the equals method) System.out.println("----------------------------------"); // containsAll(Collection coll): judge whether all elements in the formal parameter coll exist in the current collection Collection coll = Arrays.asList("QQ", 123, "Hey, hey, hey"); // As long as there is a different one, it will return false System.out.println(coll.containsAll(collection)); // false } @Test public void testTwo() { Collection collection = new ArrayList(); collection.add("AAA"); collection.add(123); collection.add("ABC"); collection.add(new String("QQ")); collection.add(new Person("Laoyang", 20)); // remove(Object obj): deletes an obj element from the current collection. Returns true on success and false on failure System.out.println(collection); // [AAA, 123, ABC, QQ, Person{name='Laoyang', age=20}] System.out.println(collection.remove("AAA")); // true System.out.println(collection); // [123, ABC, QQ, Person{name='Laoyang', age=20}] System.out.println("----------------------------------"); // Remove all (collection Coll): removes all elements in the coll from the current collection Collection coll = Arrays.asList(123, "QQ", "WW"); System.out.println(collection.removeAll(coll)); // true System.out.println(coll); // [123, QQ, WW] System.out.println(collection); // [ABC, Person{name='Laoyang', age=20}] } @Test public void testThree() { Collection collection = new ArrayList(); collection.add("AAA"); collection.add(123); collection.add("ABC"); collection.add(new String("QQ")); collection.add(new Person("Laoyang", 20)); // Retain all (collection Coll): intersection. Get the intersection of the current collection and coll collection and return it to the current collection Collection coll = Arrays.asList(123, "QQ", "WW"); System.out.println(collection.retainAll(coll)); // true System.out.println(collection); // [123, QQ] System.out.println("----------------------------------"); // equals(Object obj): to return true, the elements of the current set and the parameter set must be the same Collection collA = new ArrayList(); collA.add("AAA"); collA.add(123); Collection collB = new ArrayList(); collB.add("AAA"); collB.add(123); Collection collC = new ArrayList(); collC.add(123); collC.add("AAA"); System.out.println(collA.equals(collB)); // true System.out.println(collA.equals(collC)); // False (because the List stores ordered and repeatable data, false will be returned if the values are the same and the order is different) } @Test public void testFour() { Collection collection = new ArrayList(); collection.add("AAA"); collection.add(123); collection.add("ABC"); collection.add(new String("QQ")); collection.add(new Person("Laoyang", 20)); // hashCode(): returns the hash value of the current object System.out.println(collection.hashCode()); /* Collection to array: toArray() Array to collection: Arrays.asList() */ Object[] objects = collection.toArray(); System.out.println(Arrays.toString(objects)); // [AAA, 123, ABC, QQ, Person{name='Laoyang', age=20}] List<Object> list = Arrays.asList(objects); System.out.println(list); // [AAA, 123, ABC, QQ, Person{name='Laoyang', age=20}] /* Note: when using an array of basic data types, List will only recognize one element!!! If necessary, you can use the wrapper class for transmission */ List<int[]> ints = Arrays.asList(new int[]{1, 2, 3, 4}); System.out.println(ints.size()); // 1 System.out.println(ints); // [[I@22927a81] List<char[]> chars = Arrays.asList(new char[]{'q', 'a'}); System.out.println(chars); // [[C@78e03bb5] // How to package class parameters List<Integer> integers = Arrays.asList(new Integer[]{1, 2, 3, 4}); System.out.println(integers.size()); // 4 System.out.println(integers); // [1, 2, 3, 4] List<Double> doubles = Arrays.asList(new Double[]{1.2, 2.3, 3.4}); System.out.println(doubles.size()); // 3 System.out.println(doubles); // [1.2, 2.3, 3.4] } } class Person { private String name; private int age; /** * Override the equals method */ @Override public boolean equals(Object o) { System.out.println("get into Person Class equals method"); if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person(String name, int age) { this.name = name; this.age = age; } public Person() { } }
be careful
-
String internally rewrites the equals method, so when using the contains method, the rewritten equals method will be called automatically for judgment. Therefore, two classes with the same value are true.
-
If the equals method is not overridden in some classes, the equals method in Object will be called by default, and the equals method in Object class uses the = = sign to judge (that is, to judge the address value). Therefore, the comparison between two classes with the same value is false.
If you want two classes with the same value to be true, you need to override equals manually
-
When using an array of basic data types, List will only recognize one element!!! If necessary, you can use the wrapper class for transmission.
Iterator iterator
explain
-
The Iterator object is called an Iterator (a kind of design pattern) and is mainly used to traverse the elements in the Collection.
-
GOF defines the iterator pattern as providing a way to access each element in a container object without exposing the internal details of the object. The iterator pattern is born for containers.
Similar to "conductor on the bus", "stewardess on the train" and "stewardess".
-
Every time a collection object calls the iterator() method, it will get a new iterator object. The default cursor is before the first element of the collection.
Internally defined methods in Iterator
- hasNext(): judge whether there is another element
- next(): the pointer moves down, and the element at the collection position will be returned after moving down
- Remove(): when traversing, delete the specified elements in the collection. This method is different from the direct call to remove() in the collection
case
Here is a simple demonstration of three traversal methods
package com.laoyang.test.day1; import org.junit.Test; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /** * @ClassName IteratorTest * @Description: Ierator Use of iterators * @Author Laoyang * @Date 2021/9/30 11:18 */ public class IteratorTest { @Test public void testOne() { Collection collection = new ArrayList(); collection.add("AAA"); collection.add(123); collection.add(new String("QQ")); collection.add(new Person("Laoyang", 20)); Iterator iterator = collection.iterator(); // Mode 1 // System.out.println(iterator.next()); // AAA // System.out.println(iterator.next()); // 123 // System.out.println(iterator.next()); // QQ // System.out.println(iterator.next()); // Person{name='Laoyang', age=20} // System.out.println(iterator.next()); // Error reported: NoSuchElementException // Method 2: not recommended // for (int i = 0; i < collection.size(); i++) { // System.out.println(iterator.next()); // } // Method 3: recommend (hasNext(): judge whether there is another element) while (iterator.hasNext()) { System.out.println(iterator.next()); } } }
Iterator execution principle
- A pointer is generated when the Iterator object is created
- The hashNext method determines whether there is a next element
- If hashNext returns true, the pointer will move down to the first element in the collection. If it is false, it will end directly... And so on
Two wrong ways of Iterator traversing a set
Error 1: directly use next() to judge, resulting in skip traversal
Error 2: using Iterator anonymous object causes an endless loop
package com.laoyang.test.day1; import org.junit.Test; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /** * @ClassName IteratorTest * @Description: Ierator Use of iterators * @Author Laoyang * @Date 2021/9/30 11:18 */ public class IteratorTest { /** * Iterator Two wrong ways to write traversal sets */ @Test public void testTwo() { Collection collection = new ArrayList(); collection.add("AAA"); collection.add(123); collection.add(new String("QQ")); collection.add(new Person("Laoyang", 20)); /* Error 1: AAA is obtained during the first execution, and then AAA is used for judgment After the judgment is successful, the value 123 pointed to by the next pointer is returned The final effect is to jump to the output set element, and then jump to the last one. If there is no next one, it will report NoSuchElementException */ // Iterator iterator = collection.iterator(); // While ((iterator. Next())! = null) {/ / AAA is obtained during the first execution, and then AAA is used for judgment // System.out.println(iterator.next()); / / after judging success, return the value 123 pointed to by the next pointer // } /* Error 2: using Iterator anonymous object - causes an endless loop */ while (collection.iterator().hasNext()) { System.out.println(collection.iterator().next()); } } }
Use of the remove method
be careful
-
Iterator can delete the elements of the collection, but it is the remove method of the iterator object during traversal, not the remove method of the collection object.
-
If you call remove() before calling next(), you will report IllegalStateException
-
After calling the next method two times after the last call, the remove method also reported IllegalStateException.
case
package com.laoyang.test.day1; import org.junit.Test; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /** * @ClassName IteratorTest * @Description: Ierator Use of iterators * @Author Laoyang * @Date 2021/9/30 11:18 */ public class IteratorTest { /** * remove Use of methods * Case 1: if you call remove() before calling next(), you will report IllegalStateException * Situation two: after the last call to the next method, two times the remove method also called IllegalStateException. */ @Test public void testTherr() { Collection collection = new ArrayList(); collection.add("AAA"); collection.add(123); collection.add(new String("QQ")); collection.add(new Person("Laoyang", 20)); // Deletes the specified element in the collection Iterator iterator = collection.iterator(); while (iterator.hasNext()) { // Case 1: the remove method cannot be executed immediately after the hasNext() method is executed, because the pointer does not point to any value at this time //iterator.remove(); / / error: IllegalStateException Object next = iterator.next(); if ("QQ".equals(next)) { iterator.remove(); // Case 2: you cannot call remove() twice after the next() method, but you can call it outside, for example, you can call remove() outside the current while structure //iterator.remove(); / / error: IllegalStateException } } // Traverse the collection, because the above has been traversed, so we need to re assign the value here, and then traverse iterator = collection.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } }
Traversing collection elements in foreach mode
explain
- foreach is a new for loop feature added in JDK5, which is used to traverse sets and arrays.
- The traversal operation does not need to get the length of the Collection or array, and does not need to use an index to access elements.
- Traverse the bottom layer of the collection and call Iterator to complete the operation.
case
package com.laoyang.test.day1; import org.junit.Test; import java.util.ArrayList; import java.util.Collection; /** * @ClassName ForTest * @Description: JDK5 New features of for loop * @Author Laoyang * @Date 2021/9/30 15:52 */ public class ForTest { /** * Traverse collection: for (element type local variable in collection: collection object) {} */ @Test public void testOne() { Collection collection = new ArrayList(); collection.add("AAA"); collection.add(123); collection.add(new String("QQ")); collection.add(new Person("Laoyang", 20)); // This traversal method still calls the iterator internally for (Object o : collection) { System.out.println(o); } } /** * Traversal array: for (element type of array, local variable: array object) {} */ @Test public void testTwo() { int[] arr = new int[]{1, 5, 3, 2}; for (int i : arr) { System.out.println(i); } } }
Little practice
Using two different for loop assignment methods, what are the final printed results?
package com.laoyang.test.day1; import org.junit.Test; import java.util.ArrayList; import java.util.Collection; /** * @ClassName ForTest * @Description: JDK5 New features of for loop * @Author Laoyang * @Date 2021/9/30 15:52 */ public class ForTest { /** * Small exercise: is the final printed result WW or MM? */ @Test public void testThree() { String[] strs = new String[]{"WW", "WW", "WW"}; /* Method 1: ordinary for assignment This assignment operation is to replace the element at the specified subscript position in the strs array with a new value, so the final traversal result is the replaced element */ // for (int i = 0; i < strs.length; i++) { // strs[i] = "MM"; // } /* Method 2: enhance for assignment This assignment operation is not saved in strs, because it first obtains each value from strs, and then assigns it to str for use However, str is a new local variable, and its value will not affect the elements in strs, so the final printed result will still be WW */ for (String str : strs) { str = "MM"; } for (String str : strs) { System.out.println(str); } } }
You can open / close the commented code for testing
Use of List
explain
- For the limitation that arrays are used to store data in Java, we usually use List instead of arrays.
- The elements in the List collection class are ordered and repeatable, and each element in the collection has its corresponding sequential index.
- The elements in the List container correspond to an integer serial number. The position recorded in the container can access the elements in the container according to the serial number.
- The implementation classes of List interface in JDK API are ArrayList, LinkedList and Vector.
Common interview questions: what are the similarities and differences of ArrayList, LinkedList and Vector?
Similarities: the three classes implement the List interface, and the characteristics of storing data are the same (they are ordered and repeatable data)
difference:
ArrayList: as the main implementation class of the List interface (JDK1.2); high execution efficiency (thread unsafe); the underlying layer uses Object[] elementData for storage;
LinkedList: JDK1.2 appears; for frequent insert and delete operations, the efficiency is higher than ArrayList; the bottom layer uses two-way linked list storage;
Vector: as an ancient implementation class of the List interface (JDK1.0); low execution efficiency (thread safe); the underlying layer uses Object[] elementData for storage;
The List interface also appeared in JDK1.2
ArrayList source code analysis (JDK7 & jdk8)
ArrayList in JDK7
ArrayList list = new ArrayList(); // The bottom layer creates an array with a length of 10 list.add(111); // elementData[0] = new Integer(111); ... list.add(999); // If the capacity of the underlying elementData array is insufficient due to this addition operation, the capacity will be expanded > By default, the capacity will be expanded to 1% of the original capacity.5 At the same time, you need to assign the data in the original array to the new array! > It is recommended to use a constructor with parameters in actual development: ArrayList list = new ArrayList(int initialCapacity);
Partial source code
package java.util; import java.util.*; public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ // The array buffer in which the elements of ArrayList are stored. The capacity of ArrayList is the length of the array buffer private transient Object[] elementData; // The size of the ArrayList (the number of elements it contains). private int size; /** * The maximum size of the array to allocate. Some VM S keep some headers in the array. * Attempting to allocate a larger array may result in OutOfMemoryError: the requested array size exceeds the VM limit */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // The null parameter constructor automatically sets the original size of elementData public ArrayList() { this(10); } // With parameter constructor, manually set the original size of elementData public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Cap" + "acity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } // Returns the total number of current elements public int size() { return size; } // Add element public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } // Ensure that the content can be put into the current collection normally. If the currently added content exceeds the storage length of the collection, the underlying capacity expansion mechanism will be used private void ensureCapacityInternal(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } // Increase the capacity to ensure that it can accommodate at least the number of elements specified by the minimum capacity parameter private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; // The default expansion is 1.5 times the original length int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) // If it is not enough, the length of the current value is directly regarded as the length of the set newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) // If it is not enough, the maximum value of int will be taken as the length newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: // Copy all the elements in the current elementData array to the new array elementData = Arrays.copyOf(elementData, newCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } }
I added the Chinese Notes myself, which can be understood in combination or ignored
ArrayList in JDK8
ArrayList list = new ArrayList(); // The underlying Object[] elementData is initialized to {}, and an array with a length of 10 is not created list.add(111); // When add() is called for the first time, the underlying layer creates an array with a length of 10 and adds data 111 to elementDate[0] ... list.add(999); // If the capacity of the underlying elementData array is insufficient due to this addition operation, the capacity will be expanded ... Capacity expansion operation and JDK7 No difference
Partial source code
package java.util; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.UnaryOperator; public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ // Shared empty array instance for empty instances of default size. We compare it with empty_ Element data to see how much expansion is required when the first element is added private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // The size of the ArrayList (the number of elements it contains). private int size; // The maximum size of the array to allocate. Some VMS keep some headers in the array. Attempting to allocate a larger array may result in OutOfMemoryError: the requested array size exceeds the VM limit private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // Construct an empty list with an initial capacity of 10. public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } // Appends the specified element to the end of this list public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } // Ensure internal capacity private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } // Ensure explicit capacity private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } // Increase the capacity to ensure that it can accommodate at least the number of elements specified by the minimum capacity parameter. private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; 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); } // Huge capacity private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } }
I added the Chinese Notes myself, which can be understood in combination or ignored
Summary
The creation of ArrayList in JDK7 is similar to the hungry man in singleton mode, and the creation of ArrayList object in JDK8 is similar to the lazy man in singleton mode, which delays the creation of array and saves memory.
LinkedList source code analysis
LinkedList list = new LinkedList(); // The first and last attributes of Node type are declared internally, and the default value is null list.add(111); // Encapsulate 111 into Node and create Node object among Node(Reflects LinkedList Is defined as: private static class Node<E> { E item; Node<E> next; Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } }
Partial source code
package java.util; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.UnaryOperator; public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ // Shared empty array instance for empty instances of default size. We compare it with empty_ Element data to see how much expansion is required when the first element is added private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // The size of the ArrayList (the number of elements it contains). private int size; // The maximum size of the array to allocate. Some VMS keep some headers in the array. Attempting to allocate a larger array may result in OutOfMemoryError: the requested array size exceeds the VM limit private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // Construct an empty list with an initial capacity of 10. public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } // Appends the specified element to the end of this list public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } // Ensure internal capacity private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } // Ensure explicit capacity private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } // Increase the capacity to ensure that it can accommodate at least the number of elements specified by the minimum capacity parameter. private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; 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); } // Huge capacity private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } }
I added the Chinese Notes myself, which can be understood in combination or ignored
Vector source code analysis
Since Vector was a long time ago, this implementation class will not be used now, so let's briefly explain it here
-
When creating objects through the Vector() constructor in JDK7 and JDK8, the underlying layer creates an array with a length of 10
-
In terms of capacity expansion, the default capacity expansion is twice the original array
-
Vector is thread safe
Partial source code
package java.util; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.UnaryOperator; public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ // An array buffer that stores Vector components. The capacity of the Vector is the length of the array buffer and is at least sufficient to contain all the elements of the Vector. Any array element after the last element in the Vector is empty protected Object[] elementData; // The number of valid components in this Vector object protected int elementCount; // When the size of the vector becomes larger than its capacity, the capacity of the vector increases automatically. If the capacity increment is less than or equal to zero, the capacity of the vector will double each time it needs to grow protected int capacityIncrement; // Construct an empty vector so that the size of its internal data array is 10 and its standard capacity increment is zero. public Vector() { this(10); } // Appends the specified element to the end of this Vector. public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; } // This implements the asynchronous semantics of ensureCapacity. The synchronization method in this class can call this method internally to ensure capacity without incurring the cost of additional synchronization. private void ensureCapacityHelper(int minCapacity) { // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } // The maximum size of the array to allocate. Some VMS keep some headers in the array. Attempting to allocate a larger array may result in OutOfMemoryError: the requested array size exceeds the VM limit private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } }
I added the Chinese Notes myself, which can be understood in combination or ignored
common method
method | effect |
---|---|
void add(int index, Object ele) | Insert the ele element at the index position |
boolean addAll(int index, Collection eles) | Add all elements in eles from the index position |
Object get(int index) | Gets the element at the specified index location |
int indexOf(Object obj) | Returns the position where obj first appears in the collection |
int lastIndexOf(Object obj) | Returns the last occurrence of obj in the current collection |
Object remove(int index) | Removes the element at the specified index location and returns this element |
Object set(int index, Object ele) | Set the element at the specified index location to ele |
List subList(int fromIndex, int toIndex) | Returns a subset from fromIndex to toIndex |
Some methods are not listed here. You can see the use in the following cases
case
package com.laoyang.test.day2; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; /** * @ClassName ListMethod * @Description: List Common interface methods * @Author Laoyang * @Date 2021/10/2 9:41 */ public class ListMethod { @Test public void testOne() { ArrayList list = new ArrayList(); // add(Object obj) list.add("Laoyang"); list.add(20); list.add(new Person("Xiaobai", 18)); list.add(20); System.out.println(list); // [Laoyang, 20, Person{name='Xiaobai', age=18}, 20] System.out.println("-----------------------------"); // add(int index, Object ele): inserts an ele element at the index position list.add(2, "QQ"); System.out.println(list); // [Laoyang, 20, QQ, Person{name='Xiaobai', age=18}, 20] System.out.println("-----------------------------"); // Add all (int index, collection ELES): add all elements in eles from the index position List strings = Arrays.asList("WW", "EE", "RR"); list.addAll(4, strings); // If the collection is passed in by using the add method, the list will take it as a whole by default and add it to the corresponding list //list.add(strings); System.out.println(list); // [Laoyang, 20, QQ, Person{name='Xiaobai', age=18}, WW, EE, RR, 20] System.out.println(list.size()); // Use addAll() to return 9 and add() to return 6 System.out.println("-----------------------------"); // get(int index): gets the element at the specified index position Object o = list.get(3); System.out.println(o); // Person{name='Xiaobai', age=18} System.out.println("-----------------------------"); // indexOf(Object obj): returns the position where obj first appears in the collection. If the corresponding value cannot be found, - 1 is returned System.out.println(list.indexOf(20)); // 1 System.out.println(list.indexOf(200)); // -1. Return - 1 when the corresponding value cannot be found System.out.println("-----------------------------"); // lastIndexOf(Object obj): returns the last occurrence of obj in the current collection. If the corresponding value cannot be found, - 1 is returned System.out.println(list.lastIndexOf(20)); // 7 System.out.println(list.lastIndexOf(205)); // -1. Return - 1 when the corresponding value cannot be found System.out.println("-----------------------------"); /* remove(int index):Removes the element at the specified index location and returns this element remove(Object o):Remove the element specified in the corresponding array (Note: the element to be removed will not be returned in this way) */ Object remove = list.remove(3);// Delete by index System.out.println(remove); // Person{name='Xiaobai', age=18} list.remove("EE"); // Delete according to element System.out.println(list); // [Laoyang, 20, QQ, WW, RR, 20] System.out.println("-----------------------------"); // Set (int index, opbject, ELE): sets the element at the specified index position to ele list.set(3, "QWER"); System.out.println(list); // [Laoyang, 20, QQ, QWER, RR, 20] System.out.println("-----------------------------"); // subList(int fromIndex, int toIndex): returns the subset from fromIndex to toIndex, which will not affect the original collection elements List list1 = list.subList(0, 3); System.out.println(list1); // [Laoyang, 20, QQ] System.out.println(list); // [Laoyang, 20, QQ, QWER, RR, 20] } } class Person { private String name; private int age; @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person(String name, int age) { this.name = name; this.age = age; } public Person() { } }
Three ways to traverse the List collection
Iterator iterator, foreach(), for()
package com.laoyang.test.day2; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; /** * @ClassName ListMethod * @Description: List Common interface methods * @Author Laoyang * @Date 2021/10/2 9:41 */ public class ListMethod { /** * List Three ways of traversal of sets * Iterator Iterator, foreach(), for() */ @Test public void testTwo() { ArrayList list = new ArrayList(); list.add("Laoyang"); list.add(20); list.add(new Person("Xiaobai", 18)); list.add(20); // Method 1: Iterator iterator Iterator iterator = list.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } System.out.println("------------------------------"); // Method 2: foreach() for (Object o : list) { System.out.println(o); } System.out.println("------------------------------"); // Method 3: for() for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } } } class Person { private String name; private int age; @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person(String name, int age) { this.name = name; this.age = age; } public Person() { } }
Summary
Add: add(Object ele), addAll(Collection eles)
Delete: remove(int index), remove(Object obj)
Change: set(int index, Object ele)
Query: get(int index)
Insert: add(int index, Object ele)
Length: size()
Traversal: Iterator iterator, foreach(), for()
Use of Set
explain
-
The set interface is a sub interface of the Collection. The set interface does not provide additional methods.
-
The Set set cannot contain the same elements. If you try to add two identical elements to the same Set set, the add operation fails.
-
Set determines whether two objects are the same, not using the = = operator, but according to the equals() method.
Features: store unordered and unrepeatable data
Use requirements
- The class of the data added to the Set must override hashCode() and equals()
- Overridden hashCode() and equals() are as consistent as possible: equal objects must have equal hash codes (hash values)
- Tip for rewriting two methods: the properties in the object used for the equals() method comparison should be used to calculate the hashCode() value
Generally, the properties of the objects that participate in the calculation of hashCode() should also participate in the calculation of equals().
Suggestion: there are automatically generated equals() and hashCode() in the IDEA. It is recommended to directly use the automatically generated in the development to avoid some unnecessary trouble.
IDEA shortcut: ALT + INS
understand
There are no new methods defined in the Set interface, but all the methods declared in the Collection interface are used
Set implementation class
-
HashSet: as the main implementation class of Set interface; Thread unsafe; null values can be stored.
HashSet underlying structure: array + linked list (JDK7)
-
LinkedHashSet: as a subclass of HashSet; When traversing internal data, it can be traversed in the order of addition.
-
ThreeSet: you can sort by the specified attribute of the added object.
Disorder and non repeatability of Set (taking HashSet as an example)
- Disorder: not equal to randomness; The stored data is not added in the order of array index in the underlying array, but determined according to the hash value of the data.
- Non repeatability: ensure that when the added element is judged according to equals(), it cannot return true (because returning true means that the two elements are the same); Only one of the same elements can be added.
You can refer to the following case code to understand the use of HashSet and the disorder and non repeatability in HsahSet
case
Entity class
package com.laoyang.test.day3; import java.util.Objects; /** * @ClassName User * @Description: * @Author Laoyang * @Date 2021/10/8 11:02 */ public class User implements Comparable { private String name; private int age; public User() { } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public User(String name, int age) { this.name = name; this.age = age; } /** * Override the equals() method */ @Override public boolean equals(Object o) { System.out.println("Called User of equals method"); if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return age == user.age && Objects.equals(name, user.name); } /** * Override hashCode() method */ @Override public int hashCode() { return Objects.hash(name, age); } }
Test class
package com.laoyang.test.day3; import org.junit.Test; import java.util.*; /** * @ClassName SetTest * @Description: Set Use of interfaces * @Author Laoyang * @Date 2021/10/2 10:52 */ public class SetTest { /** * Disorder * Not equal to randomness; The stored data is not added in the order of array index in the underlying array, but determined according to the hash value of the data. */ @Test public void testOne() { // HashSet will create an array with a length of 16 by default Set set = new HashSet(); set.add(123); set.add("QQ"); set.add(new String("ABC")); set.add(12.5); Iterator iterator = set.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } /** * Non repeatability * Ensure that when the added element is judged according to equals(), it cannot return true (because returning true means that the two elements are the same); Only one of the same elements can be added. */ @Test public void testTwo() { Set set = new HashSet(); set.add(123); set.add("QQ"); set.add(new String("ABC")); set.add(12.5); /* Override the hashCode() method in the User class to determine whether the hash values of two objects are the same (if the hash values are the same, the equals() method will be called to determine) If the hashCode() method is not overridden, the hashCode() method in the Object class will be called by default, and the hashCode() in the Object will be judged randomly Therefore, in the end, it may not be judged with the same value as the existing value, but directly inserted in different positions, resulting in the final acquisition of two identical objects */ set.add(new User("Xiaobai", 18)); set.add(new User("Xiaobai", 18)); Iterator iterator = set.iterator(); while (iterator.hasNext()) { // There will be only one User object in the last printed result System.out.println(iterator.next()); } } }
If you want to see the effect of printing the last two identical elements, you only need to annotate the hashCode() method in the User class
Use of LinkedHashSet
explain
-
LinkedHashSet is a subclass of HashSet. While adding data, each data also maintains two references to record the previous data and the latter data
-
Advantages: for frequent traversal operations, LinkedHashSet is more efficient than HashSet
case
package com.laoyang.test.day3; import org.junit.Test; import java.util.*; /** * @ClassName SetTest * @Description: Set Use of interfaces * @Author Laoyang * @Date 2021/10/2 10:52 */ public class SetTest { /** * LinkedHashSet Use of */ @Test public void testThree() { Set set = new LinkedHashSet(); set.add(123); set.add("QQ"); set.add(new String("ABC")); set.add(12.5); set.add(new User("Xiaobai", 18)); set.add(new User("Xiaobai", 18)); Iterator iterator = set.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } }
Use of TreeSet
explain
- The data added to TreeSet must be objects of the same class.
- There are two sorts: natural sort (to achieve Comparable) and custom sort (Comparator)
- In natural sorting, the criteria for comparing whether two objects are the same is: compareTo() returns 0 and doesn't care about equals()
- In custom sorting, the criteria for comparing whether two objects are the same is: compare() returns 0 and doesn't care about equals()
Features: orderly, faster query speed than List
The underlying TreeSet uses a red black tree structure to store data
case
Entity class User
package com.laoyang.test.day3; import java.util.Objects; /** * @ClassName User * @Description: * @Author Laoyang * @Date 2021/10/8 11:02 */ public class User implements Comparable { // Omit some code - this class is the User class above /** * Sort by name from small to large */ @Override public int compareTo(Object o) { if (o instanceof User) { User user = (User) o; //return this.name.compareTo(user.name); // Only judge whether the name is the same int i = this.name.compareTo(user.name); if (i != 0) { return i; } else { return Integer.compare(this.age, user.age); } } else { throw new RuntimeException("Inconsistent type"); } } }
Test class
package com.laoyang.test.day3; import org.junit.Test; import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; /** * @ClassName TreeSetTest * @Description: TreeSet Use of * @Author Laoyang * @Date 2021/10/8 10:56 */ public class TreeSetTest { /** * Natural sorting */ @Test public void testOne() { TreeSet set = new TreeSet(); // Cannot add objects of different classes: ClassCastException // set.add(123); // set.add("QQ"); // set.add(12.5); // Example 1 // set.add(123); // set.add(-1); // set.add(233); // set.add(99); // Example 2 set.add(new User("Tom", 22)); set.add(new User("Jerry", 18)); set.add(new User("Jim", 35)); // If you only judge the name, only one Mike will appear at the end of printing set.add(new User("Mike", 6)); set.add(new User("Mike", 15)); Iterator iterator = set.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } /** * Custom sorting */ @Test public void testTwo() { Comparator comparator = new Comparator() { // Sorted by age @Override public int compare(Object o1, Object o2) { if (o1 instanceof User && o2 instanceof User) { User userA = (User) o1; User userB = (User) o2; return Integer.compare(userA.getAge(), userB.getAge()); } else { throw new RuntimeException("Inconsistent type"); } } }; TreeSet set = new TreeSet(comparator); set.add(new User("Tom", 18)); set.add(new User("Jerry", 18)); set.add(new User("Jim", 35)); set.add(new User("Mike", 6)); set.add(new User("Mike", 15)); Iterator iterator = set.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } }
The process of adding elements to a HashSet (taking HashSet as an example)
-
We add element A to the HashSet. First, we call the hashCode() method of the class where element A is located to calculate the hash value of element A.
-
Then, the hash value calculates the storage location (i.e. index location) in the underlying array of HashSet through some algorithm.
-
Determine whether the element already exists in the current position of the array:
If there are no other elements in this position, element A is added successfully (case 1)
If there are other elements B (or multiple elements in the form of A linked list), compare the hash values of elements A and BIf the hash values are different, element A is added successfully (case 2)
If the hash values are the same, you need to call the equals() method in the class where element A is locatedIf the equals() method returns true, it means that element A and element B are the same, and the addition fails
If the equals() method returns false, it indicates that element A is different from element B, and the addition is successful (case 3)For cases 2 and 3 where the addition is successful, element A and the data already existing at the specified index position are stored in A linked list
Specific storage mode
JDK7: element A is placed in the array and points to the original element
JDK8: the original element is placed in the array and points to element A
Conclusion: seven up and eight down
practice
Exercise one
Create five objects of the Employee class, put them into the TreeSet collection, sort the elements in the collection in the following two ways, and traverse the output:
- Make the Employee class implement the Comparable interface and sort by name.
- When creating a TreeSet, the Comparator object is passed in and sorted by birthday date.
Employee birthday class
package com.laoyang.test.day4; /** * @ClassName MyDate * @Description: Birthday class * @Author Laoyang * @Date 2021/10/10 10:16 */ public class MyDate implements Comparable { private int year; private int month; private int day; public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public int getDay() { return day; } public void setDay(int day) { this.day = day; } public MyDate(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } public MyDate() { } @Override public String toString() { return "MyDate{" + "year=" + year + ", month=" + month + ", day=" + day + '}'; } @Override public int compareTo(Object o) { if (o instanceof MyDate) { MyDate myDate = (MyDate) o; // Judgment year int compareA = Integer.compare(this.getYear(), myDate.getYear()); if (compareA != 0) { return compareA; } // Judgment month int compareB = Integer.compare(this.getMonth(), myDate.getMonth()); if (compareB != 0) { return compareB; } else { // Judgment day return Integer.compare(this.getDay(), myDate.getDay()); } } throw new RuntimeException("Inconsistent type"); } }
Employee category
package com.laoyang.test.day4; /** * @ClassName Employee * @Description: Employee category * @Author Laoyang * @Date 2021/10/10 10:15 */ public class Employee implements Comparable { private String name; private int age; private MyDate birthday; public Employee() { } public Employee(String name, int age, MyDate birthday) { this.name = name; this.age = age; this.birthday = birthday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public MyDate getBirthday() { return birthday; } public void setBirthday(MyDate birthday) { this.birthday = birthday; } @Override public String toString() { return "Employee{" + "name='" + name + '\'' + ", age=" + age + ", birthday=" + birthday + '}'; } @Override public int compareTo(Object o) { if (o instanceof Employee) { Employee employee = (Employee) o; return this.name.compareTo(employee.name); } throw new RuntimeException("Inconsistent type"); } }
Test class
package com.laoyang.test.day4; import org.junit.Test; import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; /** * @ClassName EmployeeTest * @Description: Test class * @Author Laoyang * @Date 2021/10/10 10:21 */ public class EmployeeTest { /** * Natural sorting * Sort by employee name */ @Test public void testOne() { Employee employeeA = new Employee("David",18,new MyDate(2003,2,20)); Employee employeeB = new Employee("Jerome",32,new MyDate(1988,5,18)); Employee employeeC = new Employee("Aaron",21,new MyDate(2000,3,11)); Employee employeeD = new Employee("Dennis",15,new MyDate(2006,6,1)); Employee employeeE = new Employee("Robinson",19,new MyDate(2002,10,6)); TreeSet set = new TreeSet(); set.add(employeeA); set.add(employeeB); set.add(employeeC); set.add(employeeD); set.add(employeeE); Iterator iterator = set.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } /** * Custom sorting * Sort according to employee birthday information */ @Test public void testTwo() { Employee employeeA = new Employee("David",18,new MyDate(2003,2,20)); Employee employeeB = new Employee("Jerome",32,new MyDate(1988,5,18)); Employee employeeC = new Employee("Aaron",21,new MyDate(2000,3,11)); Employee employeeD = new Employee("Dennis",15,new MyDate(2006,6,1)); Employee employeeE = new Employee("Robinson",19,new MyDate(2003,10,6)); Comparator comparator = new Comparator() { @Override public int compare(Object o1, Object o2) { if (o1 instanceof Employee && o2 instanceof Employee) { Employee employeeA = (Employee) o1; Employee employeeB = (Employee) o2; MyDate myDateA = employeeA.getBirthday(); MyDate myDateB = employeeB.getBirthday(); // Method 1: write corresponding judgment in corresponding method // //Judgment year // int compareA = Integer.compare(myDateA.getYear(), myDateB.getYear()); // if (compareA != 0) { // return compareA; // } // //Judgment month // int compareB = Integer.compare(myDateA.getMonth(), myDateB.getMonth()); // if (compareB != 0) { // return compareB; // } else { // //Judgment day // return Integer.compare(myDateA.getDay(), myDateB.getDay()); // } // Method 2: judge in MyDate class, and then call directly return myDateA.compareTo(myDateB); } else { throw new RuntimeException("Inconsistent type"); } } }; TreeSet set = new TreeSet(comparator); set.add(employeeA); set.add(employeeB); set.add(employeeC); set.add(employeeD); set.add(employeeE); Iterator iterator = set.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } }
Exercise 2
Remove duplicate numeric values in the List, which is required to be as simple as possible
package com.laoyang.test.day4; import java.util.ArrayList; import java.util.HashSet; import java.util.List; /** * @ClassName ListDeduplication * @Description: Exercise 2: remove duplicate numeric values in the List. It is required to be as simple as possible * @Author Laoyang * @Date 2021/10/10 11:06 */ public class ListDeduplication { public static List duplicateList(List list) { HashSet set = new HashSet(); set.addAll(list); return new ArrayList(set); } public static void main(String[] args) { List list = new ArrayList(); /* If a custom class is added to the list, the hashCode() and equals() methods need to be overridden in the custom class */ list.add(new Integer(1)); list.add(new Integer(2)); list.add(new Integer(2)); list.add(new Integer(4)); list.add(new Integer(4)); List list2 = duplicateList(list); for (Object integer : list2) { System.out.println(integer); } } }
Use of Map
introduce
Map: double column data, which stores the data of key value pairs
- Map and Collection exist side by side. Used to save data with mapping relationship: key value
- The key and value in the Map can be data of any reference type
- The key s in the Map are stored in a Set and cannot be repeated. That is, the classes corresponding to the same Map object must override the hashCode() and equals() methods
- String class is often used as the "key" of Map
- There is a one-way one-to-one relationship between key and value, that is, a unique and definite value can always be found through the specified key
common method
Add, delete and modify
method | effect |
---|---|
Object put(Object key,Object value) | Add (or modify) the specified key value to the current map object |
void putAll(Map m) | Store all key value pairs in m into the current map |
Object remove(Object key) | Remove the key value pair of the specified key and return value |
void clear() | Clear all data in the current map |
Operation of element query
method | effect |
---|---|
Object get(Object key) | Gets the value corresponding to the specified key |
boolean containsKey(Object key) | Whether to include the specified key |
boolean containsValue(Object value) | Whether to include the specified value |
int size() | Returns the number of key value pairs in the map |
boolean isEmpty() | Judge whether the current map is empty |
boolean equals(Object obj) | Judge whether the current map and parameter object obj are equal |
Methods of meta view operation
method | effect |
---|---|
Set keySet() | Returns the Set set composed of all key s |
Collection values() | Returns a Collection of all value s |
Set entrySet() | Returns the Set set composed of all key value pairs |
case
package com.laoyang.test.day5; import org.junit.Test; import java.util.*; /** * @ClassName MapMethod * @Description: Map Common methods in * @Author Laoyang * @Date 2021/10/13 11:04 */ public class MapMethod { /** Add, delete and modify: Object put(Object key,Object value): Add (or modify) the specified key value to the current map object void putAll(Map m):Store all key value pairs in m into the current map Object remove(Object key): Remove the key value pair of the specified key and return value void clear(): Clear all data in the current map */ @Test public void testOne(){ // put(Object key,Object value) Map map = new HashMap(); // add to map.put("AA", 123); map.put(111, 321); map.put("bb", 56); // modify map.put("AA", 99); System.out.println(map); // {AA=99, bb=56, 111=321} // putAll(Map m) Map maps = new HashMap(); maps.put("CC", 123); maps.put("DD", 123); map.putAll(maps); System.out.println(map); // {AA=99, bb=56, CC=123, DD=123, 111=321} // remove(Object key) map.remove("CC"); System.out.println(map); // {AA=99, bb=56, DD=123, 111=321} // clear(): Note: this method does not change all elements to null, but directly changes back to the newly created appearance (without any elements) map.clear(); System.out.println(map.size()); // 0 System.out.println(map); // {} } /** Operation of element query: Object get(Object key): Gets the value corresponding to the specified key boolean containsKey(Object key): Whether to include the specified key boolean containsValue(Object value): Whether to include the specified value int size(): Returns the number of key value pairs in the map boolean isEmpty(): Judge whether the current map is empty boolean equals(Object obj): Judge whether the current map and parameter object obj are equal */ @Test public void testTwo() { Map map = new HashMap(); map.put("AA", 123); map.put(111, 321); map.put("bb", 56); // get(Object key): returns null if the corresponding key value cannot be found System.out.println(map.get("BB")); // null System.out.println(map.get("bb")); // 56 // containsKey(Object key) boolean A1 = map.containsKey("AA"); boolean A2 = map.containsKey("aa"); System.out.println(A1); // true System.out.println(A2); // false // containsValue(Object value): if the same value exists, as long as you find the first one, you won't continue to find it boolean B1 = map.containsValue(123); boolean B2 = map.containsValue(345); System.out.println(B1); // true System.out.println(B2); // false // size() System.out.println(map.size()); // 3 // isEmpty() boolean empty = map.isEmpty(); System.out.println(empty); // false Map map1 = new HashMap(); System.out.println(map1.isEmpty()); // true // equals(Object obj) System.out.println(map.equals(map1)); // false Map maps = new HashMap(); maps.put("AA", 123); maps.put(111, 321); maps.put("bb", 56); System.out.println(map.equals(maps)); // true } /** Method of metaview operation (traversal): Set keySet(): Returns the Set set composed of all key s Collection values(): Returns a Collection of all value s Set entrySet(): Returns the Set set composed of all key value pairs Ps: Because they are all kinds of sets, you can use for, foreach, iterator, and Lambda expressions in jkd8 */ @Test public void testThree() { Map map = new HashMap(); map.put("AA", 123); map.put(111, 321); map.put("bb", 56); // map.iterator() / / iterator() cannot be called directly // keySet(): traverse all key values Iterator iterator = map.keySet().iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } System.out.println("-----------------------------"); // values(): traverse all value values Collection values = map.values(); for (Object value : values) { System.out.println(value); } System.out.println("-----------------------------"); /* Traverse all key values */ // Method 1: entrySet() Set set = map.entrySet(); Iterator iterator1 = set.iterator(); while (iterator1.hasNext()) { Object obj = iterator1.next(); // All elements in the entry set collection are entries Map.Entry entry = (Map.Entry) obj; System.out.println(entry.getKey() + " = " + entry.getValue()); } System.out.println("-----------------------------"); // Mode II Iterator key = map.keySet().iterator(); while (key.hasNext()) { Object obj = key.next(); Object value = map.get(obj); System.out.println(obj + " = " + value); } } }
summary
Add: put(Object key, Object value), putAll(Map m)
Delete: remove(Object key)
Change: put(Object key, Object value)
Query: get(Object key)
Length: size()
Traversal: keySet(), values(), entrySet()
Map implementation class
-
HashMap: as the main implementation class of Map (released by JDK1.2); The thread is unsafe and the efficiency is high; Store null key and value;
Underlying structure of JDK7 and before: array + linked list
The underlying structure of JDK8: array + linked list + red black tree
-
LinkedHashMap: (JDK1.4 release); Subclass of HashMap; Ensure that when traversing Map elements, they can be traversed in the order of addition (on the basis of the original HashMap underlying structure, a pair of pointers are added to point to the previous and subsequent elements)
For frequent traversal operations, this kind of execution is more efficient than HashMap
-
TreeMap: (JDK1.2 release); Ensure that the added key value pairs are sorted to realize sorting traversal (at this time, consider the natural sorting or customized sorting of keys); Red and black trees are used at the bottom;
-
Hashtable: as an ancient implementation class (released by JDK1.0); Thread safety and low efficiency; null key and value cannot be stored;
-
Properties: (JDK1.0 release); Subclass of Hashtable; Commonly used to process configuration files; Both key and value are String types;
Use of HashMap
Understanding of HashMap structure
Keys in Map: unordered and cannot be repeated. Use Set to store all keys (the class of the key needs to override equals() and hashCode(), taking HashMap as an example)
Value in Map: unordered and repeatable. Use Collection to store all values (the class where value belongs needs to override equals())
A key value pair: key value constitutes an Entry object
Entries in Map: unordered and non repeatable. Use Set to store all entries
Underlying implementation principle of HashMap
Take JDK7 as an example:
HashMap map = new HashMap(); // After instantiation, the bottom layer creates a one-dimensional array Entry[] table with a length of 16; ..Suppose we have put I have some data.. map.put(key1, value1);
You can see how JDK7 implements the process of adding elements
The process of adding elements to HashMap
JDK7
-
First, call hashCode() of the class where key1 is located to calculate the hash value of key1;
-
Then, the hash value is calculated by some algorithm to get the storage position in the Entry array;
-
Judge whether there is data in the current position:
If the data in this location is empty, key1-value1 is added successfully (case 1)
If the data in this location is not empty (which means that there are one or more data in this location (in the form of linked list)), compare the hash values of key1 and one or more existing dataIf the hash values of key1 and existing data are different, key1-value1 is added successfully (case 2)
If the hash value of key1 is the same as that of an existing data, call equals() of the class where key1 is located to compare the values of key1 and one or more existing dataIf equals() returns false, key1-value1 is added successfully (case 3)
If equals() returns true, replace the value value of the same key with value1Such as like as two peas and A, and then add a new value C, C key (hash value and value) is exactly the same as A, which will give value value of C to A of B at this time, C.
This is equivalent to a modification operationSupplement: for case 2 and case 3: at this time, key1-value1 and the original data are stored in a linked list
Capacity expansion: in the process of continuous addition, capacity expansion will be involved. When the critical value is exceeded (and the location to be stored is not empty), capacity expansion will begin.
By default, the capacity will be expanded to twice the original capacity, and the original data will be copied to the expanded array
JDK8 is different from JDK7 in the underlying implementation
-
HashMap map = new HashMap(); // The underlying layer did not create an array with a length of 16
-
The underlying array of JDK8 is Node [], not Entry
-
When the put() method is called for the first time, the underlying layer will create an array with a length of 16
-
The underlying structure of JDK7 is only: array + linked list; JDK8 underlying structure: array + linked list + red black tree
When the number of data in the form of a linked list of elements at an index position of the array is > 8 and the current array length is > 64, all data at this index position is stored using a red black tree.
This is to improve our query efficiency. Once there are more data, the efficiency of using array search will be relatively low (because we need to traverse it completely every time); The red black tree is orderly. The left side of the small row and the right side of the large row can exclude half of the data for searching, which can save more time.
Partial source code
Note: I added Chinese comments myself. Some were interpreted according to my own meaning, and some were translated according to the comments in the source code. So don't fight too hard
JDK7
package java.util; import java.io.*; public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { /** * Default initial capacity - must be a power of 2 */ static final int DEFAULT_INITIAL_CAPACITY = 16; /** * The load factor to use when not specified in the constructor */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * Maximum capacity, used when two constructors with parameters implicitly specify a higher value. Must be a power of 2 < = 1 < < 30 */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * An array of data. The length must always be a power of 2 */ transient Entry<K,V>[] table; public HashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); } public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); // Find a power of 2 >= initialCapacity int capacity = 1; // Determines the length of the array created (for example, we manually set the length of the HashMap to 15, but actually created an array with the length of 16) while (capacity < initialCapacity) capacity <<= 1; this.loadFactor = loadFactor; /* threshold: For the critical value (capacity * loadFactor), HashMap does not start to expand when the array cannot fit. Because it may be stored down in the form of a linked list, it usually starts to expand when the critical value is reached capacity * loadFactor = 16 * 0.75 = 12 MAXIMUM_CAPACITY: Maximum capacity */ threshold = (int)Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); table = new Entry[capacity]; useAltHashing = sun.misc.VM.isBooted() && (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); init(); } /** * Associates the specified value with the specified key in this mapping. If the mapping previously contained a key, the old value is replaced * * @param key The key associated with the specified value * @param value The value to associate with the specified key * @return The previous value associated with the key is null if the key has no mapping. (null return can also indicate that the mapping previously associated null with key.) */ public V put(K key, V value) { if (key == null) return putForNullKey(value); // Get hash value int hash = hash(key); // Calculate the storage location of data at the bottom of HashMap through the corresponding algorithm int i = indexFor(hash, table.length); // Determine whether an element exists in the current position for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; // Determine whether the hash value is the same as the value itself if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { // If the hash value and key value are the same, replace the value value of the existing key V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; // If there is no element, the hash value is different, and the value itself is different, the addition method will be executed addEntry(hash, key, value, i); return null; } /** * DP Hash */ final int hash(Object k) { int h = 0; if (useAltHashing) { if (k instanceof String) { return sun.misc.Hashing.stringHash32((String) k); } h = hashSeed; } h ^= k.hashCode(); // This function ensures that hashcodes that differ only by a constant multiple at each bit position have a limited number of conflicts (about 8 at the default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } /** * Find the corresponding storage location according to the hash value */ static int indexFor(int h, int length) { return h & (length-1); } /** * Capacity expansion method * If you need to expand capacity, you can add data first. If you don't need to, you can directly execute the add method */ void addEntry(int hash, K key, V value, int bucketIndex) { // If the current critical value is less than or equal to the number of key value mappings and the current array position is not empty, the capacity expansion operation is performed if ((size >= threshold) && (null != table[bucketIndex])) { // Capacity expansion: when the critical value is reached and the current array position is not empty, the capacity of the array will be doubled by default resize(2 * table.length); hash = (null != key) ? hash(key) : 0; bucketIndex = indexFor(hash, table.length); } createEntry(hash, key, value, bucketIndex); } /** * New method */ void createEntry(int hash, K key, V value, int bucketIndex) { // Take out the data in the original position Entry<K,V> e = table[bucketIndex]; // Then, put the newly created Entry object in the current location and store it in a linked list (from top to bottom, similar to HashSet (JDK7)) table[bucketIndex] = new Entry<>(hash, key, value, e); size++; } Entry(int h, K k, V v, Entry<K,V> n) { value = v; next = n; key = k; hash = h; } }
JDK8
package java.util; import java.io.IOException; import java.io.InvalidObjectException; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { /** * The load factor to use when not specified in the constructor. */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * Load factor of hash table * @serial */ final float loadFactor; /** * An array of data. */ transient Node<K,V>[] table; /** * constructor */ public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted } /** * Associates the specified value with the specified key in this mapping. If the mapping previously contained a key, the old value is replaced * * @param key The key associated with the specified value * @param value The value to associate with the specified key * @return The previous value associated with the key is null if the key has no mapping. (null return can also indicate that the mapping previously associated null with key.) */ public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } /** * Get hash value */ static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } /** * Implementation of Map.put and related methods * * @param hash Hash of key * @param key key * @param value Value to place * @param onlyIfAbsent If true, do not change the existing value * @param evict If false, the table is in create mode * @return Previous value, null if none */ final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); 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; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; } /** * Initialize or double the table size. * If it is blank, it is allocated according to the initial capacity target held in the field threshold. * Otherwise, because we use a power of 2 extension, the elements in each bin must maintain the same index or move at an offset of a power of 2 in the new table */ final Node<K,V>[] resize() { Node<K,V>[] oldTab = table; int oldCap = (oldTab == null) ? 0 : oldTab.length; int oldThr = threshold; int newCap, newThr = 0; if (oldCap > 0) { if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; // double threshold } else if (oldThr > 0) // initial capacity was placed in threshold newCap = oldThr; else { // zero initial threshold signifies using defaults newCap = DEFAULT_INITIAL_CAPACITY; newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } if (newThr == 0) { float ft = (float)newCap * loadFactor; newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE); } threshold = newThr; @SuppressWarnings({"rawtypes","unchecked"}) Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; table = newTab; if (oldTab != null) { for (int j = 0; j < oldCap; ++j) { Node<K,V> e; if ((e = oldTab[j]) != null) { oldTab[j] = null; if (e.next == null) newTab[e.hash & (newCap - 1)] = e; else if (e instanceof TreeNode) ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); else { // preserve order Node<K,V> loHead = null, loTail = null; Node<K,V> hiHead = null, hiTail = null; Node<K,V> next; do { next = e.next; if ((e.hash & oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); if (loTail != null) { loTail.next = null; newTab[j] = loHead; } if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; } } } } } return newTab; } /** * Replace all linked nodes in the bin at the given hash index unless the table is too small, in which case resize instead. */ final void treeifyBin(Node<K,V>[] tab, int hash) { int n, index; Node<K,V> e; if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) resize(); else if ((e = tab[index = (n - 1) & hash]) != null) { TreeNode<K,V> hd = null, tl = null; do { TreeNode<K,V> p = replacementTreeNode(e, null); if (tl == null) hd = p; else { p.prev = tl; tl.next = p; } tl = p; } while ((e = e.next) != null); if ((tab[index] = hd) != null) hd.treeify(tab); } } }
Important constants in HashMap source code
- DEFAULT_ INITIAL_ Capability: default capacity of HashMap: 16
- DEFAULT_LOAD_FACTOR: default load factor of HashMap: 0.75
- threshold: critical value of expansion, = capacity * filling factor: 16 * 0.75 = 12
- TREEIFY_THRESHOLD: if the length of the linked list in the Bucket is greater than the default value, it will be converted into a red black tree: 8
- MIN_ TREEIFY_ Capability: minimum hash table capacity when nodes in the bucket are trealized: 64
Here are just a few examples. There are others you can check the source code yourself
Use of LinkedHashMap
-
LinkedHashMap is a subclass of HashMap
-
Based on the HashMap storage structure, a pair of two-way linked lists are used to record the order of adding elements
-
Similar to LinkedHashSet
LinkedHashMap underlying principle (understand)
The underlying structure of LinkedHashMap is the same as that of HashMap, because LinkedHashMap inherits from HashMap
Difference: the LinkedHashMap internally provides an Entry to replace the Node in the HashMap
LinkedHashMap internal class:
static class Entry<K,V> extends HashMap.Node<K,V> { Entry<K,V> before, after; // Able to record the order of added elements Entry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); } }
Internal classes in HashMap
static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; }
Use of TreeMap
introduce
- When storing key value pairs in TreeMap, you need to sort them according to key value pairs. TreeMap can ensure that all key value pairs are in an orderly state.
- The underlying TreeSet uses a red black tree structure to store data.
- Adding key value to TreeMap requires that the key must be an object created by the same class, because it needs to be sorted by key: natural sorting and custom sorting.
Note: you can only sort by key, not by value!!!
case
package com.laoyang.test.day5; import org.junit.Test; import java.util.*; /** * @ClassName TreeMapTest * @Description: TreeMap Use of * @Author Laoyang * @Date 2021/10/13 15:08 */ public class TreeMapTest { /** * Natural sorting */ @Test public void testOne() { TreeMap map = new TreeMap(); User userA = new User("Tom", 22); User userB = new User("Jerry", 18); User userC = new User("Jim", 35); User userD = new User("Mike", 6); map.put(userA, 60); map.put(userB, 76); map.put(userC, 32); map.put(userD, 100); Set set = map.entrySet(); Iterator iterator = set.iterator(); while (iterator.hasNext()) { Object obj = iterator.next(); Map.Entry entry = (Map.Entry) obj; System.out.println(entry.getKey() + "The results are:" + entry.getValue()); } } /** * Custom sorting */ @Test public void testTwo() { Comparator comparator = new Comparator() { // Sort by age @Override public int compare(Object o1, Object o2) { if (o1 instanceof User && o2 instanceof User) { User userA = (User) o1; User userB = (User) o2; return Integer.compare(userA.getAge(), userB.getAge()); } throw new RuntimeException("Inconsistent type"); } }; TreeMap map = new TreeMap(comparator); User userA = new User("Tom", 22); User userB = new User("Jerry", 18); User userC = new User("Jim", 35); User userD = new User("Mike", 6); map.put(userA, 60); map.put(userB, 76); map.put(userC, 32); map.put(userD, 100); Set set = map.entrySet(); Iterator iterator = set.iterator(); while (iterator.hasNext()) { Object obj = iterator.next(); Map.Entry entry = (Map.Entry) obj; System.out.println(entry.getKey() + "The results are:" + entry.getValue()); } } } class User implements Comparable { private String name; private int age; /** * Override the equals() method */ @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return age == user.age && Objects.equals(name, user.name); } /** * Override hashCode() method */ @Override public int hashCode() { return Objects.hash(name, age); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public User(String name, int age) { this.name = name; this.age = age; } public User() { } /** * Sort by name from small to large */ @Override public int compareTo(Object o) { if (o instanceof User) { User user = (User) o; int i = this.name.compareTo(user.name); if (i != 0) { return i; } else { return 0; } } throw new RuntimeException("Inconsistent type"); } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
Use of Hashtable
- Hashtable is an ancient Map implementation class, which is provided by JDK1.0. Unlike HashMap, hashtable is thread safe.
- The implementation principle and function of Hashtable are the same as that of HashMap. The bottom layer uses hash table structure, which has fast query speed and can be used with each other in many cases. Unlike HashMap, Hashtable does not allow null as key and value.
- Like HashMap, Hashtable cannot guarantee the order of key value pairs.
- Hashtable judges that two key s are equal and two value s are equal, which is consistent with HashMap.
Use of Properties
introduce
- The Properties class is a subclass of Hashtable, which is used to process property files
- Since the key and value in the Properties file are of string type, the key and value in Properties are of string type
- When accessing data, it is recommended to use setProperty(String key,String value) method and getProperty(String key) method
case
Configuration file - jdbc.properties
username=root password=123456
The file is created under the parent project (because this is just to test the effect, you can write anything after creation)
Note: spaces cannot appear on both sides of the equal sign (=) in the configuration file, such as name = "AAA"
Test class
package com.laoyang.test.day5; import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; /** * @ClassName PropertiesTest * @Description: Properties Use of * @Author Laoyang * @Date 2021/10/13 15:28 */ public class PropertiesTest { /** Properties: It is commonly used to process configuration files. Both key and value are String types */ public static void main(String[] args) { FileInputStream stream = null; try { Properties properties = new Properties(); stream = new FileInputStream("jdbc.properties"); properties.load(stream); String name = properties.getProperty("username"); String password = properties.getProperty("password"); System.out.println("Account number:" + name + ",Password is:" + password); } catch (IOException e) { System.out.println(e.getMessage()); } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
Sometimes writing configuration files leads to garbled code, which may be because the coding format is not set properly
Extension: if you do not want the configuration file to be garbled, you need to set the corresponding encoding format before creating the configuration file (if the file has been created and garbled, you need to delete the corresponding configuration file first, and then make encoding settings before writing, otherwise the correct effect will not be achieved)
If you are using IDEA, you need to tick File > editor > file encodings > International native to ASCII conversion
Use of Collections tool class
Tool class for manipulating Arrays: Arrays
introduce
- 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. It also provides methods to set immutable collection objects and realize synchronous control over collection objects
common method
Sort operation
method | effect |
---|---|
reverse(List list) | Inverts all elements in the collection |
shuffle(List list) | Randomly sort collection elements |
sort(List list) | Sort collection elements naturally |
sort(List list, Comparator com) | Custom sort collection elements |
swap(List list,int i, int j) | Swaps elements at a specified location in a collection |
Find, replace
method | effect |
---|---|
Object max(Collection) | Returns the largest element in a given set according to the natural order of the elements |
Object max(Collection,Comparator) | Returns the largest element in a given collection according to the custom order of elements |
Object min(Collection) | Returns the smallest element in a given set according to the natural order of the elements |
Object min(Collection,Comparator) | Returns the smallest element in a given set according to the custom order of elements |
int frequency(Collection,Object) | Returns the number of occurrences of the specified element in the specified collection |
void copy(List dest,List src) | Copy the contents of src to dest |
boolean replaceAll(List list,Object oldVal,Object newVal) | Replace the old value (newVal) in the List with the new value (oldVal) |
Note that copy()
Synchronous control
The Collections class provides multiple synchronizedXxx() methods, which can wrap the specified collection into a thread synchronized collection, so as to solve the thread safety problem when multiple threads access the collection concurrently
method | effect |
---|---|
synchronizedCollection(Collection c) | Returns a synchronized (thread safe) collection supported by the specified collection |
synchronizedList(List list) | Returns a list of synchronization (thread safe) supported by the specified list |
synchronizedMap(Map map) | Returns a synchronous (thread safe) Map supported by the specified Map |
synchronizedSet(Set set) | Returns the synchronized (thread safe) set supported by the specified set |
synchronizedSortedMap(SortedMap m) | Returns a synchronous (thread safe) sort map supported by the specified sort map |
synchronizedSortedSet(SortedSet s) | Returns the synchronous (thread safe) sort set supported by the specified sort set |
case
package com.laoyang.test.day6; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * @ClassName CollectionUtil * @Description: Collections Use of tool classes * @Author Laoyang * @Date 2021/10/13 15:59 */ public class CollectionsUtil { /** Sorting operations: (all static methods) reverse(List): Reverse the order of elements in the List shuffle(List): Random sorting of List collection elements sort(List): Sorts the specified List collection elements in ascending order according to the natural order of the elements sort(List,Comparator): Sorts the List collection elements according to the order generated by the specified Comparator swap(List,int, int): Exchange the elements at i and j in the specified list collection */ @Test public void testOne() { List list = new ArrayList(); list.add(22); list.add(57); list.add(33); list.add(19); System.out.println(list); // [22, 57, 33, 19] // Collections.reverse(list); // Invert collection elements // Collections.shuffle(list); // Randomly sort collection elements // Collections.sort(list); // Sort the collection elements naturally. If you want to use custom sorting, you need to add a Comparator parameter Collections.swap(list, 1, 3); // Swaps elements at a specified location in a collection System.out.println(list); } /** Find, replace Object max(Collection): Returns the largest element in a given set according to the natural order of the elements Object max(Collection,Comparator): Returns the largest element in a given collection in the order specified by the Comparator Object min(Collection): Returns the smallest element in a given set according to the natural order of the elements Object min(Collection,Comparator): Returns the smallest element in a given set according to the custom order of elements int frequency(Collection,Object): Returns the number of occurrences of the specified element in the specified collection void copy(List dest,List src): Copy the contents of src to dest boolean replaceAll(List list,Object oldVal,Object newVal): Replace all old values of the List object with the new values */ @Test public void testTwo() { List list = new ArrayList(); list.add(22); list.add(57); list.add(57); list.add(33); list.add(19); System.out.println(list); // [22, 57, 57, 33, 19] // max(Collection coll): find the maximum value in the collection according to the natural sorting. To customize the sorting, you need to add the Comparator parameter System.out.println(Collections.max(list)); // 57 // min(Collection coll): find the minimum value in the collection according to the natural sorting, and add the Comparator parameter to customize the sorting System.out.println(Collections.min(list)); // 19 // frequency(Collection coll, Object obj): System.out.println(Collections.frequency(list, 57)); // 2 System.out.println("------------------------"); //copy(List dest, List src): copy, copy the values in src to dest /* // Exception: java.lang.IndexOutOfBoundsException: Source does not fit in dest List list1 = new ArrayList(); Collections.copy(list1, list); */ // Correct writing List list1 = Arrays.asList(new Object[list.size()]); System.out.println(list1.size()); // 5 Collections.copy(list1, list); // Successful execution System.out.println(list1); System.out.println("------------------------"); //Replaceall (List, Object oldVal, Object newVal): replace the old value (newVal) in the List with the new value (oldVal) Collections.replaceAll(list, 22, 99); System.out.println(list); // [99, 57, 57, 33, 19] } /** Collections Class, which enables you to wrap the specified collection into a thread synchronized collection, This can solve the thread safety problem when multithreading accesses the collection concurrently */ @Test public void testThree() { List list = new ArrayList(); list.add(22); list.add(57); list.add(57); list.add(33); list.add(19); System.out.println(list); // [22, 57, 57, 33, 19] // The returned list1 is thread safe List list1 = Collections.synchronizedList(list); } }
Exercise one
Please input 10 integers randomly from the keyboard, save them to the List, and display them in reverse order, from large to small
package com.laoyang.test.day6; import java.util.*; /** * @ClassName Practise * @Description: Exercise one * @Author Laoyang * @Date 2021/10/13 17:15 */ public class ExerciseOne { public static void main(String[] args) { Scanner input = new Scanner(System.in); List list = new ArrayList(); int j; for (int i = 0; i < 10; i++) { System.out.print("Please enter an integer:"); j = input.nextInt(); list.add(j); } Collections.sort(list); Collections.reverse(list); System.out.println(list); } }
Exercise 2
Enter student names and test scores into the collection, and display the names of the top three students by score
package com.laoyang.test.day6; import org.junit.Test; import java.util.*; /** * @ClassName ExerciseTwo * @Description: Exercise 2 * @Author Laoyang * @Date 2021/10/13 17:28 */ public class ExerciseTwo { @Test public void testOne() { List list = new ArrayList(); list.add(new Student("Tom", 60)); list.add(new Student("Jerry", 80)); list.add(new Student("Jim", 73)); list.add(new Student("Mike", 52)); list.add(new Student("Noob", 90)); Collections.sort(list, new Comparator<Object>() { @Override public int compare(Object o1, Object o2) { if (o1 instanceof Student && o2 instanceof Student) { Student stuA = (Student) o1; Student stuB = (Student) o2; return -Double.compare(stuA.getFraction(), stuB.getFraction()); } throw new RuntimeException("Inconsistent type"); } }); for (int i = 0; i < 3; i++) { System.out.println(list.get(i)); } } } class Student { private String name; private double fraction; public Student() { } public Student(String name, double fraction) { this.name = name; this.fraction = fraction; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getFraction() { return fraction; } public void setFraction(double fraction) { this.fraction = fraction; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", fraction=" + fraction + '}'; } }
Interview questions
1, What are the similarities and differences of ArrayList, LinkedList and Vector?
Similarities: the three classes implement the List interface, and the characteristics of storing data are the same (they are ordered and repeatable data)
difference:
ArrayList: as the main implementation class of the List interface (JDK1.2 appears); High execution efficiency (thread unsafe); The underlying layer uses Object[] elementData for storage;
LinkedList: JDK1.2 appears; For frequent insert and delete operations, the efficiency of using this type is higher than that of ArrayList; The bottom layer uses two-way linked list storage;
Vector: as an ancient implementation class of the List interface (JDK1.0 appears); Low execution efficiency (thread safe); The underlying layer uses Object[] elementData for storage;
The List interface also appears in JDK1.2
2, What is the final print result of the following code?
Question 1
package com.laoyang.test.day2; import org.junit.Test; import java.util.ArrayList; import java.util.List; /** * @ClassName ListInterviewQuestions * @Description: Interview questions * @Author Laoyang * @Date 2021/10/2 10:43 */ public class ListInterviewQuestions { @Test public void testOne() { List list = new ArrayList(); list.add(1); list.add(2); list.add(3); updateList(list); System.out.println(list); //1,2 } private static void updateList(List list) { // By default, when deleting integer elements, remove(int index) in the List will be called first instead of remove(Object obj) list.remove(2); // Delete according to subscript, [1, 2] //list.remove(new Integer(2)); // Delete according to element, [1, 3] } }
Main considerations: distinguish between remove(int index) and remove(Object obj) in the list
Here are two ways. You can open the comments to test and see the final effect
Question 2
package com.laoyang.test.day4; import org.junit.Test; import java.util.HashSet; import java.util.Objects; /** * @ClassName Set * @Description: Interview questions * @Author Laoyang * @Date 2021/10/10 11:09 */ public class SetInterviewQuestions { @Test public void test() { HashSet set = new HashSet(); Person p1 = new Person(1001,"AA"); Person p2 = new Person(1002,"BB"); set.add(p1); set.add(p2); // Modify the name value of p1 in set p1.name = "CC"; /* At this time, remove finds 1001, the storage location of CC p1 is stored according to the hash value of 1001 and AA Therefore, remove cannot find p1 at this time, so it cannot be deleted successfully */ set.remove(p1); System.out.println(set); // 1002,BB;1001,CC /* Because p1 is stored according to the location found by 1001 and AA, even if it is later modified to 1001 and CC, the location has not changed Therefore, 1001 and CC here can be added successfully */ set.add(new Person(1001,"CC")); System.out.println(set); // 1002,BB;1001,CC;1001,CC /* Here, the hash value of AA is consistent with p1, but the value of p1 is now 1001, CC Therefore, after the hash values are the same, call equals() to determine whether the values of the two objects are the same, AA= CC, so it can be added successfully */ set.add(new Person(1001,"AA")); System.out.println(set); // 1002,BB;1001,CC;1001,CC;1001,AA } } class Person { public int id; public String name; public Person(int id, String name) { this.id = id; this.name = name; } public Person() { } @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return id == person.id && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(id, name); } }
3, The underlying implementation principle of HashMap?
If you can't understand the above, baidu on your own
4, What are the similarities and differences between HashMap and Hashtable?
If you can't understand the above, baidu on your own
5, What are the similarities and differences between CurrentHashMap and Hashtable?
Skip temporarily
6, What is the difference between Collections and Collections?
A Collection is a Collection interface that stores a single column interface
Collection s is a tool class that operates on Collections
7, What impact does the size of load factor have on HashMap?
- The load factor determines the data density of HashMap
- The larger the load factor, the higher the density, the higher the probability of collision, and the longer the linked list in the array, resulting in an increase in the number of comparisons during query or insertion and a decline in performance.
- The smaller the load factor, the easier it is to trigger capacity expansion, and the smaller the data density, which means that the smaller the probability of collision, the shorter the linked list in the array, the smaller the number of comparisons during query and insertion, and the higher the performance. However, a certain amount of content space will be wasted, and frequent capacity expansion will also affect the performance.
- According to the reference and research experience of other languages, it will be considered to set the load factor to 0.7 ~ 0.75, and the average retrieval length is close to a constant.