Generics of java basic study notes

  • 2020-05-05 11:13:16
  • OfStack

generic

Qualifies an element in a collection to a specific type.

The term

ArrayList < E > -- generic type ArrayList -- primitive type E -- type parameter < > - pronounced "typeof ArrayList" < Integer > -- parameterized type Integer -- actual type parameter

A few notes:

The parameterized type and the primitive type are mutually compatible with


ArrayList collection1 = new ArrayList<Integer>();// through , There is no warning
ArrayList<Integer> collection2 = new ArrayList();// through , There are warning

Parameterized types do not consider the inheritance of type parameters


ArrayList<String> collection3 = new ArrayList<Object>();// Compile not pass 
ArrayList<Object> collection4 = new ArrayList<String>();// Compile not pass 

But


ArrayList collection5 = new ArrayList<Integer>();
ArrayList<String> collection6 = collection5;// Compiled by 

& # 63; "" The wildcard character

"The & # 63;" For any type, use "?" Wildcards can refer to various parameterized types, can call methods that are not parameterized (such as size()), and cannot call methods that are parameterized (such as add()),

extension of wildcard

Qualifies the upper edge of a wildcard,


ArrayList<? extends Number > collection1= new ArrayList<Integer >();// Compiled by 
ArrayList<? extends Number > collection2= new ArrayList<String>();// Compile not pass 

Qualifies the lower boundary of the wildcard,


ArrayList<? super Integer > collection3= new ArrayList<Number >();// Compiled by 
ArrayList<? super Integer > collection4= new ArrayList<String>();// Compile not pass 

custom generic method

C++ template function


template <class T> T add(T x, T y){
  return (T)(x+y);
}

Generics of java, on the other hand, are implemented almost entirely in the compiler, which performs type checking and type determination, and then generates plain, non-generic bytecode, an implementation technique known as "erasing" (erasure).

"erase" instance

Generics are provided to the javac compiler to qualify the input type of a collection, which removes the "type" information when compiling a collection with a type description.


public class GenericTest {
  public static void main(String[] args) {
    new GenericTest().testType();
  }

  public void testType(){
    ArrayList<Integer> collection1 = new ArrayList<Integer>();
    ArrayList<String> collection2= new ArrayList<String>();

    System.out.println(collection1.getClass()==collection2.getClass());
    // both class Type the same , That is, the bytecode is consistent 

    System.out.println(collection2.getClass().getName());
    //class Are all java.util.ArrayList, There is no actual type parameter information 
  }
}

Output

true
java.util.ArrayList
Use reflection to skip the compiler and add other types of data to a generic collection.

Only the reference type can be used as an example of the actual parameter of a generic method:


public class GenericTest {
  public static void main(String[] args) {
    swap(new String[]{"111","222"},0,1);// Compiled by 

    //swap(new int[]{1,2},0,1);
    // Compile not pass , because int Not a reference type 

    swap(new Integer[]{1,2},0,1);// Compiled by 
  }

  /* Exchange of array a  The first i And the first j An element */
  public static <T> void swap(T[]a,int i,int j){
    T temp = a[i];
    a[i] = a[j];
    a[j] = temp;
  }
}

Note, however, that the base type can sometimes serve as an argument because of autoboxing and unboxing. Example (compiled) :


public class GenericTest {
  public static void main(String[] args) {
    new GenericTest().testType();
    int a = biggerOne(3,5);
    //int  and  double, Take delivery for Number
    Number b = biggerOne(3,5.5);
    //String and int  Take delivery for Object
    Object c = biggerOne("1",2);
  }
  // from x,y In return y
  public static <T> T biggerOne(T x,T y){
    return y;
  }
}

The example also shows that when arguments are inconsistent, T takes the intersection, the first common parent. In addition, if Number b = biggerOne(3,5.5); String c = biggerOne(3,5.5); Then compile error report :

