This is the 13th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Definition and meaning of generics

Definition 1.

Generics, or parameterized types. Parameterize a type from an original concrete type, similar to a variable parameter in a method, in which the type is also defined as a parameter (called a type parameter), and then pass in the concrete type (type argument) when using /.

2. The meaning of generics

  1. Execution of the same code for multiple data types (code reuse)
  2. Types in generics are specified at use without casting (type-safe, the compiler checks the type)

The nature of generics

Generics are only valid at compile time

@Test
    public void test1(a){
        List<String> stringArrayList = new ArrayList<String>();
        List<Integer> integerArrayList = new ArrayList<Integer>();
        Class classStringArrayList = stringArrayList.getClass();
        Class classIntegerArrayList = integerArrayList.getClass();
        System.out.println(classIntegerArrayList);
        System.out.println(classStringArrayList);
        System.out.println(classStringArrayList.equals(classIntegerArrayList));
    }
Copy the code

As demonstrated by the above example, the program takes steps to de-generalize after compilation. That is, generics in Java are only valid at compile time. When the result of generics is properly verified during compilation, information about generics is erased (Generic erase/type erase), and add type-checking and type-casting methods at the boundaries of how objects enter and leave methods. That is, generic information does not enter the runtime phase.

This can be summed up in one sentence: generic types are logically seen as multiple different types, but are actually the same basic type.

The use of generics

1. Some common generic type variables

E: Element, mostly used in Java collection framework K: Key N: Number T: Type V: Value

2. Constraints on generics

  1. Generic type variables cannot be instantiated
  2. A static variable or method cannot reference a generic type variable, but a static generic method can
  3. Primitive types cannot be generic types
  4. You cannot determine the type of a generic class using the instanceof keyword or ==
  5. The prototype of a generic class has nothing to do with the generic being passed, the protoclass is the same no matter what type is passed, right
  6. Generic arrays can be declared but cannot be instantiated
  7. Generic classes cannot inherit from Exceptions or Throwable
  8. Generic-qualified exceptions cannot be caught but generic-qualified exceptions can be thrown
/** * 

* Description: Generic constraints and limitations */

public class GenericRestrict1<T> { static class NormalClass {}private T data; /* Type parameter 'T' cannot be instantiated directly */ public void setData(a) { //this.data = new T(); } /** * Static variables or methods cannot reference generic type variables * 'com.jay-java. Generics. Restrict. GenericRestrict1. This' always be referenced from a static context * / // private static T result; // private static T getResult() { // return result; / /} /** * Static generic methods are ok */ private static <K> K getKey(K k) { return k; } public static void main(String[] args) { NormalClass normalClassA = new NormalClass(); NormalClass normalClassB = new NormalClass(); /** * Primitive types cannot be used as generic types */ // GenericRestrict1 genericRestrictInt = new GenericRestrict1<>(); GenericRestrict1<Integer> genericRestrictInteger = new GenericRestrict1<>(); GenericRestrict1<String> genericRestrictString = new GenericRestrict1<>(); /** * Illegal generic type for instanceof */ // if(genericRestrictInteger instanceof GenericRestrict1 ){ // return; / /} /* Operator '==' cannot be applied to this two instance */ // if (genericRestrictInteger == genericRestrictString) { // return; / /} /** * The native type of a generic class is independent of the generic being passed. The native class is the same regardless of the type being passed System.out.println(normalClassA == normalClassB);//false System.out.println(genericRestrictInteger == genericRestrictInteger);// System.out.println(genericRestrictInteger.getClass() == genericRestrictString.getClass()); //true System.out.println(genericRestrictInteger.getClass());. / / com. Jay. Java generics. Restrict. GenericRestrict1 System.out.println(genericRestrictString.getClass());. / / com. Jay. Java generics. Restrict. GenericRestrict1 /** * Generic array creation can be declared but cannot be instantiated GenericRestrict1<String>[] genericRestrict1s; // genericRestrict1s = new GenericRestrict1 [10]; genericRestrict1s = new GenericRestrict1[10]; genericRestrict1s[0]=genericRestrictString; }}Copy the code

The main uses of generics include generic classes, generic interfaces, and generic methods

3. A generic class

// Here T can be written as any identifier. Common parameters such as T, E, K, V are used to represent generics
When instantiating a generic class, you must specify the specific type of T
public class Generic<T>{ 
    // Key is a member variable of type T, whose type is externally specified
    private T key;

    public Generic(T key) { // The generic constructor parameter key is also of type T, whose type is externally specified
        this.key = key;
    }

    public T getKey(a){ // The generic method getKey returns a value of type T, the type of which is externally specified
        returnkey; }}Copy the code

Note:

