Java 语法糖 - 泛型擦除

Java About 3,854 words

示例

Java 代码

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(10);
        Integer x = list.get(0);
    }
}

字节码

Code:中字节码都将泛型擦除了。

14: invokevirtualadd的是Object类型。

23: checkcast:在get获取时会先校验转换。

public static void main(java.lang.String[]);
  descriptor: ([Ljava/lang/String;)V
  flags: (0x0009) ACC_PUBLIC, ACC_STATIC
  Code:
    stack=2, locals=3, args_size=1
       0: new           #2                  // class java/util/ArrayList
       3: dup
       4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
       7: astore_1
       8: aload_1
       9: bipush        10
      11: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      14: invokevirtual #5                  // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
      17: pop
      18: aload_1
      19: iconst_0
      20: invokevirtual #6                  // Method java/util/ArrayList.get:(I)Ljava/lang/Object;
      23: checkcast     #7                  // class java/lang/Integer
      26: astore_2
      27: return
    LineNumberTable:
      line 7: 0
      line 8: 8
      line 9: 18
      line 10: 27
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      28     0  args   [Ljava/lang/String;
          8      20     1  list   Ljava/util/ArrayList;
         27       1     2     x   Ljava/lang/Integer;
    LocalVariableTypeTable:
      Start  Length  Slot  Name   Signature
          8      20     1  list   Ljava/util/ArrayList<Ljava/lang/Integer;>;
  MethodParameters:
    Name                           Flags
    args

说明

在方法参数和返回值上的泛型不会被擦除。

Java 代码

public class Test2 {

    public Set<Integer> test(List<String> list, Map<Integer, Object> map) {
        return null;
    }

}

字节码

可以看到方法体上有泛型类型。

Signature也有泛型。

public java.util.Set<java.lang.Integer> test(java.util.List<java.lang.String>, java.util.Map<java.lang.Integer, java.lang.Object>);
  descriptor: (Ljava/util/List;Ljava/util/Map;)Ljava/util/Set;
  flags: (0x0001) ACC_PUBLIC
  Code:
    stack=1, locals=3, args_size=3
       0: aconst_null
       1: areturn
    LineNumberTable:
      line 14: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       2     0  this   Lcom/example/dao/Test2;
          0       2     1  list   Ljava/util/List;
          0       2     2   map   Ljava/util/Map;
    LocalVariableTypeTable:
      Start  Length  Slot  Name   Signature
          0       2     1  list   Ljava/util/List<Ljava/lang/String;>;
          0       2     2   map   Ljava/util/Map<Ljava/lang/Integer;Ljava/lang/Object;>;
  MethodParameters:
    Name                           Flags
    list
    map
  Signature: #42                          // (Ljava/util/List<Ljava/lang/String;>;Ljava/util/Map<Ljava/lang/Integer;Ljava/lang/Object;>;)Ljava/util/Set<Ljava/lang/Integer;>;

可以通过反射获取这些未擦除的信息

public static void main(String[] args) throws NoSuchMethodException {
    Method test = Test2.class.getMethod("test", List.class, Map.class);
    Type[] types = test.getGenericParameterTypes();
    for (Type type : types) {
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            System.out.println("原始类型#" + parameterizedType.getRawType());

            Type[] arguments = parameterizedType.getActualTypeArguments();
            for (int i = 0; i < arguments.length; i++) {
                System.out.println("泛型参数#" + i + ", " + arguments[i]);
            }
        }
    }
}

输出

原始类型#interface java.util.List
泛型参数#0, class java.lang.String
原始类型#interface java.util.Map
泛型参数#0, class java.lang.Integer
泛型参数#1, class java.lang.Object
Views: 1,774 · Posted: 2022-04-20

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb/LiteNote

扫描下方二维码关注公众号和小程序↓↓↓

扫描下方二维码关注公众号和小程序↓↓↓


Today On History
Browsing Refresh