Java泛型小记

前言

经常会看到 “泛型会在编译期擦除,但是运行时可以获取到”,自己也有过这样的疑惑。此处做一下笔记,记录一下认识和理解。

一、泛型概述

可以参照本文 Java 泛型,你了解类型擦除吗?

二、获取泛型类型

3.1、demo

参照本文Java通过反射获取泛型实际类型总结(什么可获取,什么不可获取)

文章中列出了几种可以通过反射在 runtime 获取泛型类型的情况:

package bean;

import java.lang.reflect.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TestCache extends LocalCache {

    private Map map = new HashMap<>();

    public TestCache(Map map) {
    }

    public void set(List list) {

    }

    public List get() {
        return null;
    }

    public static void main(String[] args) throws Exception {
        System.out.println("获取属性上的泛型: ");
        getFieldType();
        System.out.println("获取方法参数中的泛型类型: ");
        getMethodParamsType();
        System.out.println("获取方法返回值中的泛型类型: ");
        getMethodReturnType();
        System.out.println("获取构造方法中参数的泛型类型: ");
        getConstructorParamsType();
        System.out.println("获取当前类的直接父类上设置的泛型类型: ");
        getClassType();
    }

    /**
     * 获取属性的泛型类型
     *
     * @throws Exception
     */
    private static void getFieldType() throws Exception {
        Field field = TestCache.class.getDeclaredField("map");
        field.setAccessible(true);
        Type genericType = field.getGenericType();
        if (genericType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            Type[] typeList = parameterizedType.getActualTypeArguments();
            for (Type type : typeList) {
                System.out.println(type.getTypeName());
            }
        }
    }

    /**
     * 获取方法参数中的泛型类型
     *
     * @throws Exception
     */
    public static void getMethodParamsType() throws Exception {
        Method method = TestCache.class.getDeclaredMethod("set", List.class);
        Type[] types = method.getGenericParameterTypes();
        if (types[0] instanceof ParameterizedType) {
            System.out.println(((ParameterizedType) (types[0])).getActualTypeArguments()[0]);
        }
    }

    /**
     * 获取方法返回值中的泛型类型
     *
     * @throws Exception
     */
    public static void getMethodReturnType() throws Exception {
        Method method = TestCache.class.getDeclaredMethod("get");
        Type genericReturnType = method.getGenericReturnType();
        if (genericReturnType instanceof ParameterizedType) {
            System.out.println(((ParameterizedType) (genericReturnType)).getActualTypeArguments()[0]);
        }
    }

    /**
     * 获取构造方法中参数的泛型类型
     *
     * @throws Exception
     */
    public static void getConstructorParamsType() throws Exception {
        Constructor constructor = TestCache.class.getConstructor(Map.class);
        Type[] genericParameterTypes = constructor.getGenericParameterTypes();
        Type[] typeList = ((ParameterizedType) (genericParameterTypes[0])).getActualTypeArguments();
        for (Type type : typeList) {
            System.out.println(type.getTypeName());
        }
    }

    /**
     * 获取当前类的直接父类上设置的泛型类型
     */
    public static void getClassType() {
        Type genType = TestCache.class.getGenericSuperclass();
        Type type = ((ParameterizedType) genType).getActualTypeArguments()[0];
        System.out.println(type);
    }
}

我个人理解:
能从 class 文件中找到的泛型,都可以在 runtime 通过反射获取到,下面看一下 class 文件中哪些地方记录了泛型的类型。

3.2、class 文件一览

3.2.1、class 文件内容

 ~/Documents/projects/java-go/target/classes/bean  javap -v TestCache.class

Classfile /Users/dongbaowen/Documents/projects/java-go/target/classes/bean/TestCache.class
  Last modified 2021年2月11日; size 3721 bytes
  SHA-256 checksum 4d46ed7b93a4e7d51f9e3aa7e65832b01b342f11622a3ab0d52b64a5ccebbbb7
  Compiled from "TestCache.java"
public class bean.TestCache extends bean.LocalCache
  minor version: 0
  major version: 52
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #6                          // bean/TestCache
  super_class: #35                        // bean/LocalCache
  interfaces: 0, fields: 1, methods: 9, attributes: 2
