Basic introduction to Java container

Before introducing the Java container, look at a simple container classification, in order to achieve a general understanding of Java container can be classified:

Simple container class libraries

Basic introduction container

Use Java class libraries is the container 保存对象and which is divided into two different concepts:

  1. Collection : a separate element of the sequence , these elements are subject to one or more rules. List must hold the elements of the order of insertion, and Set can not have duplicate elements. Queue according to rules to determine the queuing order of the objects produced.
  2. The Map : a pair consisting of key-value pairs , allowing you to use the keys to find value. Also known as the mapping table , associative arrays , dictionaries .

List

  1. ArrayList: good random-access element, but slow in the middle of insertion and removal of elements in List.
  2. LinkedList: insert and delete operations may be performed at low cost through the middle List, a sequential access optimization. LinkedList is relatively slow in terms of random access, but its feature set larger than ArrayList.
    • ArrayList LinkedList also like to achieve the same basic List interface.
    • The method also added LinkedList queue or deque it can be used as a stack.
    • getFirst () and element () exactly the same, return head (first element) of the list, but does not remove it, if List is empty, then throw NoSuchElementException . peek () method returns null list is empty.
    • removeFirst () and remove () is exactly the same, remove and return the head of the list, if List is empty, then throw NoSuchElementException . poll (), returns null list is empty.
    • add () and addLast () as an element is inserted into the end of the list.
    • removeLast () and pollLast () the last element of the list is removed and returned.

Stack

Stack is LIFO container. The method can be realized LinkedList has all the features of the stack, it can be directly used as LinkedList stack . Stack operations:

  • the Push () : stack.
  • PEEK () : Gets the top element, but does not remove it from the top of the stack.
  • POP () : Removes and returns the top element.

Queue

Typical FIFO queue container. LinkedList implements Queueu interfaces to support queue behavior.

  • the offer () : an element into the tail.
  • peek () and the element () will return the head without removal, element () in the queue is empty, it is thrown NoSuchElementException . peek () method returns the list is empty in null .
  • poll () and remove () Removes and returns the head. ** remove () ** If the queue is empty, then throw NoSuchElementException . poll (), returns null list is empty.

PriorityQueue

FIFO describes the most typical queue rules . So-called queuing discipline refers to the case where a given element of the set of queues, a rule to determine the next queue element pop. FIFO declaration is the next element should be the longest waiting time element.

PriorityQueue is a priority queue, its declaration of a pop element is most needed elements (highest priority).

When you call on PriorityQueue the offer () when the methods to insert an object, the object will be sorted in the queue. The default sort will use the object in the queue queue natural order , but you can provide your own Comparator to modify the order interface. PriorityQueue ensures that when you call peek (), poll () and remove () method to get the elements in the queue will be the highest priority elements.

Example of use:


public class TestQueueElement {
    public int getAge() {
        return age;
    }

    public int getSex() {
        return sex;
    }

    public String getName() {
        return name;
    }

    private int age;
    private int sex;
    private String name;

    public TestQueueElement(int age, int sex, String name) {
        this.age = age;
        this.sex = sex;
        this.name = name;
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + " { name:" + name + " ,age:" + age + ",sex:" + sex + "}";
    }
}



/**
 * 1.以age字段的升序进行排序,
 * 2.在age相同时,以name字段的长度的升序进行排序
 */
public class TestQueueElementComparator implements Comparator<TestQueueElement> {
    @Override
    public int compare(TestQueueElement o1, TestQueueElement o2) {
        int result = 0;

        if (o1.getName().length() > o2.getName().length()) {
            result += 1;
        } else if (o1.getName().length() < o2.getName().length()) {
            result -= 1;
        }

        if (o1.getAge() > o2.getAge()) {
            result += 2;
        } else if (o1.getAge() < o2.getAge()) {
            result -= 2;
        }

        return result;
    }
}


public class Main {

