Why generics

Generics: labels

For example:

  • In a Traditional Chinese medicine store, there are labels on the outside of each drawer

  • There are many bottles on the supermarket shelves. What does each bottle contain, with a label

The design background for generics

The collection container class does not know at design/declaration stage what type of Object the container actually holds, so before JDK1.5 we had to design the element type as Object, and after JDK1.5 we used generics to solve this problem. At this time, except for the type of the element, other parts are determined, such as how to save the element, how to manage and so on. Therefore, the type of the element is designed as a parameter, and this type parameter is called generic. Collection, List, ArrayList these are type parameters, generics

The concept of generics

  • The so-called generic type is allowed to define a class or interface through an identifier to represent the type of an attribute in the class or the return value and parameter type of a method. This type parameter is determined (that is, passed the actual type parameter, also known as the type argument) when it is used (for example, when inheriting or implementing the interface, declaring variables with the type, creating objects).

  • Since JDK1.5, Java has introduced the concept of “Parameterized Type”, which allows us to specify the types of collection elements when creating a collection, such as: List, which indicates that the List can only hold objects of type string.

  • JDK1.5 rewrites all interfaces and classes in the collection framework to add generics support for those interfaces and classes, allowing you to pass in type arguments when declaring collection variables and creating collection objects.

So why generics? Can’t direct Object store data?

1. Solve the security problems of element storage, such as commodity and drug labels, without mistake.

2. Solve the problem of type casting when retrieving data elements, such as not having to identify goods and drugs every time.

When there are no generics in the collection:

When there are generics in the collection:

Java generics guarantee that a ClassCastException will not occur at runtime if the program is not warned at compile time. At the same time, the code is more concise and robust.

Use generics in collections

  • Collection interfaces or collection classes were changed to generic structures in jdk5.0.
  • When you instantiate a collection class, you can specify a specific generic type
  • Once specified, the instantiated generic type is specified wherever the internal structure (such as methods, constructors, properties, etc.) uses the generic type of the class when defining the class or interface in the collection class or interface. For example: add(E E) –> After instantiation: add(Integer E)
  • Note: The type of a generic must be a class, not a primitive data type. Where basic data types are needed, use wrapper classes instead
  • If the type of the generic is not specified at instantiation time. The default type is java.lang.Object.

The code is shown as follows:

/** ** use of generics * 1. JDK 5.0 new features * 2. Using generics in collections: * summary: * ① collection interfaces or collection classes are changed to generic structures in jdk5.0. When you instantiate a collection class, you can specify the specific generic type. When you instantiate a collection class or interface, you can specify the instantiated generic type wherever the internal structure (such as methods, constructors, properties, etc.) uses the class's generic type. * Add (E E) --> Add (Integer E) * ④ Note: The type of the generic must be a class, not a basic data type. Where basic data types are needed, replace * ⑤ with wrapper classes if the type of the generic type is not specified when instantiated. The default type is java.lang.Object. * * 3. How to customize generic structures: generic classes, generic interfaces; Generic methods. See GenericTest1. Java * /
public class GenericTest {
    
    // What happened before generics were used in collections:
    @Test
    public void test1(a){
        ArrayList list = new ArrayList();
        // Request: store student's score
        list.add(78);
        list.add(76);
        list.add(89);
        list.add(88);
        // The type is not safe
// list.add("Tom");

        for(Object score : list){
            // ClassCastException may occur during strong casting
            intstuScore = (Integer) score; System.out.println(stuScore); }}// The case for using generics in collections: Take ArrayList
    @Test
    public void test2(a){
       ArrayList<Integer> list =  new ArrayList<Integer>();

        list.add(78);
        list.add(87);
        list.add(99);
        list.add(65);
        // At compile time, type checks are performed to ensure data security
// list.add("Tom");

        // Method 1:
// for(Integer score : list){
// // avoids strong-arm operations
// int stuScore = score;
//
// System.out.println(stuScore);
//
/ /}
        // Method 2:
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            intstuScore = iterator.next(); System.out.println(stuScore); }}// The case for using generics in collections: take HashMap
    @Test
    public void test3(a){
// Map
      
        map = new HashMap
       
        ();
       ,integer>
      ,integer>
        //jdk7 new features: type inference, i.e. New HashMap
      
       (); String in <>,Integer can be removed
      ,integer>
        Map<String,Integer> map = new HashMap<>();

        map.put("Tom".87);
        map.put("Jerry".87);
        map.put("Jack".67);

// map.put(123,"ABC");
        // Generic nesting
        Set<Map.Entry<String,Integer>> entry = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();
        while(iterator.hasNext()){
            Map.Entry<String, Integer> e = iterator.next();
            String key = e.getKey();
            Integer value = e.getValue();
            System.out.println(key + "--"+ value); }}}Copy the code

Custom generic structures

1. Declaration of generics

Interface List and Class GenTest<K,V> where T,K,V do not represent values, but represent types. I can use any letter here. T is the abbreviation of Type.

2. Instantiation of generics

Be sure to specify the value (type) of the type parameter after the class name. Such as:

List strList = new ArrayList();

Iterator iterator = customers.iterator();

  • T can only be classes and cannot be populated with primitive data types. But you can populate it with wrapper classes

  • Limiting the contents of a collection to a specific data type is the core idea behind Generics

Lesson learned: The main advantage of using generics is the ability to detect errors at compile time rather than at run time.

  • 1. A generic class may have multiple parameters, which should be enclosed in Angle brackets. For example: < E1, E2, E3 >

  • 2. GenericClass constructor: public GenericClass(){} Public GenericClass(){}

    1. When instantiated, the structure that operates on the original generic location must be consistent with the specified generic type.
    1. References to different generics cannot be assigned to each other.
/** * Generic references cannot be assigned to each other. * /
@Test
public void test3(a){

    ArrayList<String> list1 = null;
    ArrayList<Integer> list2 = new ArrayList<Integer>();
    // Generic references cannot be assigned to each other.
// list1 = list2;
}
Copy the code

Although ArrayList and ArrayList are two different types at compile time, only one ArrayList is loaded into the JVM at run time.

    1. If a generic type is not specified, it will be erased. The corresponding type of the generic type is treated as Object, but not equivalent to Object. Lesson of thumb: Use generics all the way. If you don’t use it, don’t use it all the way.
    1. If the generic structure is an interface or abstract class, objects of the generic class cannot be created.
    1. Flist = new ArrayList<>(); Type inference
    1. Primitive data types cannot be used in the specification of generics; wrapper classes can be used instead.
    1. A generic declared on a class/interface that represents a type in that class or interface can be used as a type for a non-static property, a parameter type for a non-static method, or a return value type for a non-static method. But you cannot use a class’s generics in a static method. Because generics are specified when the class creates the object, and the execution of static methods precedes the creation of the object, you cannot use a class’s generics in a static method
/** * Custom generic class *@author shkstart
 * @create 2019 上午 11:05
 */
public class Order<T> {

    String orderName;
    int orderId;

    // The inner structure of the class can use the generics of the class

    T orderT;

    public Order(a){
        // Failed to compile
// T[] arr = new T[10];
        // The compiler passes
        T[] arr = (T[]) new Object[10];
    }

    public Order(String orderName,int orderId,T orderT){
        this.orderName = orderName;
        this.orderId = orderId;
        this.orderT = orderT;
    }

    // None of the following three methods are generic
    public T getOrderT(a){
        return orderT;
    }

    public void setOrderT(T orderT){
        this.orderT = orderT;
    }

    @Override
    public String toString(a) {
        return "Order{" +
                "orderName='" + orderName + ' '' + ", orderId=" + orderId + ", orderT=" + orderT + '}'; } // Class generics cannot be used in static methods. // public static void show(T orderT){ // System.out.println(orderT); / /}}Copy the code
    1. Exception classes cannot be generic

