Bee*_*ope 5 java eclipse javac language-lawyer
考虑以下returnsNull函数并使用泛型类型调用它:
public static <T> List<T> returnNull(Class<? extends T> clazz) {
return null;
}
public static void main( String[] args )
{
List<AtomicReference<?>> l = returnNull(AtomicReference.class);
}
Run Code Online (Sandbox Code Playgroud)
Eclipse编译器在设置为Java 8时接受它,但javac在Java 8中拒绝它:
incompatible types: cannot infer type-variable(s) T
(argument mismatch; java.lang.Class<java.util.concurrent.atomic.AtomicReference> cannot be converted to java.lang.Class<? extends java.util.concurrent.atomic.AtomicReference<?>>)
Run Code Online (Sandbox Code Playgroud)
底层差异似乎是给定两个参数化类型,P1<T>并且P2<T>Eclipse允许从使用原始内部类型参数化的外部类型转换为P1<P2>使用无界通配符的内部类型的下限参数化的外部类型P1<? extends P2<?>>.javac没有.
这不仅仅是一个理论上的思考:如果这个代码被接受,它将解决我的泛型过滤问题.
谁是对的?
在适用性推理过程中, ECJ 推断<T>,AtomicReference#RAW这让 的签名returnNull显示为
List<AtomicReference#RAW> returnNull(Class<? extends AtomicReference#RAW>)\nRun Code Online (Sandbox Code Playgroud)\n\n具体步骤是:
\n\n\xe2\x9f\xa8Class<AtomicReference#RAW> \xe2\x86\x92 Class<? extends T#0>\xe2\x9f\xa9\xe2\x9f\xa8Class<AtomicReference#RAW> <: Class<? extends T#0>\xe2\x9f\xa9\xe2\x9f\xa8AtomicReference#RAW <= ? extends T#0\xe2\x9f\xa9\xe2\x9f\xa8AtomicReference#RAW <: T#0\xe2\x9f\xa9AtomicReference#RAW <: T#0T#0 = AtomicReference#RAW现在,将类型值传递到该方法中没有问题Class<AtomicReference#RAW>。
(后缀 #RAW 是原始类型的实现特定表示,为了清楚起见,在此处复制)。
\n\n编辑:在调用类型推断期间事情看起来有所不同:通过将目标类型添加到混合中,我们最终(在合并期间)具有以下约束:
\n\n\xe2\x9f\xa8AtomicReference#RAW <: AtomicReference<?>\xe2\x9f\xa9此约束应减少为 FALSE,但 ecj 减少为 TRUE。由此看来,拒绝该计划似乎才是正确的答案。
\n\n我向 ECJ 提交了错误 528970以便进一步调查。
\n\n这有一些讽刺意味,因为javac 有一个长期存在的错误,它错误地假设T#RAW <: T<X>. 出于兼容性原因,ECJ 明确将此错误复制到许多位置,但显然在一个特定代码位置,情况恰恰相反:javac 在 ECJ 检查兼容性的位置应用子类型。
编辑2:一年后,ECJ 中的错误似乎只能在 JLS 在JDK-8054721及其周围进行改进后才能修复。
\n| 归档时间: |
|
| 查看次数: |
145 次 |
| 最近记录: |