【发布时间】:2015-06-24 09:02:15
【问题描述】:
给定以下课程:
public class FooTest {
public static class Base {
}
public static class Derived extends Base {
}
public interface Service<T extends Base> {
void service(T value);
}
public abstract class AbstractService<T extends Derived> implements Service<T> {
public void service(T value) {
}
}
private AbstractService service;
public void bar(Base base) {
if(base instanceof Derived) {
service.service(base); // compile error at this line
}
}
}
使用以下pom.xml 构建类时:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mgm-tp</groupId>
<artifactId>java-compiler-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerId>eclipse</compilerId>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-eclipse</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
在 maven 3.4 中会产生以下编译错误:
[ERROR] 无法在项目 java-compiler-test 上执行目标 org.apache.maven.plugins:maven-compiler-plugin:3.3:compile (default-compile):编译失败 [错误] C:\Users\abrieg\workingcopy\java-compiler-test\src\main\java\FooTest.java:[25] FooTest.Service 类型中的方法 service(FooTest.Base) 不适用于参数(FooTest.Base)
将eclipse编译器的源和目标级别设置为1.7或使用javac作为编译器时,不会报告编译错误。
问题是 JLS 1.8 是否对类型推断更具体,以至于 eclipse 编译器对 java 1.8 的假设确实不允许使用此代码,或者这是否是 eclipse 编译器中的回归。
根据编译器错误的文本,我倾向于说它是一种回归,但我不确定。
我已经确定了以下两个已经报告给 jdt 的错误,但我认为它们并不完全适用:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=432603
https://bugs.eclipse.org/bugs/show_bug.cgi?id=430987
如果这是回归,是否已经向 jdt 报告过?
【问题讨论】:
-
用 javac 编译得很好 - 问题可能是 eclipse 特有的......
-
但是为什么呢?服务需要一个 T 扩展 Derived,但得到一个 Base 对象(尽管它被检查为实际上是 Derived 的实例,并且可能被强制转换。
-
@baraber 在语句
service.service(base);中,编译器可以推断出base的类型为Derived,因为前面的 if 语句带有base instanceof Derived表达式。因此,将问题改写为“编译器可以/应该/必须使用它从 instanceof 表达式中获得的信息吗?” -
@SpaceTrucker 我不知道这里发生了什么(它为我编译),但方法
service是 重载。如果你不相信我,你可以这样做for (Method method : FooTest.AbstractService.class.getMethods()) if (method.getName().equals("service")) System.out.println(method);。由于AbstractService实现了Service,并且Service有一个方法service接受Base,因此在AbstractService接受Base中创建了对此的综合覆盖。这是接受Derived的service方法的重载。 -
它为我编译,但 IntelliJ 显示为红色。我在 Java 1.8.0_45 上。
标签: java eclipse java-8 language-lawyer jls