【问题标题】:Cast to generic type (T) is never checked by the compiler?编译器从不检查转换为泛型类型(T)吗?
【发布时间】:2017-10-29 20:30:52
【问题描述】:
static <T> void f1(Base arg1, T arg2) {
    T loc = (T) arg1; // why Derived is "kind of cast" to String?
    System.out.println(loc.getClass().getName()); // would print: Derived
}

f1(new Derived(), "sdf");  // T is String - inferred from arg2

class Base { }

class Derived extends Base { }

我的想法是否正确:编写强制转换 (T) 的意思是“编译器不能也不会检查这个强制转换”在编译时编译器不知道 arg2 是什么(它可以是任何东西),因此编译器不能排除强制转换可以工作并且必须信任程序员。因此,这个演员表只是在编译时从未检查过。 在运行时本地 var 声明看起来像 Object loc = arg1;(在类型擦除之后)。所以一切正常,只是因为编译器从不关心这个 (T) 转换?

P.S:我的研究:thisthisThis is also very interesting ("casting primitive to generic": (T) true) 我的问题更明确地指出了这个问题,问题也是关于编译器是否检查了转换(T)并且代码示例中没有分心有问题。

【问题讨论】:

  • 我不确定你在这里问什么:你是说编译器在给出这段代码时会做什么?它是否编译?
  • 显式强制转换总是受信任的。当然,程序员经常会背叛这种信任。
  • @AndyTurner 你是对的。这不是 100% 的时间。我更多的是考虑涉及泛型的情况。
  • 试图回答它,它超出了编译器的能力来现场检查演员表。但是,当您尝试调用特定类型的内容时,jvm 最终会检查类型。是你想知道的吗?
  • 在未来,类型擦除会走得更远。运行时类型将出现;例如,List&lt;int&gt; 有努力,所以语言仍然没有僵化。

标签: java generics casting


【解决方案1】:

这在JLS Sec 5.5.1:

给定一个编译时引用类型 S(源)和一个编译时引用类型 T(目标),如果由于以下规则没有发生编译时错误,则存在从 S 到 T 的强制转换。

...

如果 T 是类类型,则 |S| <:>

...

如果 T 是类型变量,则递归应用此算法,使用 T 的上限代替 T。

因此编译器使用Object 代替T,因此它认为强制转换是合法的。

【讨论】:

    【解决方案2】:

    在编译时,编译器不知道 arg2 是什么(它可能是任何东西),因此编译器不能排除强制转换可以工作并且必须信任程序员。

    我宁愿说编译器不知道 T 会是什么。它可以是例如Object 在这种情况下,演员表将是合法的。在这种情况下,设计师决定更喜欢允许可能非法的演员表而不是不允许可能合法的演员表。

    其他问题是编译器不能产生实际的“cast to T”,因为JVM只有“cast to specific class”指令。因此,演员表似乎在运行时也成功了。

    如果您真的想要检查演员表,您可以通过传递 Class&lt;T&gt; 作为额外参数来实现它:

    static <T> void f1(Base arg1, Class<T> clazz) {
        T loc = clazz.cast(arg1); // will throw exception
        System.out.println(loc.getClass().getName());
    }
    

    在你的情况下,你可以

    static <T> void f1(Base arg1, T arg2) {
        T loc = (T) arg2.getClass().cast(arg1);
        System.out.println(loc.getClass().getName());
    }
    

    弄清楚它在什么情况下与之前的代码不同应该是有益的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-02
      • 2023-04-05
      • 1970-01-01
      • 2015-07-31
      • 1970-01-01
      • 2011-08-13
      • 1970-01-01
      相关资源
      最近更新 更多