首页 > 解决方案 > 为什么泛型的这种使用不会引发运行时或编译时异常?

问题描述

我在一个类中有一个方法,该方法具有通过使用泛型指定的返回类型。

public class SomeMain {

  public static void main(String[] args) {

    Foo<Integer> foo = new Foo<Integer>();
    System.out.println(foo.getFoo()); // Works, prints out "Foo"

  }

  public static class Foo<E>  {
    public E getFoo() {
      return (E) "Foo";
    }
  }
}

对于通用返回类型,我假设上面示例中的返回值将计算为:

return (Integer) "Foo";  // Inconvertible types !!!

而是String返回并正确打印 a。

如果我将调用更改为:

String fooString = foo.getFoo(); // Compile error, incompatible types found
System.out.println(fooString);

我缺少什么来帮助我理解这里发生了什么以及为什么原始版本没有导致编译错误。

标签: javagenerics

解决方案


这是因为重载决议解决了您对 的println调用println(Object),因为没有println(Integer).

请记住,Java 的泛型在运行时会被删除。并且演员喜欢(E) "Foo"被删除,并被移动到呼叫站点。有时这不是必需的,因此仅在需要时才将事物转换为正确的类型。

换句话说,内部不执行任何类型转换getFoo。语言规范支持这一点:

第 5.5.2 节 检查的强制转换和未检查的强制转换

  • 演员表是完全未经检查的演员表。

    不会对此类强制转换执行任何运行时操作。

擦除后,getFoo返回Object。这被传递到println(Object),这非常好。

如果我调用这个方法并通过foo.getFoo,我得到一个错误:

static void f(Integer i) {
    System.out.println(i);
}
// ...
f(foo.getFoo()); // ClassCastException

因为这一次需要铸造。


推荐阅读