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

当使用泛型时,javac编译器是否为每种类型创建不同的类?,java,class,generics,compiler-construction,bytecode,Java,Class,Generics,Compiler Construction,Bytecode,如果我有一个泛型类,编译器会为我使用的每个类型创建不同的类吗?让我们考虑一下这个代码>类< /代码>。如果我创建类型为Class和Class的两个实例,编译器会创建两个不同的类吗 如果答案是否定的:扩展泛型类的类如何可能继承具有不同类型的相同方法或属性(来自单个类) 另一个问题:为什么我不能使用参数化类型而不是Class或Class来检查类的var instanceof 如果尝试执行此操作,则会出现以下错误: “无法对参数化类型Test执行instanceof check。请改用Test格式,因

如果我有一个泛型类,编译器会为我使用的每个类型创建不同的类吗?让我们考虑一下这个代码>类< /代码>。如果我创建类型为
Class
Class
的两个实例,编译器会创建两个不同的类吗

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

另一个问题:为什么我不能使用参数化类型而不是
Class
Class
来检查类的
var instanceof

如果尝试执行此操作,则会出现以下错误: “无法对参数化类型
Test
执行instanceof check。请改用
Test
格式,因为运行时将删除更多的泛型类型信息”


你能给我更多关于泛型的信息吗?

不,任何
的类都是相同的。泛型只在编译之前存在,不在字节码中。这样做是为了向后兼容

有关更多信息,您可能需要阅读

如果我有一个泛型类,编译器会为我使用的每个类型创建不同的类吗?让我们来考虑一下这门课。如果我创建两个Class和Class类型的实例,编译器会创建两个不同的类吗

不,只有一个类,在字节码中,类型变量的所有外观都有效地替换为其上限(通常是
对象
,但可能是
T扩展U
形式的类型变量的某些类型
)。这个概念被称为类型擦除,因为类型变量被有效地擦除(并替换为它们的上界)

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

有趣的问题!假设有两个不同的类实现了
Comparator
。一个实现
比较器
,另一个实现
比较器

Comparator
定义了以下方法:

int compare(T p0, T p1)
那么,两个不同的泛型实例如何用不同的参数类型实现相同的方法呢?好的,代码中实现的方法实际上并没有覆盖
Comparator.compare()
Comparer.compare()
接受两个
Object
参数,但
Comparator.compare()
接受两个
String
参数。它们不是相同的方法。那么,为什么它的行为像一个覆盖?因为编译器会为您生成一个隐藏的桥接方法。通过反编译程序或反汇编程序运行一个通用实现,以便自己查看。下面是我自己运行的反编译器的输出,它使用
--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);
        }
    },
    ...
}
上面的代码编译得很好,因为
Comparator.compare()的原始形式接受两个
Object
参数。但是在运行时,调用将触发一个
ClassCastException
,因为
IntegerComparator
中的桥接方法将尝试将字符串“hello”转换为
整数

另一个问题:为什么我不能使用参数化类型而不是类或类来检查类的var instanceof

由于一个具体泛型类型的所有实例共享同一个类,其中所有类型变量都已被删除,因此泛型类实例除了其原始类型之外没有任何身份感。它不知道实例化它时使用的类型参数,因为这些信息在编译过程中被蒸发掉了。如果实例化
ArrayList
,则生成的实例只知道它是
ArrayList
。在这种情况下,检查ArrayList的实例实例不能产生有意义的结果。由于此类检查无法可靠地产生有意义的结果,因此不允许进行此类检查



1有趣的是,上面的
StringComparator
类的一个实例确实知道它实现了
Comparator
,因为泛型超类型信息保留在元数据中。

不,只有一个类,因为参数化类型只在运行时已知,编译器无法为每个匹配类型创建类

扩展泛型类时,将继承方法和成员。我不明白你的目的。。。 例如:

public class MyClass<T> extends AbstractMyClass<T> {

    @Override
    public void add(T element) {
        // do something with element...
    }


}

   public class MyClass<T> {
       private final List<T> store = new ArrayList<T>();

       protected void add(T element) {
          store.add(element);
       }
  }
公共类MyClass扩展了AbstractMyClass{
@凌驾
公共无效添加(T元素){
//用元素做点什么。。。
}
}
公共类MyClass{
私有最终列表存储=新建ArrayList();
受保护的空添加(T元素){
存储。添加(元素);
}
}
[版本]好的,我想我不理解你第一次提出的关于延期的问题。。。对不起。[/edition]

您不能检查instanceof,因为参数化类型在运行时是未知的。
您可以这样做:检查您的参数化类型是否相同。

简短的回答是否。类型参数只是。。。参数。查找类型擦除。不,这就是为什么在rutime的许多情况下,您实际上无法分辨使用了哪种泛型类型。这是一个编译时功能。这个问题是一个教学书的例子,重复。。。它非常常见,在Oracle教程中有一个专门的部分。请参阅副本。
public class MyClass<T> extends AbstractMyClass<T> {

    @Override
    public void add(T element) {
        // do something with element...
    }


}

   public class MyClass<T> {
       private final List<T> store = new ArrayList<T>();

       protected void add(T element) {
          store.add(element);
       }
  }