当使用泛型时,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);
}
}