我今天读了一条推文说:
当Java用户抱怨类型擦除时,这很有趣,这是Java唯一正确的做法,而忽略了所有错误的东西.
因此我的问题是:
Java的类型擦除是否有好处?除了JVM实现偏向于向后兼容性和运行时性能之外,它(可能)提供的技术或编程风格有哪些优势?
为什么以下代码编译?该方法IElement.getX(String)返回该类型IElement或其子类的实例.类中的代码Main调用该getX(String)方法.编译器允许将返回值存储到类型的变量中Integer(显然不在层次结构中IElement).
public interface IElement extends CharSequence {
<T extends IElement> T getX(String value);
}
public class Main {
public void example(IElement element) {
Integer x = element.getX("x");
}
}
Run Code Online (Sandbox Code Playgroud)
返回类型是否仍然是一个实例IElement - 即使在类型擦除之后?
该getX(String)方法的字节码是:
public abstract <T extends IElement> T getX(java.lang.String);
flags: ACC_PUBLIC, ACC_ABSTRACT
Signature: #7 // <T::LIElement;>(Ljava/lang/String;)TT;
Run Code Online (Sandbox Code Playgroud)
编辑:替换String与一致Integer.
为什么下面的代码片段会编译?OtherInterface没有扩展,Concrete所以我打赌肾脏,这将无法编译.但确实如此.
public class Test {
public static interface SomeInterface {}
public static interface OtherInterface{}
public static class Concrete implements SomeInterface {
public <T extends Concrete> T getConcrete() {
return null;
}
}
public static void doStuff() {
Concrete c = new Concrete();
OtherInterface iCompile = c.getConcrete();
}
}
Run Code Online (Sandbox Code Playgroud)
另一方面,下一个片段不能编译,这是我所期望的.
public class Test {
public static interface SomeInterface {}
public static class UnrelatedClass{}
public static class Concrete implements SomeInterface {
public <T extends Concrete> T getConcrete() { …Run Code Online (Sandbox Code Playgroud) 有这样的方法吗?
public <P, T extends List<P>> T getAwesomeList() {
// ...
}
Run Code Online (Sandbox Code Playgroud)
怎么编译没有任何警告?
Set<String> test = getAwesomeList();
Run Code Online (Sandbox Code Playgroud)
我认为这与通用擦除有关,但不确定编译器是怎么回事.这种情况发生在Java 7上,8时你会收到编译错误.
J8上有什么变化让这个不能编译?
更新:
经过仔细检查后,它还可以在Java 8上编译.
为什么javac不在此代码示例中中止类型错误
import java.util.List;
public class StaticMethodWithBoundedReturnType {
static class Foo {
}
static class Bar extends Foo {
}
static <F extends Foo> F getFoo(String string) {
…
}
public static void main(String[] args) {
// Compiles without error, even though List does not extend Foo.
List<Integer> list = getFoo("baz");
}
}
Run Code Online (Sandbox Code Playgroud)
显然List永远不可能是一个子类型Foo.即使存在一个List以某种方式扩展的子类型Foo,那么list在呼叫站点的分配getFoo()应该是无效的.我知道类型擦除的存在.但是不javac应该看到类型list不满足有界类型约束extends Foo因此失败编译时出现类型错误?
为什么javac无法使用有界类型参数作为返回类型来检查静态方法的调用站点?
看来我可以通过以下轻微修改获得类型安全性:
import java.util.List; …Run Code Online (Sandbox Code Playgroud) 我最近被以下 Java 代码惊呆了:
interface Common {}
interface A extends Common {}
static class B implements Common {}
static class Impl {
private A a;
public <T extends A> T translate() {
return (T) a;
}
}
static class Usage {
public void use() {
Impl impl = new Impl();
B b = impl.translate(); // Why does this compile?
}
}
Run Code Online (Sandbox Code Playgroud)
我本来期望的是在类型约束Impl.translate不会允许将结果存储在类型B由编译器所接受,考虑到B不延长A。代码UncheckedCastException在运行时抛出一个,而不是编译器错误。
这仅在方法返回类型时发生T;如果它是方法参数:
public <T extends A> …Run Code Online (Sandbox Code Playgroud)