Error:(17, 29) java: incompatible type: inferred type does not meet upper limit
      conclude java. lang. Number & java. lang. Comparable< ? extends java.lang.Number&java.lang.Comparable < ? > >
      ceiling: java. lang. String, java. lang. Object
However, there is one thing that is not clear, I step in IDEA debugging, and found the following figure: generic debugging screenshot -1 do not know why b is Double type (but directly Double b received the return value will compile the error). I don't know if it has anything to do with IDE, does IDE display the most precise type of this object when debug?

Type inference for type parameters

The process by which the compiler determines the actual type parameter of a generic method is called type inference.

When a type variable is applied to only one of the parameters and return values in the entire parameter list, it is determined based on the actual application type at the time the method is called. That is, the type of a generic parameter is determined directly based on the parameter type or return value passed when the method is called. For example:


swap(new String[3],1,2) -> static <E> void swap(E[]a,int i,int j)

When a type variable is applied to more than one of all the arguments and return values in the entire parameter list, the type of a generic parameter is the same if the actual application types in so many places correspond to the same type when the method is called. For example:


ArrayList<String> collection3 = new ArrayList<Object>();// Compile not pass 
ArrayList<Object> collection4 = new ArrayList<String>();// Compile not pass 
0

When a type variable is applied to * in all parameters and return values in the entire parameter list, if the actual application types in so many places correspond to different types when the method is called, and there is no return value, the maximum intersection type in the multiple parameters is taken, that is, the first common parent class. For example:


ArrayList<String> collection3 = new ArrayList<Object>();// Compile not pass 
ArrayList<Object> collection4 = new ArrayList<String>();// Compile not pass 
1

The actual type of this example is Number.

When a type variable is applied in multiple places in all parameters and return values of the entire parameter list,
of the return value is preferred if the actual application type in so many places corresponds to a different type when the method is called and a return value is used For example:


ArrayList<String> collection3 = new ArrayList<Object>();// Compile not pass 
ArrayList<Object> collection4 = new ArrayList<String>();// Compile not pass 
2

The above example reported an error,x type changed to float also reported an error, changed to Number success.

Type inference for parameter types is transitive
Example:

copy(new Integer[5],new String[5]) - > static < T > void copy(T []a,T []b)

The example concludes that the actual parameter type is Object

copy(new ArrayList < String > ,new Integer[5]) - > static < T > void copy(Collection < T > a,T[]b)

This example directly determines the type variable as String type according to the parameterized ArrayList class instance, and compiles and reports an error.

Custom generic class

Example


public class GenericDao<T>{
  public void add(T x){
  }

  public T findById(int id){
    return null;
  }

  public void delete(T obj){
  }

  public void delete(int id){
  }

  public void update(T obj){
  }

  public T findByUserName(String name){
    return null;
  }

  public <T> Set<T> findByConditions(String where){
    return null;
  }

}

Note: when a variable is declared generic, it can only be called by instance variables and methods (as well as embedded types), not by static variables and static methods. Because static members are Shared by parameterized classes, static members should not have class-level type parameters.

Comparison of generic methods and generic classes

Example:


ArrayList<String> collection3 = new ArrayList<Object>();// Compile not pass 
ArrayList<Object> collection4 = new ArrayList<String>();// Compile not pass 
4

Here Integer i = A< String > (a). findByUserName (" s "); Will compile error:

Error: (35, 61) java: incompatible types: java. lang. String unable to convert java. The lang. Integer

From this example, the T of a generic method is different from the T of class A.

generics and reflection

The actual type parameter

of the generic is obtained by reflection

Using the getGenericParameterTypes method of the Method class to get an example of the actual type parameter of the generic:


ArrayList<String> collection3 = new ArrayList<Object>();// Compile not pass 
ArrayList<Object> collection4 = new ArrayList<String>();// Compile not pass 
5

Output:


ArrayList<String> collection3 = new ArrayList<Object>();// Compile not pass 
ArrayList<Object> collection4 = new ArrayList<String>();// Compile not pass 
6


Related articles: