An overview of the

Generics, we often see the use of Generics in Java collections or frameworks, so what is the role of Generics?

  • Can help us handle multiple data types to execute the same code
  • Data security, the type of the generic type in the use of the specified type, do not need to force type conversion, the earliest Java is not generic, it is the use of Object to replace, so that programmers in writing procedures are prone to type conversion errors.

The nature of generics is to parameterize a type, that is, to parameterize a type from an original concrete type, like a variable parameter in a method, where the type is also defined as a parameter (called a type parameter) and then passed in the concrete type (type argument) when used or called. That is, in the use of generics, the data type of the operation is specified as a parameter, which can be used in classes, interfaces, and methods, called generic classes, generic interfaces, and generic methods, respectively.

Generic classes and generic interfaces

The definition of a generic class/interface uses a type variable T (any other uppercase letter is fine, but the usual ones are T, E, K, V, etc.), which acts as a placeholder, enclosed in <>, and followed by the class/interface name. Generic classes are allowed to have multiple type variables

public class GenericsClass<T> {
    private void print(){
        System.out.println("Generic type"); } public static void main(String [] args){ GenericsClass<String> genericsClass = new GenericsClass<>(); genericsClass.print(); }}Copy the code
public class GenericsClass<T,V> {
    private void print(){
        System.out.println("Generic type"); } public static void main(String [] args){ GenericsClass<String,Integer> genericsClass = new GenericsClass<>(); genericsClass.print(); }}Copy the code
public interface ImpGenerics<V> {
}

Copy the code

Classes that implement generic interfaces can be implemented in two ways

public class Generics<T> implements ImpGenerics<T> {
}
Copy the code

This implementation does not specify a specific type. This implementation requires passing in a specific type when creating an object

public class Generics implements ImpGenerics<String> {
}

Copy the code

This is done by passing in a concrete argument at implementation time and creating an object just like a normal class

Generic method

Generic methods, which specify the specific type of a generic when calling a method, can be used anywhere and in any scenario, including ordinary and generic classes.

public class GenericsClass<K,V> { private K date; private V value; Private V getValue(K date){returnvalue; } // genericsMethod private <T> T genericsMethod(T date){return date;
    }

    public GenericsClass(K date, V value) {
        this.date = date;
        this.value = value;
    }

    private void print(){
        System.out.println("Generic type");
    }
    public static void main(String [] args){
        GenericsClass<String,Integer> genericsClass = new GenericsClass<>("k", 123); genericsClass.print(); int a = genericsClass.getValue("k");
        System.out.println("v="+a); }}Copy the code

Generic methods must declare the returned type through a < type placeholder >, such as <V>, etc

Generics qualify type variables

Usually when we use it, we want to make sure that all the types are the same method, we need to put constraints on the type variables, for example, calculate the minimum and maximum of two variables, in order to make sure that the two variables passed must have a compareTo method, right? We need to restrict T to classes that implement interface Comparable

private <T extends Comparable> T min(T a,T b){
       return a.compareTo(b)>0 ? b:a;
    }
Copy the code

T extends Comparable where T refers to the subtype of the type to be bound. Comparable refers to the binding type. Both subtypes and binding types can be classes or interfaces. Such as T,V extends Comparable & Serializable Notice that only one class is allowed in a restricted type, and if there is a class, that class must be the first in the restricted list. This class qualification applies to both generic methods and generic classes

 private <T extends Comparable & Serializable> T min(T a, T b){
       return a.compareTo(b)>0 ? b:a;
    }
Copy the code

Constraints and limitations in generics

  1. Type parameters cannot be instantiated with primitive types
public class GenericsClass<K,V> { private K date; private V value; Private V getValue(K date){returnvalue; } // genericsMethod private <T> T genericsMethod(T date){return date;
    }

    private <T extends Comparable & Serializable> T min(T a, T b){
       return a.compareTo(b)>0 ? b:a;
    }

    public GenericsClass(K date, V value) {
        this.date = date;
        this.value = value;
    }

    private void print(){
        System.out.println("Generic type"); } public static void main(String [] args){GenericsClass<String,int> GenericsClass = new GenericsClass<>("k",123);
    }
}
Copy the code
  1. Runtime type queries apply only to primitive types
