preface

The first time you’re exposed to Java, compiling once, running everywhere, it feels powerful and must be sunk. But now the mainstream use of Java or the back-end of the scene, graphical interface development is not good at. Java’s continued dominance in the competition for back-end languages has a lot to do with the Java ecosystem, but there’s no denying that Java is reliably stable in high-concurrency scenarios. I also read an evaluation of golang language today and am ready to consider it as a technical reserve under entry. When I have time to study, I must study more.

Recently decided to spend some time duking up Java and decided to take a look at the JDK source code to the next level. I also want to write a series of blogs about Java and SpringBoot.

The generic

JDK 1.5 before

When I went into Java, it was JDK 1.7. But generics are a good thing. Before generics we might have written code like this

    @Test
    public void run1(a) {
        // There is a collection where you want to store String data
        List list =new ArrayList();

        list.add("1111");

        String o = (String) list.get(0);
        System.out.println(o.length());

        // May cause other developers to store ints
        list.add(2222);
    }
Copy the code

Problems with the above code:

  • The elements stored in the collection need to be cast to use the corresponding Api.
  • Compile-time syntax does not detect the problem I mentioned, which is potentially dangerous at run time

JDk 1.5

1.7 added features of rhombus generics that I doped together

        // There is a collection where you want to store String data
        List<String> list =new ArrayList();

        list.add("1111");

        String s = list.get(0);
        System.out.println(s.length());

        // The following error will be reported at compile time
        // list.add(2222);
Copy the code

Isn’t Big Ben less anti-human

The generic

Generics: Parameter typing

  • Generics can be declared on a class or method, and generics on a method take precedence over generics on a class. It is best not to declare the same name on a class for ease of understanding.
  • Static methods cannot be declared with generic declarations on a class, only on a method
  • Common generic declarations (T, E, K, V,?)
    • ? Represents an indeterminate Java type
    • T (type) indicates a specific Java type
    • K and V are key values in Java key values
    • E stands for Element
    • S, U, V, etc. : the second, third, and fourth types in the multi-parameter case

Code validation

  • Generics can be declared on a class or method, and generics on a method take precedence over generics on a class
public class ClientTest<T> {

    /** * verify that generics can be declared on classes and methods * not so 
      
        */
      

    public <T2 extends ArgsParent> T2 run2(T k) {
        System.out.println(k.getName());
        System.out.println(k);
        return(T2) k; }}Copy the code

This validates that generics can be declared on classes and methods

package com.fly.study.java.generics;

import org.junit.Before;
import org.junit.Test;

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

/ * * *@authorZhang qin * climbing@dateThe 2019-09-16-00:04 *@descriptionGeneric validation */
public class ClientTest<T> {

    private ClientTest clientTest;

    private Parent parent;

    private Son son;

    private ClientTest<Son> sonClientTest;

    private ArgsParent argsParent;

    private ArgsSon argsSon;


    /** * limits the generics and return value types of method arguments. Generics take precedence over methods that do not use class *

    public <T extends ArgsParent, T2 extends ArgsParent> T2 run2(T k) {
        System.out.println(k.getName());
        System.out.println(k);
        return (T2) k;
    }



    @Before
    public void before(a) {
        clientTest = new ClientTest();
        parent = new Parent();
        parent.setName("parent");

        son = new Son();
        son.setAge(18);

        sonClientTest = new ClientTest<>();

        argsParent = new ArgsParent();
        argsParent.setName("argsParent");
        argsSon = new ArgsSon();
    }

    @Test
    public void test2(a) {
        System.out.println(clientTest.run2(argsParent));
        System.out.println(clientTest.run2(argsSon));
        // Verify that generics on methods take precedence over generics on classes
        sonClientTest.run2(argsSon);
// The following is incorrect
// sonClientTest.run2(son);}}@Data
public class ArgsParent {
    private String name;
}

@Data
public class ArgsSon extends ArgsParent {
    private Integer age;
}

@Data
public class Parent {
    private String name;
}

@Data
public class Son extends Parent {
    private Integer age;
}
Copy the code

I’m using the same generic T on my class and on my method, but with different type constraints, the generic T on my class is ClientTest on my new object sonClientTest, and I’m specifying T on my method, when I run my method, Verify my conclusion if the argument can only be passed to ArgsParent and its subclasses.

        // public class ClientTest<T> 
        // public <T extends ArgsParent, T2 extends ArgsParent> T2 run2(T k)
        ArgsSon is a subclass of ArgsParent
        sonClientTest.run2(argsSon);
        // son is an instance of son
        // sonClientTest.run2(son);
Copy the code
  • Static methods cannot be declared with generics on a class, only on a method
public class ClientTest<T> {
    /** * static methods can not use generics on the class, can only be declared on the method */
    public static <T extends ArgsParent, T2 extends ArgsParent> void run4(T k) {
        System.out.println(k);
    }
  	
  	// Syntax error
    public static  void run4(T k) { System.out.println(k); }}Copy the code
  • Generic qualifier

Generic qualifiers are easy to understand literally; comments in the code will tell you what they mean

JDK 1.8 <S super ArgsParent> < ArgsParent <? Extends ArgsParent> // limits arguments to ArgsParent and its parent <? extends ArgsParent>Copy the code
public class AllGenerics<T> {

