Generics, enhanced for loops, and Set collections

Posted by thedon on Sun, 26 Dec 2021 03:30:28 +0100

generic paradigm
Introduction of generics
When we write the following code, we find that there are some small problems, because we store the data of String type and Integer type at the same time, but we convert it into String type, and an error will be reported when running. On the contrary, when the array stores data, it can only store one type of data, which is also an advantage of the array, Is there such an approach in the collection to specify the data type of the element when it is created, so that we can directly report errors during compilation when inserting data or downward transformation. In the collection, this design is called generics.

public static void main(String[] args) {

        ArrayList list = new ArrayList();

        list.add("hello");
        list.add("world");
        list.add(100);

        Iterator iterator = list.iterator();
        while (iterator.hasNext()){
            Object next = iterator.next();
            String next1 = (String) next;
            System.out.println(next1);
        }
        
    }

Introduction to generics
Generics: a type that defers type - specific work until the creation of an object or the invocation of a method. Parameterized type, which is passed as a parameter
Format:
< data type >
Note: the data type here can only be reference type

Benefits of generics
Advance the run-time problem to compile time
Casts are avoided
Optimize the program and eliminate the yellow warning line
Examples and applications of generics
Examples of generic storage of String type data

 public static void main(String[] args) {

        ArrayList<String> list = new ArrayList<String>();

        list.add("hello");
        list.add("world");
//        list.add(100); Directly reported an error

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            String r = iterator.next();
            System.out.println(r);
        }
    }
}
//hello
//world

Generic class

Generic classes: define generics on classes

This only represents a parameter type. The parameter type is a variable. Since it is a variable, it meets our variable naming rules and can be any name that conforms to the identifier

public class GenericTool<T> {
    private T obj;

    public T getObj(){
        return obj;
    }

    public void setObj(T obj){
        this.obj = obj;
    }

}


public static void main(String[] args) {

        GenericTool genericTool = new GenericTool();
        genericTool.setObj(new String("zhangsan"));
        Object obj = genericTool.getObj();
        String obj1 = (String) obj;
        System.out.println(obj1);

        genericTool.setObj(new String("lisi"));
        Object obj2 = genericTool.getObj();
        String obj21 = (String) obj2;
        System.out.println(obj21);

        GenericTool<String> stringGenericTool = new GenericTool<String>();
        stringGenericTool.setObj("wangwu");
        String obj3 = stringGenericTool.getObj();
        System.out.println(obj3);
    }
}
//zhangsan
//lisi
//wangwu

Enhanced for loop
What is an enhanced for loop
JDK1. After 5, some new contents appeared:
Automatic packing and unpacking
generic paradigm
Enhanced for loop
Enhanced for loop: it is a kind of for loop, which simplifies the traversal of arrays and Collection collections
For (element data type variable: array or Collection){
Just use a variable, which is an element
}
Benefits: simplifies traversal of arrays and Collection collections
Enhanced for loop example
Note: enhanced for can be used multiple times. The iterator can only be used once, and the life cycle ends (because the iterator only traverses once, and the pointer ends at the end)

public static void main(String[] args) {
        //Define an array
        int []arr = new int[]{1,2,3,4,5,6};
        for(int i=0;i<arr.length;i++){
            System.out.println(arr[i]);
        }

        //Enhanced for loop improvement
        //If Java can be replaced with enhanced for loop, use enhanced for loop to reduce the yellow warning line
        for(int i:arr){
            System.out.println(i);
        }

        //Define a collection object
        ArrayList<String> strings = new ArrayList<>();
        strings.add("hello");
        strings.add("world");
        strings.add("java");
        for(String s:strings){
            System.out.println(s);
        }

        //This step is only an improvement and judgment compared with the previous step
        List<String> list1 = null;
        if(!(list1 == null)){
            for (String s1:list1) {
                System.out.println(s1);
            }
        }
        //In fact, the enhanced for loop is used to replace the iterator
        //How to verify that it is used to replace iterators
        //I encountered a concurrent modification exception while looking at the iterator
        //ConcurrentModificationException
        for(String s:strings){
            if("java".equals(s)){
                strings.add("spark");
            }
        }
    }

Static import
What is static import
import static package name... Class name Method name; (can be imported directly to the level of the method)

be careful
Method must be static
If there are other methods in this class with the same name as the statically imported methods, the methods of this class are preferred
If some methods have the same name when importing, what should I do? It's best to add a prefix. It's required. This doesn't make much sense. You can understand it

public static void main(String[] args) {

        System.out.println(Math.abs(-100));
        System.out.println(Math.pow(2,3));
        System.out.println(Math.max(100,200));

        //Is there any way to write the method name directly without writing the class name
        //Import at the beginning: import static Java lang.Math. abs;
        System.out.println(abs(-900));

        FunDemo.show("hello");
        com.bigdata.shujia19.FunDemo.show(12.34);
    }
}
//100
//8.0
//200
//900
//hello
//12.34

Variable parameters

What are variable parameters and the points for attention of variable parameters

  • Variable parameters: when defining a method, the method can have multiple parameters
  • Modifier return value type method name (data type... Variable name) {}
  • Note: the variable here is actually an array of multiple parameters and gives it a name. This variable is the array name

Example of variable parameter code:

 public static void main(String[] args) {
        //Sum of two data
        int a = 10;
        int b = 20;
        int result1 = sum(a,b);
        System.out.println(result1);

        //Sum of three data
        int c = 30;
        int result2 = sum1(a,b,c);
        System.out.println(result2);

        //Write a summation requirement, but I don't know how many data requirements and, but the requirements are
        //When you call a method, you must find out
        //What to do? In order to solve this problem, Java provides a technology: variable parameters

        int res4 = sum(a,b,c,40,50,20,304,70);
        System.out.println(res4);
    }

    public static int sum(int a,int b){
        return a+b;
    }
    public static int sum1(int a,int b,int c){
        return a+b+c;
    }
    public static int sum(int...arr){
        int sum = 0;
        for(int i:arr){
            sum += i;
        }
        return sum;
    }
}
//30
//60
//544

