[英]Java Generics: Who is right, javac or Eclipse compile?
調用此方法:
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
javac和Eclipse之間顯然存在一些差異。 但是,這里的要點是javac在發出錯誤時是正確的。 最終,您的代碼將Maybe <BarExtendsFoo>轉換為具有風險的Maybe <Foo>。
這是對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 <BarExtendsFoo>到Maybe <Foo>的分配。 這是有風險的。 確實,我的Eclipse編譯器在分配行上發出錯誤。 這是一段利用這種風險將整數存儲在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
}
我不明白為什么javac沒有推斷出正確的類型,
但是您可以通過提供如下所示的類型來幫助編譯器
public @Nonnull Maybe<Foo> visit() {
return Maybe.<Foo, BarExtendsFoo>something(new BarExtendsFoo());
}
兩條評論:
一種。 正如您在評論中提到的那樣,根本沒有必要在something()簽名中使用TG類型參數,因為在該方法中對子類TG沒有特定的定義。
灣 最簡單的解決方案是通過將新創建的對象顯式分配給變量來幫助編譯器了解您正在使用的類型(無論如何通常都是很好的做法)。 現在,對於編譯器和普通讀者來說,您如何調用該方法都更加清楚:
public @Nonnull Maybe<Foo> visit() {
final Foo bar = new BarExtendsFoo();
return Maybe.something(bar);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.