Java Generics: Кто прав, Javac или Eclipse компилируются? - PullRequest
2 голосов
/ 11 января 2010

Вызов этого метода:

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

как это:

public @Nonnull Maybe<Foo> visit() {
    return Maybe.something(new BarExtendsFoo());
}

прекрасно компилируется в Eclipse, но javac выдает предупреждение «несовместимые типы»:

found   : BarExtendsFoo

требуется: Foo

Ответы [ 3 ]

5 голосов
/ 11 января 2010

Очевидно, что между Javac и Eclipse есть некоторые различия.Тем не менее, главное здесь заключается в том, что javac является правильным в выдаче ошибки.В конечном счете, ваш код преобразует Maybe в Maybe , что является рискованным.

Вот переписывание метода visit ():

  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;      
  }

Это переписывание практически идентичнок вашему коду, но он явно показывает назначение, которое вы пытаетесь выполнить от Maybe до Maybe .Это рискованно.Действительно, мой компилятор Eclipse выдает ошибку в строке назначения.Вот фрагмент кода, который использует этот риск для хранения Integer внутри объекта Maybe :

  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
  }
2 голосов
/ 11 января 2010

Я не понимаю, почему javac не определил правильный тип,
но вы можете помочь компилятору, указав типы как в

public @Nonnull Maybe<Foo> visit() {
    return Maybe.<Foo, BarExtendsFoo>something(new BarExtendsFoo());
}
0 голосов
/ 30 ноября 2010

Два комментария:

а. Как вы упомянули в одном из ваших комментариев, параметр типа TG в сигнатуре что-то () вообще не нужен, так как нет ничего конкретного для подкласса TG, который вы делаете в методе.

б. Самым простым решением этого было бы помочь компилятору понять, какой тип вы используете, явно назначив вновь созданный объект переменной (что обычно является хорошей практикой в ​​любом случае). Теперь и для читателя, и для читателя стало понятнее, как вы хотите вызывать метод:

public @Nonnull Maybe<Foo> visit() {
    final Foo bar = new BarExtendsFoo();
    return Maybe.something(bar);
}
...