Java - 泛型类型 - 类型擦除

7
我在Oracle网站上找到了以下问题和答案。 在类型擦除后,下列类被转换成什么?
public class Pair<K, V> {

    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public K getKey(); { return key; }
    public V getValue(); { return value; }

    public void setKey(K key)     { this.key = key; }
    public void setValue(V value) { this.value = value; }

    private K key;
    private V value;
}

回答:

public class Pair {

    public Pair(Object key, Object value) {
        this.key = key;
        this.value = value;
    }

    public Object getKey()   { return key; }
    public Object getValue() { return value; }

    public void setKey(Object key)     { this.key = key; }
    public void setValue(Object value) { this.value = value; }

    private Object key;
    private Object value;
}

但是,当我使用JD-GUI反编译class文件时,我仍然看到所有泛型类型与实际源代码中的类似。
这是否意味着泛型类型在class文件中保留?我正在使用Java 6。
使用JD-GUI解码器版本的类如下所示。 我正在使用Eclipse Helios编译类。
public class Pair<K, V>
{
  private K key;
  private V value;

  public Pair(K key, V value)
  {
    this.key = key;
    this.value = value;
  }
  public K getKey() {
    return this.key; } 
  public V getValue() { return this.value; } 
  public void setKey(K key) {
    this.key = key; } 
  public void setValue(V value) { this.value = value;
  }
}

你是如何编译这些类的?某些编译器选项可能包含调试信息。 - madth3
我正在使用Eclipse。因此,它会自动编译类文件。然后我使用JD-GUI工具来反编译类文件。 - Jack
1个回答

7
在.class文件中保留了一些泛型类型信息——足以使您通过反射确定Pair类型是泛型的,对于具有Pair成员的类,可以确定其泛型参数的类型等。保留此信息的事实形成了像super type tokens这样的技术的基础,允许您传递保留有关其泛型参数信息的类型标记。
但是,在反射之外,类型擦除意味着Pair类大多会表现为Oracle网站上“Answer”中剥离版本中的行为。特别是,方法的实际字节码不会引用泛型类型K或V——只有Object,并且方法签名将接受并返回Object。
在这种情况下,JD-GUI只是聪明地使用存储在.class文件中的信息来恢复反编译输出中的泛型信息,但请放心,类型在字节码中被擦除了。

1
也许如果您发布类的反编译版本会有所帮助。我的意思是,字节码将操作“对象”,而不是K或V(它们本来就不是具体类型)。可能是您的反汇编器很好地使用了类文件中记录的通用信息来显示通用类型,但是字节码本身不会反映这一点(例如,对(V)的转换根本不会出现在字节码中)。 - BeeOnRope
备选措辞:字节码知道有一个名为K的变量,但在运行时,如果你有一个Pair<String, Integer>K将不会是String——它只是Object - Louis Wasserman
在这种情况下,JD-GUI只是机智地利用了.class文件中存储的信息。这回答了我的问题...非常感谢。 - Jack
我的意思是字节码将操作对象而不是K或V(它们本来就不是具体类型)。实际的字节码并没有变量的“类型”。你不会“操作一个对象”或“操作一个字符串”或“操作一个K”;你只会操作一个引用值。“类型”适用于变量,这是一个编译时的概念。在运行时,你只有值。 - newacct
@BeeOnRope - 顺便说一下,这里有一个关于你答案的后续问题 - https://dev59.com/bZXfa4cB1Zd3GeqPaymX - MasterJoe
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接