Generics in Java

Posted by KingIsulgard on Tue, 25 Jan 2022 23:04:05 +0100

The following are my notes on watching the Java learning video of shangsilicon valley

Why generics

Generic can be understood as a tag, which is jdk5 0 new features
Analogy: there are labels on the outside of each drawer in a traditional Chinese medicine store, and only the drugs represented by the labels can be stored in the drawer. We can compare the container in Java to a drawer, so generics are labels, which means that this container can only store objects of the type specified by generics

Design background of generics:
The collection container class cannot determine what type of objects actually exist in this container in the design phase / declaration phase, so in jdk1 Before 5, the element type can only be designed as Object, jdk1 After 5, use generics to solve it. Because at this time, except the type of the element is uncertain, other parts are determined, such as how to save and manage the element. Therefore, at this time, the type of the element is designed as a parameter, which is called generics. Collection < E >, list < E >, ArrayList < E > this < E > is the type parameter, that is, generic type.
 

The concept of generics

The so-called genericity is to allow an identifier to represent the type of an attribute in a class or the return value and parameter type of a method when defining a class or interface. This type parameter will be determined when using (for example, inheriting or implementing this interface, declaring variables and creating objects with this type) (that is, passing in the actual type parameter, also known as type argument).

From jdk1 After 5, Java introduced the concept of "Parameterized type", which allows us to specify the type of collection elements when creating a collection, such as: List < string >, which indicates that the list can only save objects of string type.

JDK1.5 rewrites all interfaces and classes in the collection framework and adds generic support for these interfaces and classes, so that type arguments can be passed in when declaring collection variables and creating collection objects

 

Benefits of using generics

So why do we need generics? Can't direct object s also store data?
1. Solve the security problem of element storage, such as commodity and drug labels, without making mistakes.
2. Solve the problem of type coercion when obtaining data elements, such as not taking goods and drugs every time
All products should be distinguished.

Generic sample code:

import java.util.*;

public class Sample {
    public static void main(String[] args) {
        //Take ArrayList as an example
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(123);
        //Type checking will be carried out during compilation to ensure the safety of data
        //list.add("Tom");

        //ergodic
        //Mode 1:
        for (Integer integer : list) {
            //Casts are avoided
            int tmp = integer;
            System.out.println(tmp);
        }
        //Mode 2:
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            int tmp = iterator.next();
            System.out.println(tmp);
        }

        //Take HashMap as an example
        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("Tom", 87);
        //Type check, compilation error
        //map.put(123, "Tom");

        //Nesting of generics
        Set<Map.Entry<String, Integer>> entry = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator1 = entry.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Integer> e = iterator1.next();
            String key = e.getKey();
            Integer value = e.getValue();
            System.out.println(key + " --> " + value);
        }
    }
}

Summary:
1. Collection interface or collection class in jdk5 0 is modified to a structure with generics
2. When instantiating a collection class, you can specify the specific generic type
3. After specifying, when defining a class or interface in a collection class or interface, the location where the generic type of the class is used by the internal structure (such as method, constructor, attribute, etc.) is specified as the instantiated generic type, such as: add(E e) → add(Integer e) after instantiation
4. Note: the type of generic type must be a class, not a basic data type. Where the basic type needs to be used, replace it with a wrapper class
5. If the generic type is not specified during instantiation, the default type is Java Lang.Object type
 

jdk7.0 generic new feature: type inference

//jdk7. When declaring objects before 0, the following statements also need to indicate the data type
ArrayList<Integer> list = new ArrayList<Integer>();
//jdk7. Can be omitted after 0
ArrayList<Integer> list = new ArrayList<>();

 

Custom generic structure

Generic class, generic interface

1. A generic class may have multiple parameters. In this case, multiple parameters should be placed together in angle brackets. For example: < E1, E2, E3 >
2. The constructor of generic class is as follows: public GenericClass(), which is wrong: public GenericClass()
3. After instantiation, the structure of the original generic location must be consistent with the specified generic type
4. References with different generics cannot be assigned to each other

ArrayList<String> list1 = null;
ArrayList<Integer> list2 = null;
list1 = list2;//Compilation error

  · although ArrayList and ArrayList are two types at compile time, only one ArrayList is loaded into the JVM at run time.
5. If a generic type is not specified, it will be erased. The types corresponding to the generic type are treated as Object, but they are not equivalent to Object. Experience: generics should be used all the way. No, not all the way
6. If the generic structure is an interface or abstract class, the object of the generic class cannot be created
7,jdk1.7. Simplified operation of generics: ArrayList flist = new ArrayList < > ();
8. The basic data type cannot be used in the specification of generic type, which can be replaced by wrapper class
9. The generic type declared on the class / interface represents a type in this class or interface, and can be used as the type of non static attribute, parameter type of non static method and return value type of non static method. However, the generics of classes cannot be used in static methods
10. Exception class cannot be generic
11. Let the generic parameter be e. note that new E [] cannot be used. However, it can be written as follows: E[] elements =(E[]) new Object[capacity]; (Reference: the source code of ArrayList declares: Object[] elementData, not a generic parameter type array)
12. The parent class has a generic type, and the child class can choose to keep the generic type or specify the generic type:
  · subclasses do not retain the genericity of the parent class: Implementation on demand
  · no type erase
  · specific type
  · subclasses retain the genericity of the parent class: generic subclasses
  · all reserved
  · partial reservation
  · conclusion: subclasses must be "rich second generation". In addition to specifying or retaining the generics of the parent class, subclasses can also add their own generics

Inherit generic classes

1. The type is specified at the time of inheritance

class SubOrder extends Order<Integer>