Set interface
Introduction of Set interface
There are List and Set interfaces under the Collection interface

List elements are in order (the storage order is consistent with the extraction order and can be repeated)
Set is out of order (the storage order and retrieval order are inconsistent, and the elements are not unique)
HashSet: the bottom layer is the hash table. The thread is unsafe and efficient. Sometimes, the order given is just good and the order of storage is consistent, but this does not mean order. You can try more. The elements are unique and out of order

 public static void main(String[] args) {
        HashSet<String> hashSet = new HashSet<>();

        //Creates a string object and adds it to the collection
        hashSet.add("hello");
        hashSet.add("world");
        hashSet.add("java");
        hashSet.add("hello");
        hashSet.add("world");

        for(String s:hashSet){
            System.out.println(s);
        }
    }
}
//world
//java
//hello

HashSet class

HashSet class overview

  • The iterative order of set is not guaranteed
  • In particular, there is no guarantee that the sequence will remain unchanged
public static void main(String[] args) {
        //In the process of string storage, we found that the data stored in HashSet is indeed unordered and unique
        /*
        But why store only one string with the same content when storing a string
        Let's see the source code

        Looking at the source code, we find that we first look at whether the HashCode() value is the same
            If so, continue to judge the equals() method
                If the returned content is true, it means that the element content is the same. If it is repeated, it will not be added
                If the returned content is false, it indicates that the element content is not repeated and is added to the collection
            If they are different, they are added directly to the collection
        If these two methods are not overridden in a class, the method in the parent class Object is called
        Why can String objects be de duplicated? Explain that the HashCode() and equasl() methods are overridden in the String class
        So you can remove the contents of the same string and leave only one
         */
        HashSet<String> hashSet = new HashSet<String>();
        //Add string to collection
        hashSet.add("hello");
        hashSet.add("world");
        hashSet.add("java");
        hashSet.add("hello");
        hashSet.add("world");
        //Enhanced for loop traversal collection
        for(String s:hashSet){
            System.out.println(s);
        }
    }

How does HashSet ensure the uniqueness of elements

  • The underlying data structure is a hash table (elements are arrays of linked lists)
  • Hash tables depend on hash value storage
  • Two methods for adding function underlying dependencies
    • int hashCode()
    • boolean equals(Object obj)
public static void main(String[] args) {
        /*
        Define a HashSet collection to store custom objects and ensure the uniqueness of elements
        Requirement: if the values of the member variables of two objects are the same, it indicates that they are the same element

        We finished the program according to the requirements, but we didn't remove the duplication, so it didn't meet our requirements
        And because we know that the bottom layer of HashSet depends on HashCode() and equals() methods
        Because there is no override in the student class, the method in the Object is compared, and the address value is compared by default,
        Each student is new, so the address values are different, so they are inserted

        Now we need to rewrite the HashCode() and equals() methods. We don't need to write them ourselves. We can generate them automatically
         */

        HashSet<Student> list = new HashSet<Student>();

        Student s1 = new Student("zhangsan", 21);
        Student s2 = new Student("lisi", 22);
        Student s3 = new Student("wangwu", 23);

        list.add(s1);
        list.add(s2);
        list.add(s3);

        for(Student s:list){
            System.out.println(s.getName()+"---"+s.getAge());
        }
    }
}
//wangwu---23
//zhangsan---21
//lisi---22

Source code of add method in HashSet

public interface Collection<E> extends Iterable<E>{
    ...
}

public interface Set<E> extends Collection<E>{
    ...
}

public class HashSet<E> implements Set<E>{
    //Supported by hash tables (actually HashMap instances)
    private transient HashMap<E,Object> map;

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

    static final int hash(Object key) { //key -- e -- element to insert
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

    public V put(K key, V value) { //key -- e -- element to insert
        return putVal(hash(key), key, value, false, true);
    }


    //add() method in HashSet. Finally, we found that we called putVal() method in HashMap
    //The value of hash is related to the HashCode() method of the element
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        //The hash table stores an array of nodes
        Node<K,V>[] tab; Node<K,V> p; int n, i;

        //Judge whether the hash table is initialized. If not, initialize it
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;

        //Calculate the storage location according to the hash value of the element object. If the location of the element is null, it means that the location does not exist
        //Element, create a new node and store the element
        //Through the source code, we find that the add() method of HashSet must be related to the HashCode() method
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            
            /*
                The stored element is compared with the hash value of the previous element
                    If the hash values are different, continue down to add elements to the collection
                    If the hash values are the same, the equals() method of the object is called for comparison
                        If false is returned, the execution continues down and the element is added to the collection
                        If true is returned, it means that the content of the element is the same. If it is repeated, it will not be stored
            */
            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;
    }
} 

LinkedHashSet

  • LinkedHashSet: the bottom layer consists of hash table and linked list
  • The hash table guarantees the uniqueness of elements
  • The linked list ensures the order and order of elements (the order of storage and extraction is the same)
public static void main(String[] args) {

        LinkedHashSet<String> strings = new LinkedHashSet<String>();

        strings.add("hello");
        strings.add("world");
        strings.add("java");

        for(String s:strings){
            System.out.println(s);
        }
    }
}
//hello
//world
//java

Thanks for watching, I'm cool Tao!!!  

Topics: Java