字节码分析-泛型

源码

package java.bytecode;

/**
 * 泛型示例 - 演示泛型类、泛型方法
 */
public class GenericExample<T extends Number> {

    private T genericField;

    public GenericExample(T value) {
        this.genericField = value;
    }

    // 泛型方法
    public <E> E genericMethod(E param) {
        return param;
    }

    // 泛型方法 - 多个类型参数
    public <K, V> void genericMethod2(K key, V value) {
        System.out.println("Key: " + key + ", Value: " + value);
    }

    public T getGenericField() {
        return genericField;
    }

    public void setGenericField(T genericField) {
        this.genericField = genericField;
    }
}

结构化反解析

Classfile /D:/zcp/github/yggdrasil/java/bytecode/GenericExample.class
  Last modified 2025-12-3; size 1271 bytes
  MD5 checksum 491fa07e2f426ab948e734dbb313c1c8
  Compiled from "GenericExample.java"
public class java.bytecode.GenericExample<T extends java.lang.Number> extends java.lang.Object
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
  ...
{
  private T genericField;
    descriptor: Ljava/lang/Number;
    flags: ACC_PRIVATE
    Signature: #44                          // TT;

  public java.bytecode.GenericExample(T);
    descriptor: (Ljava/lang/Number;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: aload_1
         6: putfield      #7                  // Field genericField:Ljava/lang/Number;
         9: return
    Signature: #48                          // (TT;)V

  public <E extends java.lang.Object> E genericMethod(E);
    descriptor: (Ljava/lang/Object;)Ljava/lang/Object;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=2, args_size=2
         0: aload_1
         1: areturn
    Signature: #51                          // <E:Ljava/lang/Object;>(TE;)TE;

  public <K extends java.lang.Object, V extends java.lang.Object> void genericMethod2(K, V);
    descriptor: (Ljava/lang/Object;Ljava/lang/Object;)V
    flags: ACC_PUBLIC
    Code:
      ...
    Signature: #54                          // <K:Ljava/lang/Object;V:Ljava/lang/Object;>(TK;TV;)V

  public T getGenericField();
    descriptor: ()Ljava/lang/Number;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #7                  // Field genericField:Ljava/lang/Number;
         4: areturn
    Signature: #57                          // ()TT;

  public void setGenericField(T);
    descriptor: (Ljava/lang/Number;)V
    flags: ACC_PUBLIC
    Code:
      ...
    Signature: #48                          // (TT;)V
}
Signature: #59                          // <T:Ljava/lang/Number;>Ljava/lang/Object;
SourceFile: "GenericExample.java"

详细说明

Signature属性

泛型信息存储在Signature属性中,而不是方法描述符中:

类型擦除

泛型在运行时被擦除,只保留原始类型(Raw Type):

方法描述符

方法描述符使用擦除后的类型:

public GenericExample(T);
  descriptor: (Ljava/lang/Number;)V  // T被擦除为Number

public <E> E genericMethod(E);
  descriptor: (Ljava/lang/Object;)Ljava/lang/Object;  // E被擦除为Object

类型检查

泛型的类型检查在编译时完成,运行时通过类型转换保证类型安全:

14: checkcast     #18  // class java/lang/Integer

桥接方法

编译器可能生成桥接方法以保持类型安全,但在本例中未生成。

泛型的作用

  1. 编译时类型检查:确保类型安全
  2. 代码复用:避免类型转换
  3. 运行时擦除:保持向后兼容性

注意事项