Spa*_*ker 14 java eclipse jls language-lawyer java-8
给出以下课程:
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用以下内容构建类时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>
Run Code Online (Sandbox Code Playgroud)
在maven 3.4中,它产生以下编译错误:
[错误]无法执行目标org.apache.maven.plugins:maven-compiler-plugin:3.3:在项目java-compiler-test上编译(default-compile):编译失败[错误] C:\ Users\abrieg\workingcopy\java-compiler-test\src\main\java\FooTest.java:[25] FooTest.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/错误/ show_bug.cgi?ID = 430987
如果这是一个回归,这已经报告给jdt?
据我了解,这段代码应该可以编译,但当然不是没有未经检查的警告。
\n\n您已经声明了一个原始类型service的变量,它是原始类型的子类型,它有一个擦除 的方法。 AbstractService Servicevoid service(Base)void\xc2\xa0service(T)
因此,调用可能会调用在 中声明service.service(base)的方法,当然,会出现未经检查的警告,因为该方法是通用的,并且没有发生类型参数的验证。void service(Base)ServiceT
这可能是违反直觉的,因为类型使用AbstractService擦除的方法覆盖该方法void service(Derived),但该方法只能在通用上下文中覆盖其他方法,而不能在原始类型中覆盖继承关系中覆盖。
或者,换句话说,类型可以\xe2\x80\x99t 重写方法,其方式是在参数类型方面比重写的超类型方法更具限制性。
\n\n这也适用于泛型类型继承,但结果不同。如果您的变量具有类型AbstractService<X>,则由于类型参数的约束,X必须可分配给。Derived该类型AbstractService<X>是其子类型,Service<X>它有一个方法void\xc2\xa0service(X)(如T:= ),该方法被接受相同参数类型的方法X覆盖(实现) 。AbstractService<X>void\xc2\xa0service(X)
由于您的网站上似乎存在一些混乱,我想强调这与您的陈述无关if(\xe2\x80\xa6 instanceof Derived)。如上所述,此行为是由于原始类型使用造成的,这意味着您正在使用AbstractService,并且基本上关闭了泛型类型检查。如果你写了,这甚至可以工作
public void bar(Base base) {\n service.service(base); // UNCHECKED invocation\n}\nRun Code Online (Sandbox Code Playgroud)\n\n如果您将变量的声明更改为
\n\nprivate AbstractService<Derived> service;\nRun Code Online (Sandbox Code Playgroud)\n\n它不再是原始类型,并且类型检查将会发生,并且service.service(base)会生成编译器错误,无论您是否将其括起来if(base instanceof Derived) { \xe2\x80\xa6 }是否将其括起来。
原始类型的存在只是为了与泛型之前的代码兼容,您应该避免使用它们,并且不要忽略原始类型引发的警告使用引起的警告。
\n| 归档时间: |
|
| 查看次数: |
1015 次 |
| 最近记录: |