The introduction

Before talking about Ali Fastjson, let’s talk about some basic knowledge of generics and how to get generics in reflection. Think you can skip to the end of the directory to see what you have mastered

A generic class

A generic class is defined as long as the class name is followed by < E>, where E can be any letter or multiple letters separated by commas. Sample code is as follows

public class SelfList<E> {}
Copy the code

Inference of the actual type in a generic class

So when are we going to determine what type E is? In fact, when new an object, look at the following code

public class SelfList<E> {

    public void add(E e) {
        if (e instanceof String) {
            System.out.println(" I am String");
        } else if (e instanceof Integer) {
            System.out.println("I am Integer"); }} public static void main(String[] SelfList<String> a = new SelfList<String>(); a.add("123"); Integer SelfList<Integer> b = new SelfList<Integer>(); b.add(123); }}Copy the code

A generic interface

Generic interfaces are used in the same way as classes

Public interface IndicatorTypeService<T> {} public interface ProductSale <T> {} Public class ProductSaleServiceImpl implements IndicatorTypeService<ProductSale> {}Copy the code

Generic method

This one, I think, is relatively rare, so pay close attention to me, because maybe the generic approach you’ve been thinking about is fake. Ok, first give a fake generic method for you to test, or the above code example, for easy reading I paste the code again

