[英]Why these generics don't compile in OpenJDK7, but do in OpenJDK6
class HasId<I> {}
class HasStringId extends HasId<String> {}
class Alert<T extends /*Some*/Object> extends HasStringId {}
class BaseController<M extends HasId<String>> {
// abstract Class<M> getModelClass();
}
class AlertController extends BaseController<Alert> { // error here
// @Override Class<Alert> getModelClass() {
// return Alert.class;
// }
}
compiles fine on OpenJDK6, but in OpenJDK7 gives: 在OpenJDK6上可以正常编译,但在OpenJDK7中可以提供:
AlertController.java:50: error: type argument Alert is not within bounds of
type-variable T
class AlertController extends BaseController<Alert> {
^
where T is a type-variable:
T extends HasId<String> declared in class BaseController
Note that there's rawtype warning at line 50, because Alert must be parameterized. 请注意,在第50行有原始类型警告,因为必须将Alert参数化。 If I do that, eg
extends BaseController<Alert<Object>>
, code compiles. 如果我这样做,例如
extends BaseController<Alert<Object>>
,代码就会编译。 But I cannot do that, because I need to implement getModelClass(). 但是我不能这样做,因为我需要实现getModelClass()。
UPDATE: That was a bug in Java 6 implementations, which was fixed in Java 7: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6559182 . 更新:这是Java 6实现中的错误,已在Java 7中修复: http : //bugs.sun.com/bugdatabase/view_bug.do?bug_id=6559182 。 (And here's my question to compiler devs: http://openjdk.5641.n7.nabble.com/Nested-generics-don-t-compile-in-1-7-0-15-but-do-in-1-6-0-27-td121820.html )
(这是我对编译器开发人员的问题: http : //openjdk.5641.n7.nabble.com/Nested-generics-don-t-compile-in-1-7-0-15-but-do-in-1 -6-0-27-td121820.html )
The question is whether HasId<String>
is a supertype of the raw type Alert
. 问题是
HasId<String>
是否是原始类型Alert
的超类型。 The spec is not very clear on this issue. 规格在这个问题上不是很清楚。
In the spirit of [4.8], the supertypes of a raw type should all be erased types too. 本着 [4.8]的精神 ,原始类型的超类型也应全部删除。 So
Alert
should have a supertype HasId
, but not HasId<String>
. 因此
Alert
应该具有HasId
的超类型,但不能具有HasId<String>
。 However the section talks only in terms of "super classes/interfaces", not in terms of "supertypes". 但是,本节仅针对“超类/接口”进行讨论,而不针对“超类型”进行讨论。
In the spirit of [4.10], the supertypes are discovered through direct supertypes. 本着[4.10]的精神,通过直接超型发现超型。 It's unclear how the section applies to raw types.
目前尚不清楚本节如何适用于原始类型。 It probably intends to rule that raw
Alert
has a direct supertype HasStringId
. 它可能打算裁定原始
Alert
具有直接超类型HasStringId
。 That seems fair. 看起来很公平。 Then because
HasId<String>
is a direct supertype of HasStringId
, by transitivity, HasId<String>
is a supertype of Alert
! 然后,由于
HasId<String>
是HasId<String>
的直接超类型, HasStringId
通过传递性, HasId<String>
是Alert
的超类型!
The confusion is rooted in the fact that there are actually two HasStringId
types, one normal, one raw. 混淆的根源在于实际上有两种
HasStringId
类型,一种是普通的,一种是原始的。 Even though HasStringId
is not generic in itself, its has a generic supertype, so it makes sense to talk about the raw version of HasStringId
. 即使
HasStringId
本身不是通用的,它也具有通用的超类型,因此谈论HasStringId
的原始版本是HasStringId
。
The spec does not make a distinction between the normal and raw HasStringId
. 规范没有在普通
HasStringId
和原始HasStringId
之间进行区分。 That's an oversight. 这是一个疏忽。
Suppose we denote the raw HasStringId
as HasStringId'
, then [4.10] makes more sense now. 假设我们将原始的
HasStringId
表示为HasStringId'
,那么[4.10]现在更有意义。 The direct super interface of raw Alert
is raw HasStringId'
. raw
Alert
的直接超级接口是raw HasStringId'
。 The direct super interface of raw HasStringId'
is raw HasId
. Raw
HasStringId'
的直接超级接口是raw HasId
。 Therefore HasId
is a supertype of Alert
, not HasId<String>
. 因此,
HasId
是Alert
的超类型,而不是HasId<String>
。
See section 4 of JLS . 参见JLS的第4节 。 I'm linking to the prev JLS here, since JLS 7 has serious editing errors in section 4.10.2
我在这里链接到上一个JLS,因为JLS 7在4.10.2节中存在严重的编辑错误
There are a number of documented cases of Java 7 compilers being stricter than Java 6 compilers for various generics nuances. 在许多通用的细微差别中, 有许多 Java 7编译器的案例比Java 6编译器更为严格。 These cases are often related to the actual language spec having become more specific.
这些情况通常与实际语言规范变得更加具体有关。 The error likely has to do with the use of any raw type essentially "opting out" of generics on inherited types - whether it's correct is debatable though.
该错误可能与使用任何原始类型实质上在继承的类型上“选择退出”泛型有关—尽管是否正确尚有待商bat。
EDIT: I couldn't find this issue in the list of JDK 7 incompatibilities . 编辑:我在JDK 7不兼容列表中找不到此问题。 The error is reproducible using sun-jdk-1.7.0_10 , but not with the Eclipse compiler (which historically has a much better track record than javac when it comes to generics nuances).
使用sun-jdk-1.7.0_10可以重现该错误,但使用Eclipse编译器则无法重现(就泛型细微差别而言 ,Eclipse编译器的记录远优于javac)。 You should submit an Oracle bug .
您应该提交一个Oracle错误 。
Here's a possible workaround: 这是一个可能的解决方法:
class AlertController extends BaseController<Alert<?>> {
@Override
@SuppressWarnings("unchecked")
Class<Alert<?>> getModelClass() {
return (Class<Alert<?>>)(Class<?>)Alert.class;
}
}
I believe this has to do with how erasure is handled in the absence of actual type parameters. 我认为这与在没有实际类型参数的情况下如何处理擦除有关。 When a parameterized type is referenced without any type parameters, all references to those parameters are erased.
当引用没有任何类型参数的参数化类型时,将删除对这些参数的所有引用。
In this instance, you have a parameterized type Alert
being used without any type parameter. 在这种情况下,将使用没有任何类型参数的参数化类型
Alert
。 This erases all type parameters on Alert
and its superclasses. 这将删除
Alert
及其超类上的所有类型参数。 This causes the type parameter of HasId
in the extends-clause of HasStringId
to be erased. 这将导致
HasId
的扩展子句中的HasStringId
的类型参数被擦除。 Alert
then does not subclass HasId<String>
because HasStringId
no longer extends it but rather extends HasId
. 然后
Alert
不会将HasId<String>
子类HasId<String>
因为HasStringId
不再扩展它,而是扩展了HasId
。
Paul B.'s workaround or the one below avoids this issue by always using Alert
with its type parameters. Paul B.的变通方法或以下解决方法始终使用
Alert
及其类型参数来避免此问题。
class AlertController<T> extends BaseController<Alert<T>> {
@Override Class<Alert<T>> getModelClass() {
return cast(Alert.class);
}
@SuppressWarnings("unchecked")
private <T> T cast(final Object o) {
return (T) o;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.