    public static void main(String[] args) {

        PriorityQueue<TestQueueElement> pq = new PriorityQueue<>(10, new TestQueueElementComparator());

        pq.offer(new TestQueueElement(10, 0, "name1"));
        pq.offer(new TestQueueElement(9, 0, "name1"));
        pq.offer(new TestQueueElement(11, 0, "name1"));
        pq.offer(new TestQueueElement(10, 0, "name11"));
        pq.offer(new TestQueueElement(10, 0, "name111"));
        pq.offer(new TestQueueElement(8, 0, "name"));
        pq.offer(new TestQueueElement(8, 0, "name111"));

        while (!pq.isEmpty()) {
            System.out.println(pq.poll());
        }
    }
}

输出结果:
TestQueueElement { name:name ,age:8,sex:0}
TestQueueElement { name:name111 ,age:8,sex:0}
TestQueueElement { name:name1 ,age:9,sex:0}
TestQueueElement { name:name1 ,age:10,sex:0}
TestQueueElement { name:name11 ,age:10,sex:0}
TestQueueElement { name:name111 ,age:10,sex:0}
TestQueueElement { name:name1 ,age:11,sex:0}

复制代码

Set

Deposit Set each element must be unique, since Set does not save duplicate elements. Join Set elements must be defined equals () method to ensure the uniqueness of the object. Set has the Collection exactly the same interface, Set interface does not guarantee the order of maintenance elements.

  1. HashSet: pointless Set, storage order to quickly find and design. HashSet into elements must be defined hashCode () . If there are no other restrictions, which should be the default choice because it is optimized for speed.
  2. TreeSet: save the object according to the comparison result in ascending order, the elements stored in Red - Black Tree data structure. Order to maintain Set, the bottom of the tree structure. Use it to extract the ordered sequence from a Set. Element must implement the Comparable interface.
  3. LinkedHashSet: save the object are sequentially added, used to maintain a linked list insertion order. Having HashSet query speed, and internal maintenance order list elements (inserted sequence). Thus when using iterates over Set, the result will be displayed in the order according to the insertion element. Elements must also implement hashCode () method.

SortedSet

SortedSet the elements can be sure you are ordering state.

  • Comparator comparator (): returns the current Set Comparator used; or return null, which means sorting in a natural manner.
  • Object first (): returns the first element in the container.
  • Object last (): Returns the last element in the container. .
  • SortedSet subSet (fromElement, toElement) Set the generated subset of this range is determined by the to fromElement (inclusive) to toElement, exclusive (not included) bond.
  • SortedMap headSet (toElement) Set times generated subset of the elements is less than toElement composition.
  • SortedMap tailSet (fromElement) Set subset of this generated by the element is greater than fromElement composition.

Map

Map key requirements for use with the requirements of the Set of elements is the same. Any bond must have a equals () method, if the construction is used for the hash Map, then he must also have the proper hashCode () method, if the key is used TreeMap, then it must implement Comparable.

  1. HashMap: Find technology provides the fastest, did not follow any apparent order to save the elements. HashMap is the use of object hashCode () for quick queries, this method can rapidly improve performance. In the absence of other restrictions, HashMap is the default selection. Insert and query key-value pairs overhead is fixed. Capacity provided by the constructor and the load factor, the adjusted properties of the container.
  2. TreeMap: red-black tree achieved based on a comparison result in ascending order of key-value pairs stored, they can be sorted (the order determined by Comparable or Comparator). TreeMap feature is that the results obtained are sorted. TreeMap is only with subMap () method, he can return to a sub-tree.
  3. LinkedHashMap: insertion order to save the key, just a little slower than Hashmap speed, but faster iteration and access, because it is using the linked list to maintain internal order.
  4. WeakHashMap: weak key mappings, allowing the release of the object mapping points. If the map does not refer to outside points to a key , this key can be garbage collected.
  5. ConcurrentHashMap: in a thread-safe Map, it does not involve synchronized lock.
  6. IdentityHashMap: Use == instead of equals () of the key comparing hash map.

SortedMap

Use SortedMap (TreeMap only achieve its stage), to ensure that keys are ordered state.

  • Comparator comparator (): returns the Map currently used Comparator; or return null, which means sorting in a natural manner.
  • T firstKey (): returns the first key in the Map.
  • T lastKey (): Returns the last key Map.
  • SortedMap subMap (fromKey, toKey) Map generating the subset of this range is determined by the to fromKey (inclusive) to toKey (not included) bond.
  • SortedMap headMap (toKey) Map views generated subset, the key of all keys less than toKey pairs.
  • SortedMap tailMap (fromKey) Map generating a subset of this, all the keys by a key greater than or equal to fromKey of the composition.

