My blog reprint please indicate the original source.

sequence

I was inspired to write about generics when I saw code like this:

This is what I was thinking:

So I hurried to review, write down. Foundation is not solid, the source code can not understand ah.

Generic introduction

Java Generics is a new feature introduced in JDK 5. Generics provide compile-time type-safety checks that allow programmers to detect illegal types at compile time. The nature of generics is parameterized typing, which means that the data type being operated on is specified as a parameter, and is widely used in the Java collections framework.

The focus of the definition is to provide a compile-time type-safety checking mechanism. For example, there is a generic class like this:

public class Generics <T> {

    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) { this.value = value; }}Copy the code

Then write a class like this:

public class Generics  {

    private Object value;

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) { this.value = value; }}Copy the code

They can also store all values, but generic classes have compile-time type safety checks:

A generic class

A class that defines one or more type variables is a generic class. The syntax is that class names are enclosed in Angle brackets and type variables are written inside separated by commas. You can then use type variables in method return types, parameters and fields, and local variables, but not in methods or fields decorated with static modifiers. Example:

Generics<String> Generics = new Generics<String>(); Generics<String> Generics = new Generics<>(); Generics<String> Generics = new Generics<>();Copy the code

Generic method

A method that defines one or more type variables is a generic method. Syntax is enclosed in Angle brackets after method modifiers and before return types, with type variables written inside separated by commas. Generic methods can be defined in both normal and generic classes. Generic methods can be modified by static modifiers. Example:

private <U> void out(U u) { System.out.println(u); } Test.<String>out("test"); In most cases, <String> can be omitted, and the compiler can infer that the type test.out ("test");
    
Copy the code

Qualification of a type variable

Sometimes we want to qualify a type variable. For example, to qualify a specified type variable, we need to implement the List interface so that we can call the method in the List interface in our code on a type variable without worrying about its absence.

public class Generics <T extends List> {

    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }

    public void add(Object u) {
        value.add(u);
    }

    public static void main(String[] args) {
        Generics<List> generics = new Generics<>();
        generics.setValue(new ArrayList<>());
        generics.add("ss"); System.out.println(generics.getValue()); }}Copy the code

Qualified syntax is to add the extends keyword to a type variable, followed by the qualified type, separated by ampersand. Type variables and qualified types can be classes or interfaces. Because Java classes can only inherit from one class, qualified types must be at the top of the qualified list.

Type erasure

Type erasure is created for compatibility purposes, the general idea being that there are no generic types in the virtual machine, generics only exist at compile time. Generic type variables are erased after compilation and replaced with the first qualified type (Object if there is no qualified type). The Generics

class above is erased to produce a corresponding primitive type:

public class Generics {

    private Object value;

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) { this.value = value; }}Copy the code

The reason we can set and return the correct type is because the compiler inserts the conversion instruction automatically.

    public static void main(String[] args) {
        Generics<String> generics = new Generics<>();
        generics.setValue("ss"); System.out.println(generics.getValue()); Public static void main(java.lang.string []);} javac Generics. Code: 0: new#3 // class generics/Generics
       3: dup
       4: invokespecial #4 // Method "
      
       ":()V
      
       7: astore_1
       8: aload_1
       9: ldc           #5 // String ss
      11: invokevirtual #6 // Method setValue:(Ljava/lang/Object;) V
      14: getstatic     #7 // Field java/lang/System.out:Ljava/io/PrintStream;
      17: aload_1
      18: invokevirtual #8 // Method getValue:()Ljava/lang/Object;
      21: checkcast     #9 // class java/lang/String
      24: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;) V
      27: return

Copy the code

We can see that a conversion instruction has been inserted at line 21.

Another problem with type erasure is that if we have a class that inherits a generic class and overwrites its parent class’s methods:

public class SubGenerics extends Generics<String> {

    @Override
    public void setValue(String value) {
        System.out.println(value);
    }

    public static void main(String[] args) {
        Generics<String> generics = new SubGenerics();
        generics.setValue("ss"); }}Copy the code