  1. The type parameters of a generic type can only be class types, not simple types (8 basic types)
  2. When using a generic class, it is not necessary to pass in a generic type argument. If you do not pass in a generic type argument, a method or member variable that uses a generic type in a generic class can be of any type

4. Generic interfaces

Generic interfaces are defined and used in much the same way as generic classes. Generic interfaces are often used in producers of various classes. Here is an example:

// Define a generic interface
public interface Generator<T> {
    public T next(a);
}
Copy the code

When a class that implements a generic interface passes no generic arguments:

/* FruitGenerator
      
        implements Generator
       
        {* FruitGenerator
        
          implements Generator
         
          {* FruitGenerator
          
            implements Generator
           
            {* FruitGenerator
            
              implements Generator
             
              { FruitGenerator implements Generator
              
                "Unknown class" */
              
             
            
           
          
         
        
       
      
class FruitGenerator<T> implements Generator<T>{
    @Override
    public T next(a) {
        return null; }}Copy the code

When a class that implements a generic interface passes in a generic argument:

/** * When passing generic arguments: * Define a producer to implement this interface. Although we only created a generic interface Generator
      
        * we can pass in an infinite number of arguments to T, forming an infinite number of types of Generator interfaces. * When an implementation class implements a generic interface, if the generic type has been passed to the argument type, all uses of the generic type should be replaced with the passed argument type * i.e. Generator
       
        , public T next(); The T in is replaced by the String passed in. * /
       
      
public class FruitGenerator implements Generator<String> {

    private String[] fruits = new String[]{"Apple"."Banana"."Pear"};

    @Override
    public String next(a) {
        Random rand = new Random();
        return fruits[rand.nextInt(3)]; }}Copy the code

5. Generic methods

/** * A basic introduction to generic methods *@paramThe generic argument * passed in by tClass@return<T> <T> <T> <T> <T> * 2) Only methods that declare <T> are generic, and member methods that use generics in a generic class are not generic. * 3) <T> indicates that the method will use the generic type T before you can use the generic type T in the method. * 4) Like the definition of generic classes, here T can be written as any identifier, common parameters such as T, E, K, V are often used to represent generics. * /
public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,
  IllegalAccessException{
        T instance = tClass.newInstance();
        returninstance; } Object obj = genericMethod(class.forname ("com.test.test"));
Copy the code

Examples of generic methods

public class GenericTest {
   // This class is a generic class, as described above
   public class Generic<T>{     
        private T key;

        public Generic(T key) {
            this.key = key;
        }

        // What I really want to say is that although generics are used in methods, this is not a generic method.
        // This is just a normal member method of the class, but its return value is the declaration of the generic class already declared the generic type.
        // So we can continue to use the T generic in this method.
        public T getKey(a){
            return key;
        }

        /** * The compiler will not recognize the use of E as a parameter or return type because the generic type E is not declared in the class declaration. public E setKey(E key){ this.key = keu } */
    }

    /** * This is a true generic method. * First 
      
        is required between public and the return value, which indicates that this is a generic method and declares a generic T * that can appear anywhere in the generic method. * The number of generics can also be as many as you like. public 
       
         K showKeyName(Generic
        
          container){ * ... *} * /
        
       ,k>
      
    public <T> T showKeyName(Generic<T> container){
        System.out.println("container key :" + container.getKey());
        // Of course, this example is not appropriate, just to illustrate the nature of generic methods.
        T test = container.getKey();
        return test;
    }

    // This is not a Generic method. This is just a Generic method that uses the Generic
      
        class as its parameter.
      
    public void showKeyValue1(Generic<Number> obj){
        Log.d("Generic test"."key value is " + obj.getKey());
    }

    // This is not a generic method, this is a normal method, but uses generic wildcards.
    // This also confirms what is described in the generic wildcard section,? Is a type argument that can be considered the parent of all classes, such as Number
    public void showKeyValue2(Generic
        obj){
        Log.d("Generic test"."key value is " + obj.getKey());
    }

     /** * This method is problematic, the compiler will give us an error message: "UnKnown class 'E' "* Although we declare 
      
       , it also indicates that this is a generic method that can handle generic types. * But only the generic type T is declared, not E, so the compiler does not know what to do with E. public 
       
         T showKeyName(Generic
        
          container){ ... } * /
        
       
      

    /** * This method is also problematic, the compiler will give us an error message: "UnKnown class 'T' "* for the compiler T is not declared in the project, so the compiler does not know how to compile the class. * So this is not a correct generic method declaration either. public void showkey(T genericObj){ } */

    public static void main(String[] args) {}}Copy the code

6. Generic wildcards

Types of generic wildcards:

A. <? Extends T> specifies an upper bound on a generic type

  1. Used for method parameters that qualify only T and subclasses of T
  2. Used for parent class references, mainly for secure access to data, can access T and its subtypes, and can only write null

