Java字节码中的泛型的符号引用有什么作用?

ShinobuChyan
  • 63

有一段简单的程序如下:

import java.util.HashMap;

public class Test {

    private static HashMap<Integer, Object> m = new HashMap<>();

}

使用javap -verbose Test.class输出的字节码为:

public class com.test.Test
  minor version: 0
  major version: 55
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #5                          // com/test/Test
  super_class: #6                         // java/lang/Object
  interfaces: 0, fields: 1, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #6.#21         // java/lang/Object."<init>":()V
   #2 = Class              #22            // java/util/HashMap
   #3 = Methodref          #2.#21         // java/util/HashMap."<init>":()V
   #4 = Fieldref           #5.#23         // com/test/Test.m:Ljava/util/HashMap;
   #5 = Class              #24            // com/test/Test
   #6 = Class              #25            // java/lang/Object
   #7 = Utf8               m
   #8 = Utf8               Ljava/util/HashMap;
   #9 = Utf8               Signature
  #10 = Utf8               Ljava/util/HashMap<Ljava/lang/Integer;Ljava/lang/Object;>;
  #11 = Utf8               <init>
  #12 = Utf8               ()V
  #13 = Utf8               Code
  #14 = Utf8               LineNumberTable
  #15 = Utf8               LocalVariableTable
  #16 = Utf8               this
  #17 = Utf8               Lcom/test/Test;
  #18 = Utf8               <clinit>
  #19 = Utf8               SourceFile
  #20 = Utf8               Test.java
  #21 = NameAndType        #11:#12        // "<init>":()V
  #22 = Utf8               java/util/HashMap
  #23 = NameAndType        #7:#8          // m:Ljava/util/HashMap;
  #24 = Utf8               com/test/Test
  #25 = Utf8               java/lang/Object
{
  public com.test.Test();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 5: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/test/Test;

  static {};
    descriptor: ()V
    flags: (0x0008) ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: new           #2                  // class java/util/HashMap
         3: dup
         4: invokespecial #3                  // Method java/util/HashMap."<init>":()V
         7: putstatic     #4                  // Field m:Ljava/util/HashMap;
        10: return
      LineNumberTable:
        line 7: 0
}

可以注意到在常量池中有一个符号引用:#10 = Utf8 Ljava/util/HashMap<Ljava/lang/Integer;Ljava/lang/Object;>;

这里看上去似乎是一个包含了泛型信息的符号引用,但是整个字节码中并没有引用这个量,请问这个常量的作用是什么呢?

评论
阅读 831
2 个回答
✓ 已被采纳

通过java.lang.reflect.Field#getGenericType可以获得成员变量的泛型信息,这个引用大概就是为实现这个功能添加的。

public class Test {
    private static HashMap<Integer, Object> m = new HashMap<>();

    public static void main(String[] args) throws NoSuchFieldException {
        final Field m = Test.class.getDeclaredField("m");
        System.out.println(m.getGenericType());
        //java.util.HashMap<java.lang.Integer, java.lang.Object>
    }
}

关于擦除,应该是针对泛型类本身而言的,运行时通过HashMap实例本身无法获取它的泛型参数信息。

可能反射的时候用得到吧,虽然我利用反射取不到泛型参数。

撰写回答

登录后参与交流、获取后续更新提醒

宣传栏