Iterator

Just use the container, do not know or care about the type of container to say no, just get container elements. Iterator unified way to access the container.

Iterator is an object that is to work through and select an object in the sequence, and the client programmer from having to know or care about the underlying structure of the sequence. In addition, the iterator is often called lightweight objects : it created a small price. But the use of iterators is limited:

  1. Use iterator () requires a container return the Iterator . Iterator will be ready to return the first element in the sequence.
  2. Use next () Gets the next element in the sequence.
  3. Use hasNext () to check whether there are elements in the sequence.
  4. Use remove () will return the iterator element of the newly deleted. It means calling remove () must be called before the Next () .

Iterator uses examples:

public static void main(String[] args) {

        List<Integer> list = new ArrayList<>();

        for (int i = 0; i < 10; i++) list.add(i);

        System.out.println(list.toString());

        Iterator<Integer> it = list.iterator();

        //遍历迭代器对象,循环结束,it中不在具有元素
        while (it.hasNext()) {
            Integer integer = it.next();
            System.out.println(integer.toString());
        }

        it = list.iterator();
        
        //删除it迭代器中的元素,同时list中对应的元素也被删除
        for (int i = 0; i < 5; i++) {
            it.next();
            it.remove();
        }
    }
复制代码

ListIterator

ListIterator is a more powerful Iterator subtype, it can only be used for a variety List access class. Although Iterator move only forward, but ListIterator can move bi-directional). It can also produce an index of the element relative to the previous iteration and the current position of the pointing device in the list, and may use the set () to replace the last visited its element method. You can call () listIterator method produces a directed List at the beginning of ListIterator , and also by calling listiterator (n) to create a start point for the element at list index n method ListIterator .

Example of use:


public class Test {
    private String id;

    public Test(int id) {
        this.id = "test:" + id;
    }

    @Override
    public String toString() {
        return id;
    }
}


 public static void main(String[] args) {

        List<Test> list = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            Test test = new Test(i);
            list.add(test);
        }

        System.out.println(list.toString());

        ListIterator<Test> it = list.listIterator();
        while (it.hasNext()) {
            //it.next() 获取下一个元素
            //it.nextIndex() 获取下一个元素的索引
            //it.previousIndex() 获取上一个元素的索引
            System.out.println(it.next() + "," + it.nextIndex() + "," + it.previousIndex() + ";");
        }

        System.out.println();

        // 是否有上一个元素
        while (it.hasPrevious()) {
            //it.previous() 获取上一个元素
            System.out.println(it.previous() + " ");
        }

        it = list.listIterator(3);
        while (it.hasNext()) {
            it.next();
            it.set(new Test(20));
        }
        System.out.println(list.toString());
    }
复制代码

Hash and hash code

Hash code is a relatively unique , the value of int for representing an object, which is obtained by converting certain information object is generated. hashCode () method is the root class Object, so all Java objects may be generated hash code.

First, using a hash aims: to find an object you want to use another object.

Secondly, the hash value is speed: the hash key stored somewhere to be able to find quickly. Storing a set of elements of the data structure is an array fastest, so it is used to represent the information key (note; the information of said key, rather than the key itself). Since the array is not saved key itself, but by the key to generate a digital object, which as a subscript of the array, this figure is a hash code, in the Object is defined by, and may be covered by your class hashCode () method generate.

To solve the problem of the array capacity is fixed, different keys may be generated at the same subscript. In other words, there may be a conflict. Therefore, the array is not important how much, any key can always find its location in the array.

So the query process is worth a calculated hash code, then use the hash code query array. If we can ensure there is no conflict, it may have a perfect hash function, but this is the exception. In general, the conflict is handled by external links: the array does not directly hold value, but stored value list. Then equals the value of the list () method of linear query. This part of the inquiry will naturally be slower (because linear query is the slowest query mode), however, if the hash function is good, each location of the array only less value. Thus, instead of searching the entire list, but quickly jump to a location in the array, only a few elements awakened by comparison. So that the HashMap queries faster.