2. <? Super T> specifies the lower bound of generic types

  1. Used as a method parameter that limits passing only T and its parent class
  2. Used for parent class references, primarily to safely write data, to a Child and its subtypes

3. <? > specifies unrestricted generic types

  1. For method parameters, there are no restrictions, can pass any type
  2. For parent class references, only null can be written
/** * 

* Description: generic wildcard test class */

public class GenericByWildcard { private static void print(GenericClass<Fruit> fruitGenericClass) { System.out.println(fruitGenericClass.getData().getColor()); } private static void use(a) { GenericClass<Fruit> fruitGenericClass = new GenericClass<>(); print(fruitGenericClass); GenericClass<Orange> orangeGenericClass = new GenericClass<>(); // Type mismatch, can use // print(orangeGenericClass); } / * * * specifies the upper bound of the generic type * to be used on method parameters and limits passing only Fruit subclasses */ private static void printExtends(GenericClass<? extends Fruit> genericClass) { System.out.println(genericClass.getData().getColor()); } public static void useExtend(a) { GenericClass<Fruit> fruitGenericClass = new GenericClass<>(); printExtends(fruitGenericClass); GenericClass<Orange> orangeGenericClass = new GenericClass<>(); printExtends(orangeGenericClass); GenericClass<Food> foodGenericClass = new GenericClass<>(); //Food is the parent of Fruit, beyond the upper bounds of the generic type, and the type does not match // printExtends(foodGenericClass); // Used for parent class references // The upper bound of the GenericClass type parameter is Fruit GenericClass<? extends Fruit> extendFruitGenericClass = new GenericClass<>(); Apple apple = new Apple(); Fruit fruit = new Fruit(); /* * The truth is simple,? Extends X is an upper bound on a type. The type argument is a subclass of X, so it's safe to say that the * get method must return an X (whether X or a subclass of X) that the compiler knows for sure. * The set method only knows that X is passed in, and that it is a subclass of X. * Summary: Mainly used to securely access data, X and its subtypes can be accessed, and only NULL can be written. * / // extendFruitGenericClass.setData(apple); // extendFruitGenericClass.setData(fruit); fruit = extendFruitGenericClass.getData(); } / * * * specifies that the lower bound of the generic type * can only be passed to Apple and its parent */ public static void printSuper(GenericClass<? super Apple> genericClass) { System.out.println(genericClass.getData()); } public static void useSuper(a) { GenericClass<Food> foodGenericClass = new GenericClass<>(); printSuper(foodGenericClass); GenericClass<Fruit> fruitGenericClass = new GenericClass<>(); printSuper(fruitGenericClass); GenericClass<Apple> appleGenericClass = new GenericClass<>(); printSuper(appleGenericClass); GenericClass<HongFuShiApple> hongFuShiAppleGenericClass = new GenericClass<>(); // HongFuShiApple is a subclass of Apple // printSuper(hongFuShiAppleGenericClass); GenericClass<Orange> orangeGenericClass = new GenericClass<>(); // Orange and Apple are brothers, there is no inheritance relationship, type mismatch // printSuper(orangeGenericClass); // Used for parent class references // The lower bound of the GenericClass type parameter is Apple GenericClass<? super Apple> supperAppleGenericClass = new GenericClass<>(); supperAppleGenericClass.setData(new Apple()); supperAppleGenericClass.setData(new HongFuShiApple()); / * *? Super X is the lower bound of the type. The type argument is the superclass of X (including X itself), * so we can be sure that the super class returned by get must be X. No, * but it's safe to say that Object must be its superclass, so the get method returns Object. * The compiler is deterministic. For the set method, the compiler does not know the exact type it needs, but X and subclasses of X can be safely converted to X. * Summary: Mainly used to safely write data, X and its subtypes can be written. * / // supperAppleGenericClass.setData(new Fruit()); The get method only returns a value of type Object. Object data = supperAppleGenericClass.getData(); } / * * * specifies the unqualified wildcard */ public static void printNonLimit(GenericClass genericClass) { System.out.println(genericClass.getData()); } public static void useNonLimit(a) { GenericClass<Food> foodGenericClass = new GenericClass<>(); printNonLimit(foodGenericClass); GenericClass<Fruit> fruitGenericClass = new GenericClass<>(); printNonLimit(fruitGenericClass); GenericClass<Apple> appleGenericClass = newGenericClass<>(); printNonLimit(appleGenericClass); GenericClass<? > genericClass =new GenericClass<>(); // The setData method cannot be called, even with Object; // genericClass.setData(foodGenericClass); // genericClass.setData(new Object()); // The return value can only be assigned to ObjectObject object = genericClass.getData(); }}Copy the code

3. Reference links

Java generics in detail

Overview of Generics in Java – this is definitely the most detailed overview of generic methods out there

Java Summary series: Java generics

Novice tutorial

Talk about it – Wildcards T, E, K, V, JAVA generics?