Constant pool:
    #1 = Methodref          #35.#97       // bean/LocalCache."":()V
    #2 = Class              #98           // java/util/HashMap
    #3 = Methodref          #2.#97        // java/util/HashMap."":()V
    #4 = Fieldref           #6.#99        // bean/TestCache.map:Ljava/util/Map;
    #5 = Methodref          #6.#100       // bean/TestCache.getConstructorParamsType:()V
    #6 = Class              #101          // bean/TestCache
    #7 = String             #36           // map
    #8 = Methodref          #16.#102      // java/lang/Class.getDeclaredField:(Ljava/lang/String;)Ljava/lang/reflect/Field;
    #9 = Methodref          #103.#104     // java/lang/reflect/Field.setAccessible:(Z)V
   #10 = Methodref          #103.#105     // java/lang/reflect/Field.getGenericType:()Ljava/lang/reflect/Type;
   #11 = Class              #106          // java/lang/reflect/ParameterizedType
   #12 = Fieldref           #107.#108     // java/lang/System.out:Ljava/io/PrintStream;
   #13 = InterfaceMethodref #11.#109      // java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
   #14 = Methodref          #110.#111     // java/io/PrintStream.println:(Ljava/lang/Object;)V
   #15 = String             #50           // set
   #16 = Class              #112          // java/lang/Class
   #17 = Class              #113          // java/util/List
   #18 = Methodref          #16.#114      // java/lang/Class.getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
   #19 = Methodref          #115.#116     // java/lang/reflect/Method.getGenericParameterTypes:()[Ljava/lang/reflect/Type;
   #20 = Class              #117          // java/lang/StringBuilder
   #21 = Methodref          #20.#97       // java/lang/StringBuilder."":()V
   #22 = String             #118          // genericParameterTypes=
   #23 = Methodref          #20.#119      // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #24 = Methodref          #20.#120      // java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
   #25 = Methodref          #20.#121      // java/lang/StringBuilder.toString:()Ljava/lang/String;
   #26 = Methodref          #110.#122     // java/io/PrintStream.println:(Ljava/lang/String;)V
   #27 = String             #56           // get
   #28 = Methodref          #115.#123     // java/lang/reflect/Method.getGenericReturnType:()Ljava/lang/reflect/Type;
   #29 = String             #124          // genericReturnType=
   #30 = Class              #125          // java/util/Map
   #31 = Methodref          #16.#126      // java/lang/Class.getConstructor:([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
   #32 = Methodref          #127.#116     // java/lang/reflect/Constructor.getGenericParameterTypes:()[Ljava/lang/reflect/Type;
   #33 = Methodref          #16.#128      // java/lang/Class.getGenericSuperclass:()Ljava/lang/reflect/Type;
   #34 = String             #129          // params=
   #35 = Class              #130          // bean/LocalCache
   #36 = Utf8               map
   #37 = Utf8               Ljava/util/Map;
   #38 = Utf8               Signature
   #39 = Utf8               Ljava/util/Map;
   #40 = Utf8               
   #41 = Utf8               (Ljava/util/Map;)V
   #42 = Utf8               Code
   #43 = Utf8               LineNumberTable
   #44 = Utf8               LocalVariableTable
   #45 = Utf8               this
   #46 = Utf8               Lbean/TestCache;
   #47 = Utf8               LocalVariableTypeTable
   #48 = Utf8               Ljava/util/Map;
   #49 = Utf8               (Ljava/util/Map;)V
   #50 = Utf8               set
   #51 = Utf8               (Ljava/util/List;)V
   #52 = Utf8               list
   #53 = Utf8               Ljava/util/List;
   #54 = Utf8               Ljava/util/List;
   #55 = Utf8               (Ljava/util/List;)V
   #56 = Utf8               get
   #57 = Utf8               ()Ljava/util/List;
   #58 = Utf8               ()Ljava/util/List;
   #59 = Utf8               main
   #60 = Utf8               ([Ljava/lang/String;)V
   #61 = Utf8               args
   #62 = Utf8               [Ljava/lang/String;
   #63 = Utf8               Exceptions
   #64 = Class              #131          // java/lang/Exception
   #65 = Utf8               getFieldType
   #66 = Utf8               ()V
   #67 = Utf8               parameterizedType
   #68 = Utf8               Ljava/lang/reflect/ParameterizedType;
   #69 = Utf8               field
   #70 = Utf8               Ljava/lang/reflect/Field;
   #71 = Utf8               genericType
   #72 = Utf8               Ljava/lang/reflect/Type;
   #73 = Utf8               StackMapTable
   #74 = Class              #132          // java/lang/reflect/Field
   #75 = Class              #133          // java/lang/reflect/Type
   #76 = Utf8               getMethodParamsType
   #77 = Utf8               method
   #78 = Utf8               Ljava/lang/reflect/Method;
   #79 = Utf8               types
   #80 = Utf8               [Ljava/lang/reflect/Type;
   #81 = Class              #134          // java/lang/reflect/Method
   #82 = Class              #80           // "[Ljava/lang/reflect/Type;"
   #83 = Utf8               getMethodReturnType
   #84 = Utf8               genericReturnType
   #85 = Utf8               getConstructorParamsType
   #86 = Utf8               constructor
   #87 = Utf8               Ljava/lang/reflect/Constructor;
   #88 = Utf8               genericParameterTypes
   #89 = Utf8               type
   #90 = Utf8               Ljava/lang/reflect/Constructor;
   #91 = Utf8               getClassType
   #92 = Utf8               genType
   #93 = Utf8               params
   #94 = Utf8               Lbean/LocalCache;
   #95 = Utf8               SourceFile
   #96 = Utf8               TestCache.java
   #97 = NameAndType        #40:#66       // "":()V
   #98 = Utf8               java/util/HashMap
   #99 = NameAndType        #36:#37       // map:Ljava/util/Map;
  #100 = NameAndType        #85:#66       // getConstructorParamsType:()V
  #101 = Utf8               bean/TestCache
  #102 = NameAndType        #135:#136     // getDeclaredField:(Ljava/lang/String;)Ljava/lang/reflect/Field;
  #103 = Class              #132          // java/lang/reflect/Field
  #104 = NameAndType        #137:#138     // setAccessible:(Z)V
  #105 = NameAndType        #139:#140     // getGenericType:()Ljava/lang/reflect/Type;
  #106 = Utf8               java/lang/reflect/ParameterizedType
  #107 = Class              #141          // java/lang/System
  #108 = NameAndType        #142:#143     // out:Ljava/io/PrintStream;
  #109 = NameAndType        #144:#145     // getActualTypeArguments:()[Ljava/lang/reflect/Type;
  #110 = Class              #146          // java/io/PrintStream
  #111 = NameAndType        #147:#148     // println:(Ljava/lang/Object;)V
  #112 = Utf8               java/lang/Class
  #113 = Utf8               java/util/List
  #114 = NameAndType        #149:#150     // getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
  #115 = Class              #134          // java/lang/reflect/Method
  #116 = NameAndType        #151:#145     // getGenericParameterTypes:()[Ljava/lang/reflect/Type;
  #117 = Utf8               java/lang/StringBuilder
  #118 = Utf8               genericParameterTypes=
  #119 = NameAndType        #152:#153     // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #120 = NameAndType        #152:#154     // append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
  #121 = NameAndType        #155:#156     // toString:()Ljava/lang/String;
  #122 = NameAndType        #147:#157     // println:(Ljava/lang/String;)V
  #123 = NameAndType        #158:#140     // getGenericReturnType:()Ljava/lang/reflect/Type;
  #124 = Utf8               genericReturnType=
  #125 = Utf8               java/util/Map
  #126 = NameAndType        #159:#160     // getConstructor:([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
  #127 = Class              #161          // java/lang/reflect/Constructor
  #128 = NameAndType        #162:#140     // getGenericSuperclass:()Ljava/lang/reflect/Type;
  #129 = Utf8               params=
  #130 = Utf8               bean/LocalCache
  #131 = Utf8               java/lang/Exception
  #132 = Utf8               java/lang/reflect/Field
  #133 = Utf8               java/lang/reflect/Type
  #134 = Utf8               java/lang/reflect/Method
  #135 = Utf8               getDeclaredField
  #136 = Utf8               (Ljava/lang/String;)Ljava/lang/reflect/Field;
  #137 = Utf8               setAccessible
  #138 = Utf8               (Z)V
  #139 = Utf8               getGenericType
  #140 = Utf8               ()Ljava/lang/reflect/Type;
  #141 = Utf8               java/lang/System
  #142 = Utf8               out
  #143 = Utf8               Ljava/io/PrintStream;
  #144 = Utf8               getActualTypeArguments
  #145 = Utf8               ()[Ljava/lang/reflect/Type;
  #146 = Utf8               java/io/PrintStream
  #147 = Utf8               println
  #148 = Utf8               (Ljava/lang/Object;)V
  #149 = Utf8               getDeclaredMethod
  #150 = Utf8               (Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
  #151 = Utf8               getGenericParameterTypes
  #152 = Utf8               append
  #153 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #154 = Utf8               (Ljava/lang/Object;)Ljava/lang/StringBuilder;
  #155 = Utf8               toString
  #156 = Utf8               ()Ljava/lang/String;
  #157 = Utf8               (Ljava/lang/String;)V
  #158 = Utf8               getGenericReturnType
  #159 = Utf8               getConstructor
  #160 = Utf8               ([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
  #161 = Utf8               java/lang/reflect/Constructor
  #162 = Utf8               getGenericSuperclass
{
  public bean.TestCache(java.util.Map);
    descriptor: (Ljava/util/Map;)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=3, locals=2, args_size=2
         0: aload_0
         1: invokespecial #1                  // Method bean/LocalCache."":()V
         4: aload_0
         5: new           #2                  // class java/util/HashMap
         8: dup
         9: invokespecial #3                  // Method java/util/HashMap."":()V
        12: putfield      #4                  // Field map:Ljava/util/Map;
        15: return
      LineNumberTable:
        line 20: 0
        line 18: 4
        line 21: 15
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      16     0  this   Lbean/TestCache;
            0      16     1   map   Ljava/util/Map;
      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
            0      16     1   map   Ljava/util/Map;
    Signature: #49                          // (Ljava/util/Map;)V

  public void set(java.util.List);
    descriptor: (Ljava/util/List;)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=0, locals=2, args_size=2
         0: return
      LineNumberTable:
        line 25: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       1     0  this   Lbean/TestCache;
            0       1     1  list   Ljava/util/List;
      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
            0       1     1  list   Ljava/util/List;
    Signature: #55                          // (Ljava/util/List;)V

  public java.util.List get();
    descriptor: ()Ljava/util/List;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aconst_null
         1: areturn
      LineNumberTable:
        line 28: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       2     0  this   Lbean/TestCache;
    Signature: #58                          // ()Ljava/util/List;

  public static void main(java.lang.String[]) throws java.lang.Exception;
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: invokestatic  #5                  // Method getConstructorParamsType:()V
         3: return
      LineNumberTable:
        line 32: 0
        line 33: 3
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       4     0  args   [Ljava/lang/String;
    Exceptions:
      throws java.lang.Exception

  public static void getMethodParamsType() throws java.lang.Exception;
    descriptor: ()V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=6, locals=2, args_size=0
         0: ldc           #6                  // class bean/TestCache
         2: ldc           #15                 // String set
         4: iconst_1
         5: anewarray     #16                 // class java/lang/Class
         8: dup
         9: iconst_0
        10: ldc           #17                 // class java/util/List
        12: aastore
        13: invokevirtual #18                 // Method java/lang/Class.getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
        16: astore_0
        17: aload_0
        18: invokevirtual #19                 // Method java/lang/reflect/Method.getGenericParameterTypes:()[Ljava/lang/reflect/Type;
        21: astore_1
        22: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
        25: new           #20                 // class java/lang/StringBuilder
        28: dup
        29: invokespecial #21                 // Method java/lang/StringBuilder."":()V
        32: ldc           #22                 // String genericParameterTypes=
        34: invokevirtual #23                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        37: aload_1
        38: invokevirtual #24                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
        41: invokevirtual #25                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        44: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        47: aload_1
        48: iconst_0
        49: aaload
        50: instanceof    #11                 // class java/lang/reflect/ParameterizedType
        53: ifeq          78
        56: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
        59: aload_1
        60: iconst_0
        61: aaload
        62: checkcast     #11                 // class java/lang/reflect/ParameterizedType
        65: checkcast     #11                 // class java/lang/reflect/ParameterizedType
        68: invokeinterface #13,  1           // InterfaceMethod java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
        73: iconst_0
        74: aaload
        75: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        78: return
      LineNumberTable:
        line 56: 0
        line 57: 17
        line 58: 22
        line 59: 47
        line 60: 56
        line 62: 78
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           17      62     0 method   Ljava/lang/reflect/Method;
           22      57     1 types   [Ljava/lang/reflect/Type;
      StackMapTable: number_of_entries = 1
        frame_type = 253 /* append */
          offset_delta = 78
          locals = [ class java/lang/reflect/Method, class "[Ljava/lang/reflect/Type;" ]
    Exceptions:
      throws java.lang.Exception

  public static void getMethodReturnType() throws java.lang.Exception;
    descriptor: ()V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=6, locals=2, args_size=0
         0: ldc           #6                  // class bean/TestCache
         2: ldc           #27                 // String get
         4: iconst_1
         5: anewarray     #16                 // class java/lang/Class
         8: dup
         9: iconst_0
        10: ldc           #17                 // class java/util/List
        12: aastore
        13: invokevirtual #18                 // Method java/lang/Class.getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
        16: astore_0
        17: aload_0
        18: invokevirtual #28                 // Method java/lang/reflect/Method.getGenericReturnType:()Ljava/lang/reflect/Type;
        21: astore_1
        22: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
        25: new           #20                 // class java/lang/StringBuilder
        28: dup
        29: invokespecial #21                 // Method java/lang/StringBuilder."":()V
        32: ldc           #29                 // String genericReturnType=
        34: invokevirtual #23                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        37: aload_1
        38: invokevirtual #24                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
        41: invokevirtual #25                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        44: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        47: aload_1
        48: instanceof    #11                 // class java/lang/reflect/ParameterizedType
        51: ifeq          74
        54: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
        57: aload_1
        58: checkcast     #11                 // class java/lang/reflect/ParameterizedType
        61: checkcast     #11                 // class java/lang/reflect/ParameterizedType
        64: invokeinterface #13,  1           // InterfaceMethod java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
        69: iconst_0
        70: aaload
        71: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        74: return
      LineNumberTable:
        line 70: 0
        line 71: 17
        line 72: 22
        line 73: 47
        line 74: 54
        line 76: 74
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           17      58     0 method   Ljava/lang/reflect/Method;
           22      53     1 genericReturnType   Ljava/lang/reflect/Type;
      StackMapTable: number_of_entries = 1
        frame_type = 253 /* append */
          offset_delta = 74
          locals = [ class java/lang/reflect/Method, class java/lang/reflect/Type ]
    Exceptions:
      throws java.lang.Exception

  public static void getConstructorParamsType() throws java.lang.Exception;
    descriptor: ()V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=5, locals=3, args_size=0
         0: ldc           #6                  // class bean/TestCache
         2: iconst_1
         3: anewarray     #16                 // class java/lang/Class
         6: dup
         7: iconst_0
         8: ldc           #30                 // class java/util/Map
        10: aastore
        11: invokevirtual #31                 // Method java/lang/Class.getConstructor:([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
        14: astore_0
        15: aload_0
        16: invokevirtual #32                 // Method java/lang/reflect/Constructor.getGenericParameterTypes:()[Ljava/lang/reflect/Type;
        19: astore_1
        20: aload_1
        21: iconst_0
        22: aaload
        23: checkcast     #11                 // class java/lang/reflect/ParameterizedType
        26: checkcast     #11                 // class java/lang/reflect/ParameterizedType
        29: invokeinterface #13,  1           // InterfaceMethod java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
        34: iconst_0
        35: aaload
        36: astore_2
        37: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
        40: aload_2
        41: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        44: return
      LineNumberTable:
        line 84: 0
        line 85: 15
        line 86: 20
        line 87: 37
        line 88: 44
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           15      30     0 constructor   Ljava/lang/reflect/Constructor;
           20      25     1 genericParameterTypes   [Ljava/lang/reflect/Type;
           37       8     2  type   Ljava/lang/reflect/Type;
      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
           15      30     0 constructor   Ljava/lang/reflect/Constructor;
    Exceptions:
      throws java.lang.Exception

  public static void getClassType() throws java.lang.Exception;
    descriptor: ()V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=2, args_size=0
         0: ldc           #6                  // class bean/TestCache
         2: invokevirtual #33                 // Method java/lang/Class.getGenericSuperclass:()Ljava/lang/reflect/Type;
         5: astore_0
         6: aload_0
         7: checkcast     #11                 // class java/lang/reflect/ParameterizedType
        10: invokeinterface #13,  1           // InterfaceMethod java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
        15: iconst_0
        16: aaload
        17: astore_1
        18: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
        21: new           #20                 // class java/lang/StringBuilder
        24: dup
        25: invokespecial #21                 // Method java/lang/StringBuilder."":()V
        28: ldc           #34                 // String params=
        30: invokevirtual #23                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        33: aload_1
        34: invokevirtual #24                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
        37: invokevirtual #25                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        40: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        43: return
      LineNumberTable:
        line 96: 0
        line 97: 6
        line 98: 18
        line 99: 43
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            6      38     0 genType   Ljava/lang/reflect/Type;
           18      26     1 params   Ljava/lang/reflect/Type;
    Exceptions:
      throws java.lang.Exception
}
Signature: #94                          // Lbean/LocalCache;
SourceFile: "TestCache.java"

查看 class 文件内容,发现 LocalVariableTypeTable 中的 Signature 包含了方法中存在的泛型,类似于:

      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
            0      16     1   map   Ljava/util/Map;
    Signature: #49                          // (Ljava/util/Map;)V

下方的 Signature 的#后面的编号对应着 Constant pool 中保存的信息。每个方法中都可以通过 LocalVariableTypeTable 的 Signature 获取到代码中写的泛型实际类型。

至于成员属性,只有在 Constant pool 中保存着。

#39 = Utf8               Ljava/util/Map;

LocalVariableTypeTable 以及 Signature 的解释:
深入探索Java泛型的本质 | 泛型

你可能感兴趣的:(Java泛型小记)