When creating keys used HashMap with their class, it must be placed in a method wherein: two methods equals () and hashCode (). Use HashMap equals () determines whether the current key and the key table present in the same. hashCode () does not need to always be able to return a unique identification code, but equals () method must be strictly determine whether two objects are the same.

How to properly cover the equals ()

Right equals () method must meet the following five criteria:

  1. Reflexive: for any x, x.equals (x) must return true.
  2. Symmetry: for any x and y, if y.equals (x) returns true, x.equals (y) returns true.
  3. Transitive:, y, z, if x.equals (y) returns true, y.equals (z) returns true for any x, then x.equals (z) must return true.
  4. Consistency: for any x and y, equivalent information for comparison if the object does not change, regardless of call x.equals (y) the number of times and the results returned should be consistent, either always true, or has been false .
  5. Not null for any of x, x.equals (null) must return false.

He stressed: Default Object.equals () only address comparison object.

How to properly cover hashCode ()

After you understand how hash, write your own hashCode () has even more meaning. Therefore, the design hashCode () is the most important factor is: whenever, calling hashCode the same object () should generate the same value. So, if you hashCode () method relies on the variable data object, then the user must be careful, because when the data changes, hashCode () will generate a different hash codes, is generated corresponding to a different key. Furthermore, nor should it be hashCode () depends on the unique object information, in particular the use of this value, this will not generate a new key, can only produce bad hashCode (). It should be used to identify meaningful information within the object.

Therefore, in order to make hashCode () utility, it must be fast and must be meaningful. That is, it must generate a hash code based on the contents of the object. Therefore, the hash code does not have to be unique (should be more concerned about the production rate, rather than uniqueness), but by hashCode () and equals (), must be able to fully determine the identity of the object.

Because before generating the index barrel, hashCode () need to do further processing, it generates a range-hash code is not important, as long as you can int.

Good hashCode () should produce a uniform distribution of hash codes. If a hash code are in several, then the load will HashSet HashMap or certain areas of heavy, thus not as uniform distribution of the hash function.

So a good hashCode () should follow the guidance:

  1. Int variables result given to a non-zero constant.
  2. F meaningful for each field within the object (i.e., each can be done equals () domain operations) calculate a hash code int C;
    Domain Type Compute
    boolean c=(f?0:1)
    byte, char, short or int c=(int)f
    long c=(int)(f^(f>>>32))
    float c=Float.floatToIntBits(f)
    double long L = Double.doubleToLongBits(f);
    c=(int)(L^(L>>>32))
    Object, which equals () call equals the domain () c=f.hashCode()
    Array Applying the above rules for each element
  3. The combined hash computation obtained: result = 37 * result + c;
  4. Return result.
  5. Check the hashCode Last exported (), to ensure that the same object will have the same hash code.

The following is an example to follow this guidance:

public class CountedString {
    private static List<String> created = new ArrayList<>();

    public String getString() {
        return mString;
    }

    public void setString(String string) {
        mString = string;
    }

    private String mString;
    private int id;

    public CountedString(String string) {
        mString = string;
        created.add(string);

        for (String s2 : created) {
            if (s2.equals(mString)) id++;
        }
    }

    @Override public String toString() {
        return "String:" + mString + " id:" + id + " hashCode():" + hashCode();
    }

    @Override public int hashCode() {
        int result = 17;
        result = 37 * result + mString.hashCode();
        result = 37 * result + id;
        return result;
    }

    @Override public boolean equals(Object obj) {
        return obj instanceof CountedString && mString
                .equals(((CountedString) obj).mString) && id == ((CountedString) obj).id;
    }

    public static void main() {
        Map<CountedString, Integer> map = new HashMap<>();
        CountedString[] cs = new CountedString[5];

        for (int i = 0; i < cs.length; i++) {
            cs[i] = new CountedString("hi");
            map.put(cs[i], i);
        }

        System.out.println(map);

        for (CountedString cst : cs) {
            System.out.println("Looking up:" + cst);
            System.out.println(map.get(cst));
        }
    }

}

复制代码

Complete Java class libraries

Complete container library

Guess you like

Origin juejin.im/post/5d01db406fb9a07eb15d50b2