在使用泛型时,javac编译器是否为每种类型创建了不同的类?

bar*_*-md 1 java compiler-construction generics bytecode class

如果我有一个泛型类,编译器是否为我使用它的每个类型创建了一个不同的类?让我们考虑一下Class<T>.如果我创建类型的两个实例Class<Integer>Class<String>,该编译器创建两个不同的类别?

如果答案是否定的:扩展泛型类的类如何可以继承具有不同类型(来自单个类)的相同方法或属性.

另一个问题:为什么我不能var instanceof Class<Integer>使用参数化类型而不是ClassClass<?>

如果我尝试这样做,我会收到以下错误:"无法对参数化类型执行instanceof检查Test<Integer>.请改用表单,Test<?>因为在运行时将删除更多泛型类型信息"

你能给我更多关于仿制药的信息吗?

Mik*_*bel 11

如果我有一个泛型类,编译器是否为我使用它的每个类型创建了一个不同的类?我们来考虑这个班级.如果我创建类型为Class和Class的两个实例,编译器是否会创建两个不同的类?

不,有一个类,在字节码中,类型变量的所有外观都被有效地替换为它们的上限(通常Object,但可能U是表单类型变量的某种类型T extends U).这个概念称为类型擦除,因为类型变量被有效地擦除(并用它们的上限替换).

如果答案是否定的:扩展泛型类的类如何可以继承具有不同类型(来自单个类)的相同方法或属性.

有趣的问题!假设你有两个不同的类来实现Comparator<T>.一个实现Comparator<String>,另一个实现Comparator<Integer>.

Comparator<T> 定义以下方法:

int compare(T p0, T p1)
Run Code Online (Sandbox Code Playgroud)

那么两个不同的泛型实例如何使用不同的参数类型实现相同的方法呢?好吧,在代码中实现的方法实际上并没有覆盖Comparator.compare(). Comparer.compare()接受两个Object参数,但Comparator<String>.compare()接受两个String参数.他们的方法不一样.那么,为什么它表现得像一个覆盖?因为编译器会为您生成隐藏的桥接方法.通过反编译器或反汇编程序运行通用实现,以便自己查看.以下是我自己的Procyon反编译运行输出--show-synthetic:

public enum StringComparator implements Comparator<String> {
    ORDINAL {
        @Override
        public int compare(final String s1, final String s2) {
            if (s1 == null) {
                return (s2 == null) ? 0 : -1;
            }
            if (s2 == null) {
                return 1;
            }
            return s1.compareTo(s2);
        }

        @Override
        public /* bridge */ int compare(final Object x0, final Object x1) {
            return this.compare((String)x0, (String)x1);
        }
    },
    ...
}
Run Code Online (Sandbox Code Playgroud)

compare()一种方法是由StringComparator类的作者编写的实际实现.第二种方法是隐藏的,由编译器生成.它存在以"桥接"通用实现与其"擦除"定义,并且这是实现接口方法的桥接方法Comparator.compare().请注意bridge方法如何使用类型转换来强制绑定Tto String.这提供了在类型擦除世界中的安全措施.它确保以下产生异常:

class IntegerComparator implements Comparator<Integer> { ... }

// 'c' is a raw Comparator, or effectively a Comparator<Object>
// (note the lack of type arguments).
Comparator c = new IntegerComparator();
int result = c.compare(1, "hello");
Run Code Online (Sandbox Code Playgroud)

上面的代码编译得很好,因为原始形式Comparator.compare()接受两个Object参数.但是在运行时,调用将触发a,ClassCastException因为bridge方法IntegerComparator将尝试将字符串"hello"强制转换为Integer.

另一个问题:为什么我不能使用参数化类型而不是Class或Class <?>检查var instanceof Class <Integer>?

由于具体泛型类型的所有实例共享同一个类,其中所有类型变量都已被擦除,因此泛型类实例在其原始类型之外没有任何标识感.它不知道实例化它的类型参数,因为在编译期间该信息已被煮沸.如果实例化一个ArrayList<String>,则生成的实例只知道它是一个ArrayList.instance instanceof ArrayList<String>在这种情况下,检查无法产生有意义的结果.由于这种检查不能可靠地1产生有意义的结果,它们被禁止.


1 有趣的是,StringComparator上面的类的实例确实知道它实现了Comparator<String>,因为通用超类型信息保留在元数据中.