这是来自第三方库API的真实示例,但已简化.
使用Oracle JDK 8u72编译
考虑这两种方法:
<X extends CharSequence> X getCharSequence() {
return (X) "hello";
}
<X extends String> X getString() {
return (X) "hello";
}
Run Code Online (Sandbox Code Playgroud)
两者都报告了"未经检查的演员"警告 - 我明白了.困扰我的是我为什么打电话
Integer x = getCharSequence();
Run Code Online (Sandbox Code Playgroud)
它编译?编译器应该知道Integer没有实现CharSequence.打电话给
Integer y = getString();
Run Code Online (Sandbox Code Playgroud)
给出错误(如预期的那样)
Run Code Online (Sandbox Code Playgroud)incompatible types: inference variable X has incompatible upper bounds java.lang.Integer,java.lang.String
有人可以解释为什么这种行为被认为是有效的?它会有用吗?
客户端不知道此调用是不安全的 - 客户端的代码在没有警告的情况下编译.为什么编译器不会警告/发出错误?
另外,它与这个例子有什么不同:
<X extends CharSequence> void doCharSequence(List<X> l) {
}
List<CharSequence> chsL = new ArrayList<>();
doCharSequence(chsL); // compiles
List<Integer> intL = new ArrayList<>();
doCharSequence(intL); // …Run Code Online (Sandbox Code Playgroud) 为什么以下代码编译?该方法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.
据我所知,Java中泛型的主要目的之一是提供编译时类型安全性.如果它被编译,代码将运行没有问题.
那么为什么要编译以下代码?
public static void main(String[] args) {
String s = getList();
}
private static <T extends List> T getList() {
return (T)new ArrayList();
}
Run Code Online (Sandbox Code Playgroud)
它汇编很好.我的类型安全编译在哪里?该getList()方法与String班级没有任何共同之处.
我最近被以下 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)