Java Generics:谁是对的,javac还是Eclipse编译?

tbk*_*tbk 2 java eclipse compiler-construction javac

调用此方法:

public static @Nonnull <TV, TG extends TV> Maybe<TV> something(final @Nonnull TG value) {
    return new Maybe<TV>(value);
}
Run Code Online (Sandbox Code Playgroud)

像这样:

public @Nonnull Maybe<Foo> visit() {
    return Maybe.something(new BarExtendsFoo());
}
Run Code Online (Sandbox Code Playgroud)

在Eclipse中编译得很好,但是javac给出了一个"不兼容的类型"警告:

found   : BarExtendsFoo
Run Code Online (Sandbox Code Playgroud)

要求:Foo

Ita*_*man 5

javac和Eclipse之间显然存在一些差异.但是,这里的要点是javac在发出错误时是正确的.最终,您的代码将Maybe <BarExtendsFoo>转换为有风险的Maybe <Foo>.

这是access()方法的重写:

  public static <TV, TG extends TV> Maybe<TV> something(final TG value) {
     return new Maybe<TV>(value);
  }

  public static class Foo { }

  public static class BarExtendsFoo extends Foo { }

  public Maybe<Foo> visit() {
     Maybe<BarExtendsFoo> maybeBar = something(new BarExtendsFoo());
     Maybe<Foo> maybeFoo = maybeBar;  // <-- Compiler error here

     return maybeFoo;      
  }
Run Code Online (Sandbox Code Playgroud)

这个重写几乎与你的代码完全相同,但它明确地显示了你想要从Maybe <BarExtendsFoo>到Maybe <Foo>的作业.这是有风险的.实际上,我的Eclipse编译器在赋值行上发出错误.这是一段利用此风险将一个Integer存储在Maybe <String>对象中的代码:

  public static void bomb() {
     Maybe<String> maybeString = new Maybe<String>("");

     // Use casts to make the compiler OK the assignment
     Maybe<Object> maybeObject = (Maybe<Object>) ((Object) maybeString); 
     maybeObject.set(new Integer(5));

     String s = maybeString.get(); // Runtime error (classCastException):
                                   //   java.lang.Integer incompatible with  
                                   //   java.lang.String
  }
Run Code Online (Sandbox Code Playgroud)