    1. You cannot use new E[]. Elements = (E[])new Object[capacity]; Object[] elementData is declared as an array of generic parameters.
  • 12. The parent class has generics, and the child class can choose to keep the generics or specify the generic type:

Generic method

Note: generic methods do not use a generic in a method, but use a new generic, independent of the generic in the class.

// Generic methods: There is a generic structure in the method. The generic parameters have nothing to do with the generic parameters of the class.
// In other words, it doesn't matter whether a generic method belongs to a generic class or not.
// Generic methods can be declared static. Reason: Generic parameters are determined when a method is called. Not when you instantiate a class.
public static <E>  List<E> copyFromArrayToList(E[] arr){

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

    for(E e : arr){
        list.add(e);
    }
    return list;

}
Copy the code

The embodiment of generics in inheritance

 Class A is the parent of class B, but G and G do not have A child parent relationship, they are parallel. Add: class A is the parent of class B, and A
        
          is the parent of B
         
           */
         
        
    @Test
    public void test1(a){

        Object obj = null;
        String str = null;
        obj = str;

        Object[] arr1 = null;
        String[] arr2 = null;
        arr1 = arr2;
        // Failed to compile
// Date date = new Date();
// str = date;
        List<Object> list1 = null;
        List<String> list2 = new ArrayList<String>();
        // The list1 and list2 types do not have child and parent relationships
        // Failed to compile
// list1 = list2;
        /* list1 = list2; list1.add(123); Causes non-string data to be mixed in. To make mistakes. * /

        show(list1);
        show1(list2);

    }

    public void show1(List<String> list){}public void show(List<Object> list){}Copy the code

The use of wildcards

1. Use type wildcards:? For example: List, Map, List<? > is the parent class of List, List, and other generic lists.

2. Read the List <? > is always safe because no matter what the actual type of the list is, it contains Object.

3. Write elements in the list. Because we don’t know the element type of C, we can’t add objects to it. The only exception is NULL, which is a member of all types.

  • Adding arbitrary elements to it is not type-safe:

    Collection<? > c = new ArrayList();

    c.add(new Object()); // Compile-time error

    Because we don’t know the element type of C, we can’t add objects to it. The add method has the type parameter E as the element type of the collection. Any arguments we pass to Add must be subclasses of an unknown type. Because we don’t know what type it is, we can’t send anything in.

  • The only exception is NULL, which is a member of all types.

  • On the other hand, we can call the get() method and use its return value. The return value is an unknown type, but we know that it is always an Object

/* 2. Wildcard:? Class A is the parent of class B. G and G are unrelated. The common parent is G
         * /

    @Test
    public void test3(a){
        List<Object> list1 = null;
        List<String> list2 = null; List<? > list =null;

        /** * = List
       is the generic parent of List and List
       
         */
       

        list = list1;
        list = list2;
        // The compiler passes
// print(list1);
// print(list2);


        //
        List<String> list3 = new ArrayList<>();
        list3.add("AA");
        list3.add("BB");
        list3.add("CC");
        list = list3;
        // Add (write) : for List
       cannot add data to it internally.
        // In addition to adding null.
// list.add("DD");
// list.add('? ');

        list.add(null);

        // Get (read) : Allows reading of data of Object type.
        Object o = list.get(0);
        System.out.println(o);


    }

    public void print(List
        list){ Iterator<? > iterator = list.iterator();while(iterator.hasNext()){ Object obj = iterator.next(); System.out.println(obj); }}/* 3. The use of conditional wildcards. ? extends A: G
       can be A parent of G and G, where B is A subclass of A? super A: G
         can be A parent of G and G, where B is the parent of A */
    @Test
    public void test4(a){

        List<? extends Person> list1 = null;// equivalent to <=person
        List<? super Person> list2 = null;// equivalent to >=person

        List<Student> list3 = new ArrayList<Student>();
        List<Person> list4 = new ArrayList<Person>();
        List<Object> list5 = new ArrayList<Object>();

        list1 = list3;
        list1 = list4;
// list1 = list5;

// list2 = list3;
        list2 = list4;
        list2 = list5;

        // Read data:
        list1 = list3;
        Person p = list1.get(0);
        // Failed to compile
        //Student s = list1.get(0);

        list2 = list4;
        Object obj = list2.get(0);
        //// failed to compile
// Person obj = list2.get(0);

        // Write data:
        // Failed to compile
// list1.add(new Student());

        // The compiler passes
        list2.add(new Person());
        list2.add(newStudent()); }}Copy the code