Since the subclass specifies the generic type when inheriting the parent class with generic type, it is no longer necessary to specify the generic type when instantiating the subclass object. SubOrder is not a generic class at this time

//Since the subclass indicates the generic type when inheriting the parent class with generic type, it is no longer necessary to specify the generic type when instantiating the subclass object
SubOrder subOrder = new SubOrder();

2. Type is not specified when inheriting

class SubOrder<T> extends Order<T>

At this time, SubOrder class is still a generic class

SubOrder<String> subOrder = new SubOrder<>();

Customize generic classes and generic interfaces (take generic classes as an example)

//Custom generic class
class Order<T> {
    String orderName;
    int orderId;

    //The internal structure of a class can use the generics of the class
    T orderT;

    public Order() {
    }

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

    public T getOrderT() {
        return orderT;
    }

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

    @Override
    public String toString() {
        return "Order{" +
                "orderName='" + orderName + '\'' +
                ", orderId=" + orderId +
                ", orderT=" + orderT +
                '}';
    }
}

public class Sample {
    public static void main(String[] args) {
        //If a generic class is defined and a generic type without a specified class is instantiated, the generic type is considered to be Object type
        Order order = new Order();
        order.setOrderT(123);
        order.setOrderT("ABC");

        //Requirement: if you have defined that the class is generic, it is recommended to specify the generic type of the class when instantiating
        Order<String> order1 = new Order<String>("orderAA", 1001, "order:AA");
        order1.setOrderT("AA:hello");
    }
}

 

generic method

The generic structure appears in the method. The generic parameters of the generic method have nothing to do with the generic parameters of the class (in other words, it doesn't matter whether the class of the generic method belongs to a generic class or not)

When a generic method is called, it indicates the type of generic parameter

Generic methods can be declared static because generic parameters are determined when the method is called, not when the class is instantiated

Example: note that the first < E > in the method declaration is used to indicate that the method is a generic method. If this < E > is not added, the compiler will mistakenly think that e is a class and report an error

public class Sample {
    public static void main(String[] args) {
        Integer[] arr = new Integer[]{1, 2, 3};
        List<Integer> list = new Sample().copy(arr);//At this time, the type of the list object is determined by the arr type
    }
	//generic method 
    public <E> List<E> copy(E[] arr) {
        ArrayList<E> list = new ArrayList<>();
        for (E e : arr) {
            list.add(e);
        }
        return list;
    }
}

 

The embodiment of generics in inheritance

Let class A be the parent of class B. note that G < A > and G < b > do not have A child parent relationship, and they are juxtaposed
For example:
Let obj be the Object of Object class and STR be the Object of String class, then we can assign obj = str
However, if list1 is the object of list < Object > and list2 is the object of list < string >, then list1 = list2 will fail the compilation because list < Object > and list < string > are in parallel

Let class A be the parent of class B. note that A < T > is the parent of B < T >
For example: List < string > is the parent of ArrayList < string >, so there is list < string > List = new ArrayList < string > (); Such assignment statement

 

Use of wildcards

Wildcard:?

In the above article, it is said that G < a > and G < b > are juxtaposed, so if you want to use polymorphism to make them all assignable, you should find their parent class, whose parent class is g <? >. Wildcards are used to solve this problem.

Wildcard sample code:

import java.util.Iterator;
import java.util.List;

public class Sample {
    public static void main(String[] args) {
        List<Object> list1 = null;
        List<String> list2 = null;
        List<?> list = null;

        //Can be assigned, indicating list <? > Is a parent class
        list = list1;
        list = list2;

        new Sample().print(list1);//Compile through

        //Add (write): for list <? > You can't add data to it, except null
        list2.add("AA");
        //list.add("AA");// Compilation error
        list.add(null);

        //Get (read): allows data to be read. The read data type is Object
        Object obj = list.get(0);

    }

    public void print(List<?> list) {
        Iterator<?> iterator = list.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println(obj);
        }
    }
}

Bounded Wildcards

  • Wildcard specifies the upper limit
    Upper bound extensions: the type specified when using must inherit a class or implement an interface, i.e<=
  • Wildcard to specify lower limit
    Lower limit super: the type specified when using cannot be less than the class of operation, i.e. >=
  • give an example:
    • <? Extensions Number > (infinitesimal, Number): only reference calls with generics of Number and Number subclasses are allowed
    • <? Super Number > [Number, infinite): only reference calls with generic Number and Number parent class are allowed
    • <? Extensions compatible >: only the generic type is allowed to be called by reference of the implementation class that implements the compatible interface

Sample code (where Student class is a subclass of Person class):
? extands A:
  G<? Extensions a > can be the parent of G < a > and G < b >, where B is a subclass of A
? super A:
  G<? Super a > can be a subclass of G < a > and G < b >, where B is the parent of A

import java.util.ArrayList;
import java.util.List;

public class Sample {
    public static void main(String[] args) {
        List<? extends Person> list1 = null;
        List<? super Person> list2 = null;

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

        list1 = list3;
        list1 = list4;
        //list1 = list5;// Compilation failed

        //list2 = list3;// Compilation failed
        list2 = list4;
        list2 = list5;

        //Read data:
        list1 = list3;
        Person p = list1.get(0);//Compile through
        //Student s = list1.get(0);// Compilation failed

        list2 = list4;
        Object obj = list2.get(0);//Compile through
        //Person person = list2.get(0);// Compilation failed

        //Write data:
        //list1.add(new Student());// Compilation failed
        list2.add(new Person());//Compile through
        list2.add(new Student());//Compile through
    }
}

class Person {
}

class Student extends Person {
}

Topics: Java Back-end