public class GenericsClass<K> {
    private K date;

    private void print(){
        System.out.println("Generic type");
    }
    public static void main(String [] args){
        GenericsClass<String> genericsClass = new GenericsClass<>();
        GenericsClass<String> genericsClass_ = new GenericsClass<>();
        System.out.println("GenericsClass ="+genericsClass_.getClass().getName().toString());
        System.out.println("Generic type genericsClass_="+genericsClass_.getClass().getName().toString()); }}Copy the code

The output

The generic type genericsClass = com. MTX. Javalib. GenericsClass generic type genericsClass_ = com. MTX. Javalib. GenericsClassCopy the code
  1. The static context type variable of a generic class is invalid

You cannot reference a type variable in a static field or method. Because generics are not known until the object is created, object creation code executes the static part first, constructors second, and so on. So the static part is executed before the object is initialized. If you refer to a generic in the static part, the virtual machine will no doubt know what it is because the class has not been initialized yet. 4. Cannot create arrays of parameterized types

public class GenericsClass<K> {
    private K date;

    private void print(){
        System.out.println("Generic type"); } public static void main(String [] args){GenericsClass<String>[] GenericsClass = new GenericsClass<String>()[3]; }}Copy the code

Why is this, mostly because of the way Generics are implemented in Java, which we’ll talk about later

  1. Type variables cannot be instantiated
  2. Cannot capture an instance of a generic class
 public <T extends Throwable> T testMethod(T t){
        try {
            System.out.println("Generic type exceptions cannot be caught");
        }catch (T e){
        }
        return t;
    }
Copy the code

But it can be done this way

public <T extends Throwable> T testMethod(T t){
        try {
            System.out.println("Generic type exceptions cannot be caught");
        }catch (Throwable e){
        }
        return t;
    }
Copy the code

Inheritance rules for generic types

Generic classes can inherit or extend other generic classes, such as List and ArrayList

Wildcard type

In general, there are two types of wildcards for generics,

  • ? Extends X represents an upper bound on a type whose argument is a subclass of X or itself
  • ? Super X represents the lower bound of the type, and the type argument is the superclass of X
public class Car {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Bmw extends Car {
    @Override
    public String getName() {
        return super.getName();
    }
    @Override
    public void setName(String name) { super.setName(name); }}Copy the code
public class Bmw extends Car {
    @Override
    public String getName() {
        return super.getName();
    }
    @Override
    public void setName(String name) {
        super.setName(name);
    }

    public static void testMethod(GenericsClass<? extends Car> car){
        System.out.println("Type arguments can only be subclasses of Car");
    }

    public static void  main(String[] args){
        GenericsClass<Bmw> genericsClass = new GenericsClass();
        testMethod(genericsClass); }}Copy the code

Java generics principles

Generics in the Java language, commonly known as pseudo-generics, exist only in the program source code. In the compiled bytecode file, they have been replaced with the original Raw Type (also known as bare Type), and the corresponding cast code has been inserted. Therefore, for the Runtime Java language, ArrayList < int > is the same class as ArrayList < String >, so generics technology is actually a syntactic sugar of the Java language. In The Java language, the implementation method of generics is called type erasing. Generics based on this method are called pseudo-generics. Method calls under various scenarios (virtual machine parsing, reflection, and so on) can have an impact on the underlying and new requirements, such as how to retrieve incoming parameterized types in generic classes. As a result, the JCP organization modified the virtual machine specification to introduce new attributes such as Signature and LocalVariableTypeTable to solve the problem of identifying parameter types that come with generics. Signature is the most important of these attributes. Its function is to store the characteristic signature of a method at the bytecode level [3]. The parameter type stored in this property is not the native type, but contains the information of the parameterized type. The modified VM specifications require that all VMS that can recognize Class files of version 49.0 or higher correctly recognize the Signature parameter. In addition, we can also conclude from the appearance of Signature attribute that the so-called erasure is only the bytecode in the Code attribute of the method. In fact, the metadata still retains the generic information, which is the basic basis of the parameterized type through reflection