[英]Can javac infer the right generics for using x.getClass() and x together?
我想要一個通用方法,它接受某種類型 T 的對象,以及一個表示該類型的類。 最終我打算用它來創建一個Map<Class<?>, Object>
,我知道每個類都將映射到一個完全屬於它自己類型的對象; 我知道我無法讓編譯器相信這一點,但我想盡可能多地為代碼保留編譯時通用安全性。 這是一個演示我遇到的問題的最小示例:
public class Example {
public static <T extends Number> void foo(Class<T> c, T x) {
;
}
public static void bar(int x) {
foo(Integer.class, x);
}
public static void baz(Number x) {
foo(x.getClass(), x);
}
}
我可以毫無問題地編寫foo
方法,並且它具有我想要的簽名,如果我在編譯時確切知道我有什么類型,我可以使用它,如bar
,但我不能在任何對象上使用它類型,正如我在baz
嘗試的那樣: baz
不編譯,引用:
Example.java:11: error: method foo in class Example cannot be applied to given types;
foo(x.getClass(), x);
^
required: Class<T>,T
found: Class<CAP#1>,Number
reason: inferred type does not conform to lower bound(s)
inferred: CAP#1
lower bound(s): Number
where T is a type-variable:
T extends Number declared in method <T>foo(Class<T>,T)
where CAP#1 is a fresh type-variable:
CAP#1 extends Number from capture of ? extends Number
我想我理解這里的問題: x.getClass()
返回Class<? extends Number>
Class<? extends Number>
,它建立<? extends Number>
<? extends Number>
as T
,但x
繼續具有類型Number
,要求T
為Number
,因此沖突。 當我寫這篇文章時,我希望編譯器知道x.getClass()
和x
確實共享完全相同的T
,但它不知道這一點是有道理的。
那么,我在這里做什么? 有沒有辦法可以寫出像foo
和baz
這樣的東西? 我應該放棄編譯時安全並在運行時進行一些強制轉換嗎? 有沒有更好的方法來達到我的最終目標Map<Class, Object>
?
實際的結果類型是
Class<? extends |X|>
Class<? extends |X|>
其中|X|
是對調用getClass
的表達式的靜態類型的擦除。
注意“靜態類型的擦除”部分。 這意味着,如果您聲明了一個類型變量T
,例如,作為<T extends Number>
和一個變量T x
,那么x.getClass()
的返回值不是Class<? extends T>
Class<? extends T>
,但Class<? extends Number>
Class<? extends Number>
。 這確實使得在沒有任何不安全強制轉換的情況下很難做你想做的事情(不可否認,這取決於你想要做什么)。
但是,您可以包含對其自身功能的不安全性。 例如,這有效:
public class test {
public static <T extends Number> void foo(Class<T> c, T x) {
;
}
@SuppressWarnings("unchecked")
public static <T> Class<? extends T> getClass2(T x) {
return((Class<? extends T>)x.getClass());
}
public static void bar(int x) {
foo(Integer.class, x);
}
public static void baz(Number x) {
foo(getClass2(x), x);
}
}
你不能這樣做嗎?
public static class Example {
public static <T extends Number> void foo(Class<? extends T> c, T x) {
;
}
public static void bar(int x) {
foo(Integer.class, x);
}
public static void baz(Number x) {
foo(x.getClass(), x);
}
}
如果你死心塌地將foo
簽名保持為foo(Class<T> c, T x)
, baz
將不得不改變如下:
@SuppressWarnings("unchecked")
public static <T extends Number> void baz(T x) {
foo((Class<T>)x.getClass(), x);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.