Public void add(E E) {public void add(E E) {if (e instanceof String) {
            System.out.println(" I am String");
        } else if (e instanceof Integer) {
            System.out.println("I am Integer"); }}Copy the code

Definition of generic methods

Okay, the point is, define a true generic method

    public <T> T get(T t) {
        return t;
    }
Copy the code
  1. The < T> between the return value and public is a requirement for generic methods, and this and the generic E defined by the class can be named (usually with different names), and they are independent of each other.

  2. can be multiple, separated by commas, columns such as
    ,v>
  3. The return value does not have to be T, but can be of any type, such as Long
  4. The argument in a method does not have to be T, but can be of any type, such as Long. It’s just a generic method that usually returns a value type and a parameter, one of which is a defined generic (all concrete types are meaningless).
    public <T> T get(T t) {
        returnt; } public static void main(String[] SelfList<String> a = new SelfList<String>(); a.add("123");
        int num = a.get(123);
    }
Copy the code

Inference of actual generics in generic methods

So how does the generic method determine this specific type? The main idea is to determine the specific type by calling the parameter type and return value type passed in the generic method

  1. Generic variables appear only once in the argument list, and are called based on the type of argument passed
    public <T>  T get1(T t) {
        if (t instanceof String) {
            System.out.println(" I am String");
        } else if (t instanceof Integer) {
            System.out.println("I am Integer");
        }
        returnt; } public static void main(String[] args) { SelfList<String> a = new SelfList<String>(); Int b= a.get_1 (123); // Int b= a.get_1 (123); }Copy the code

The output

I am Integer
Copy the code
  1. When multiple arguments in the argument list use the same generic variable and the return value type also uses that variable, the return value type is determined by their common parent class
    public <T> T get2(T t, T t2) {
        if (t instanceof Float) {
            System.out.println(" I am String");
        } else if (t instanceof Integer) {
            System.out.println("I am Integer");
        } else if (t instanceof Number) {
            System.out.println("I am Number");

        }
        returnt; } public static void main(String[] args) { SelfList<String> a = new SelfList<String>(); Number b = a.get2(123, 12.1); }Copy the code

Note that the output above will still be

I am Integer
Copy the code

Because according to the first rule, whatever type is passed in is what type, but the return value type needs to be determined according to the second rule, okay

Use of generics in reflection

These are generic types that can be determined before compilation. You know, generics actually get erased when they run. But it doesn’t matter, it gives us a way to get it by reflection. First I’ll look at generic type inheritance structures in Java

ParameterizedType source

Public interface ParameterizedType extends Type {/** * Returns an array of the actual Type * such as ArrayList<T>, ArrayList<String> returns String * */ Type[] getActualTypeArguments(); For List<T>, return List */ Type getRawType(); SelfHashMap SelfHashMap SelfHashMap SelfHashMap SelfHashMap SelfHashMap SelfHashMap SelfHashMap Selfhashmap. Entry<String,String> * Returns SelfHashMap */ Type getOwnerType(); }Copy the code

ParameterizedType Test verification

Define a class with an inner class

public class SelfHashMap {

    public static class Entry<T, V extends Collection> {

    }

}
Copy the code

Write a test class

public class ParameterizedTypeTest { public static void main(String[] args) { Class clazz = A.class; // The JDK does not provide a generic Type for this classtype = clazz.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type; System.out.println(Arrays.toString(parameterizedType.getActualTypeArguments())); System.out.println(parameterizedType.getRawType()); System.out.println(parameterizedType.getOwnerType()); }} /** * The generics specified here are String and List * getActualTypeArguments() which outputs String and List */ public static class extends SelfHashMap.Entry<String, List> { } }Copy the code

The output

[class java.lang.String, interface java.util.List]
class com.wizhuo.jdklearning.reflect.dto.SelfHashMap$Entry
class com.wizhuo.jdklearning.reflect.dto.SelfHashMap
Copy the code

TypeVariable source

Public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {/** * For example, <T, V extends Collection> where the upper bound is Collection */ Type[] getBounds(); /** * returns the class and interface that declared the generic variable. Public static class Entry<T, V extends Collection> returns Entry */ D getGenericDeclaration(); /** */ String getName(); */ AnnotatedType[] getAnnotatedBounds(); }Copy the code

Write a test class

public class TypeVariableTest {

    public static void main(String[] args) {
        Class clazz = SelfHashMap.Entry.class;
        TypeVariable[] typeVariables = clazz.getTypeParameters();
        for (TypeVariable ty :typeVariables) {
            System.out.println(ty.getName());
            System.out.println(Arrays.toString(ty.getAnnotatedBounds()));
            System.out.println((Arrays.toString(ty.getBounds())));
            System.out.println(ty.getGenericDeclaration());
            System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = ="); }}}Copy the code

Output result

T
[sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@3fee733d]
[class java.lang.Object]
class com.wizhuo.jdklearning.reflect.dto.SelfHashMap$Entry
============================
V
[sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@5acf9800]
[interface java.util.Collection]
class com.wizhuo.jdklearning.reflect.dto.SelfHashMap$Entry
Copy the code

Ali fastjson generic clever use

See the code below, which simply means taking the string from Redis and converting it to the specified generic class. Notice that we created an anonymous TypeReference class with a {} at the end, so we instantiated an anonymous inner class (which is the main point, where all the magic starts), not an instance of the TypeReference class

        List<ResourceEntity> resources =
            redisAdapter.get(BaseConstant.TENANT_CODE_SYSTEM, CacheKey.KEY_ALL_RESOURCE,
                new TypeReference<List<ResourceEntity>>() {
                });
Copy the code

View the source code

Click on the source code


    protected final Type type;
    /** * Protected, which means we can only subclass this class when we create it. After all, our class cannot be in the same package directory as Alibaba fastjson. We then pass in the final generic we want to convert * such as the code above new TypeReference
      
       >() {} List
       
         is the type we want to convert * * */
       
      
    protected TypeReference(a){
        The JDK does not support getting its own generics. This is done by inheriting the class and changing it to get the generics of the subclass
        Type superClass = getClass().getGenericSuperclass();
        // Return the actual type of the generic, List
      
        type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
    }
Copy the code

After watching two things

If you find this article inspiring, I’d like to invite you to do me two small favors:

  1. Like, so that more people can see this content (collection does not like, is a rogue -_-)
  2. Pay attention to the public number “interview BAT”, do not regularly share the original knowledge, the original is not easy, please support more (it also provides brush small program oh).