    public void run1(T t) {
        System.out.println(t);
    }

    public <S> void run2(S s) {
        System.out.println(s);
    }
    
    // Restrict the argument type to ArgsParent and its subclasses
    public <S extends ArgsParent> void run3(S s) {
        System.out.println(s);
    }
    
    // Syntax error,
    // public <S super ArgsParent> void run3(S s) {
    // System.out.println(s);
    / /}
    
    // Restrict the argument type to ArgsParent and its subclasses
    public void run4(List
        s) {
        System.out.println(s);
    }

    // Limit arguments to ArgsParent and its parent class
    public void run5(List<? super ArgsParent>  s) { System.out.println(s); }}Copy the code

Generic erasure

Generics are valid only at compile time, after which the generic declaration is replaced. For certain types, Object is used, and for uncertain ones.

  • When a generic type cannot be determined
/ / the source code
public class AllGenerics<T> {
     public void run1(T t) { System.out.println(t); }}// The compiled code can be interpreted like this

public class AllGenerics<Object> {
     public void run1(Object t) { System.out.println(t); }}Copy the code
  • Use generic qualifiers for
public class AllGenerics<T> {
     public <S extends ArgsParent> void run2(S s) { System.out.println(s); }}// The compiled code can be interpreted like this

public class AllGenerics<ArgsParent> {
     public void run1(ArgsParent t) { System.out.println(t); }}Copy the code

Code validation

  • Generics are only valid at compile time
@Data
public class ClientTestSuperT {
    @Test
    public void test1(a) throws Exception{
        List<String>t=new ArrayList<>();
        Method add = t.getClass().getMethod("add",Object.class);
        
        // Add an Integer number
        add.invoke(t,1); System.out.println(t); }}Copy the code
  • Generic erasure uses an identifiable type replacement
package com.fly.study.java.generics;


import org.junit.Test;

import java.lang.reflect.Method;


public class AllGenerics<T> {

    public <S extends ArgsParent> void run2(S s) {
        System.out.println(s);
    }

    public void run1(T t) {
        System.out.println(t);
    }

    @Test
    public void test1(a) throws Exception {
        AllGenerics<String> allGenerics =new AllGenerics<>();
        Method method= allGenerics.getClass().getMethod("run1", Object.class);
// java.lang.NoSuchMethodException:
// com.fly.study.java.generics.AllGenerics.run1(java.lang.String)
// Method method= allGenerics.getClass().getMethod("run1", String.class);
        method.invoke(allGenerics,"111");
    }

    @Test
    public void run2(a) throws Exception {
        AllGenerics<String> allGenerics =new AllGenerics<>();
        Method method= allGenerics.getClass().getMethod("run2", ArgsParent.class);
        ArgsParent argsParent = new ArgsParent();
        argsParent.setName("Test");
// java.lang.NoSuchMethodException: 
// com.fly.study.java.generics.AllGenerics.run1(java.lang.String)
// Method method= allGenerics.getClass().getMethod("run2", Object.class);method.invoke(allGenerics,argsParent); }}Copy the code
  • Verify the train of thought
AllGenerics<Object>Public void run1(Object t)
    public void run1(T t) {
        System.out.println(t);
    }
    
    Public void run2(ArgsParent s)
    public <S extends ArgsParent> void run2(S s) {
        System.out.println(s);
    }
Copy the code
  • Method run1 can be obtained by reflection. Method run1 can be obtained by reflection. Method run1 cannot be found by reflection

@Test
public void test1(a) throws Exception {
    AllGenerics<String> allGenerics =new AllGenerics<>();
    Method method= allGenerics.getClass().getMethod("run1", Object.class);
    method.invoke(allGenerics,"111");
}
Copy the code

The above code works fine, verifying that the code was actually replaced after compilation

@Test
public void test1(a) throws Exception {
    AllGenerics<String> allGenerics =new AllGenerics<>();
    Method method= allGenerics.getClass().getMethod("run1", String.class);
    method.invoke(allGenerics,"111");
}
Copy the code

The operating error code Java. Lang. NoSuchMethodException: com. Fly. Study. Java generics. AllGenerics. Run1 (Java. Lang. String), explain the compiled code there is no this way

  • For generics that use qualified types, replace them with qualified types
Public void run2(ArgsParent s)
public <S extends ArgsParent> void run2(S s) {
    System.out.println(s);
}
Copy the code
@Test
public void run2(a) throws Exception {
    AllGenerics<String> allGenerics =new AllGenerics<>();
    Method method= allGenerics.getClass().getMethod("run2", ArgsParent.class);
    ArgsParent argsParent = new ArgsParent();
    argsParent.setName("Test");
    method.invoke(allGenerics,argsParent);
}
Copy the code

The method obtained above shows that my guess is correct

@Test
public void run2(a) throws Exception {
    AllGenerics<String> allGenerics =new AllGenerics<>();
    ArgsParent argsParent = new ArgsParent();
    argsParent.setName("Test");
    Method method= allGenerics.getClass().getMethod("run2", Object.class);
    method.invoke(allGenerics,argsParent);
}
Copy the code

Code error, cannot find corresponding method

Recommended reading

Java generics understanding

Generics: How they work and why they’re important