SubGenerics actually has two setValue methods because of type erasure, SubGenerics’ own setValue(String value) method and the setValue(Object value) method inherited from Generics. In the example, generics refers to a SubGenerics object, so we want to call subgenerics.setValue. To ensure correct polymorphism, the compiler generates a bridge method in the SubGenerics class:

public void setValue(Object value) {
    setValue((String) value);
}
Copy the code

We can compile and verify:

Compiled from "SubGenerics.java"
public class generics.SubGenerics extends generics.Generics<java.lang.String> {
  public generics.SubGenerics();
    Code:
       0: aload_0
       1: invokespecial #1 // Method generics/Generics."
      
       ":()V
      
       4: return

  public void setValue(java.lang.String);
    Code:
       0: getstatic     #2 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_1
       4: invokevirtual #3 // Method java/io/PrintStream.println:(Ljava/lang/String;) V
       7: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #4 // class generics/SubGenerics
       3: dup
       4: invokespecial #5 // Method "
      
       ":()V
      
       7: astore_1
       8: aload_1
       9: ldc           #6 // String ss
      11: invokevirtual #7 // Method generics/Generics.setValue:(Ljava/lang/Object;) V
      14: return

  public void setValue(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: checkcast     #8 // class java/lang/String
       5: invokevirtual #9 // Method setValue:(Ljava/lang/String;) V
       8: return
}
Copy the code

Java Core Technology Volume 1

In summary, remember the facts about Java generics transformations: 1. There are no generics in the virtual machine, only ordinary classes and methods. 2. All type parameters are replaced with their qualified types. 3. Bridge methods are synthesized to maintain polymorphism. 4. To maintain type security, insert casts if necessary.

Constraints and Limitations

  • Type variables cannot be base variables, such asInt, doubleAnd so on. Their wrapper classes should be usedAn Integer, a Double.
  • There are no generics in the virtual machine, so you cannot use run-time type queries, such asif (generics instanceof Generics<String>) // Error
  • An array of generic classes cannot be created because of type erasure, for exampleGenerics<String>[] generics = new Generics<String>[10]; // Error
  • Type variables cannot be instantiated, for examplenew T(...) new T[...] Or tc lass,

Wildcard type

Wildcard types are similar to the type variable qualifiers described above, except that wildcard types are used when they are declared and type variables are qualified when they are defined. Such as the wildcard type Generics
Type variables that represent any generic Generics type are List and subclasses of List.

Generics<? extends List> generics = new Generics<ArrayList>();

But the Generics method has changed since that declaration, to

This results in the inability to call the setValue method

The getValue method is fine

Supertype qualification

Wildcard qualification can also qualify superclasses, such as the wildcard type Generics
The type variables that represent any generic Generics type are ArrayList and the superclasses of ArrayList.

Generics<? super ArrayList> generics = new Generics<List>();

Similarly, The Generics method has changed to become

Calling getValue can only assign values to Object variables

The setValue method can only be passed in ArrayList and subclasses of ArrayList, not List, Object, etc

Reflection and generics

Although there are no generics in virtual machines due to type erasure. However, erased classes still retain some information about generics, which can be retrieved using reflection related apis.

Similarly, look at generic methods

public static <T extends Comparable<? super T>> T min(T[] a)

This is after erasure

public static Comparable min(Coniparable[] a)

You can use the reflection API to determine:

  • This generic method has a name calledTType parameter of.
  • This type parameter has a subtype qualification and is itself a generic type.
  • This qualified type takes a wildcard argument.
  • This wildcard parameter has a supertype qualification.
  • This generic method takes a generic array parameter.

Afterword.

Monday built a good draft, to Sunday to write, or delete some section of the case, afraid is late procrastination…… However, because there is so much generics content, although it is rare to write generic-related code in your daily business, it is difficult to read library source code without understanding generics, especially for collections. Most of this is from Java Core Technology Volume 1, a great book on the basics of Java. But still the old rule, not just read, or write down in your own language. As we all know, the nature of human beings is a reread machine. To repeat the contents of a good book is equivalent to my responsibility!