[英]Nested Generics Inheritance
我有以下課程:
class Field<T> {
private final Class<T> type;
public Field(Class<T> type) {
this.type = type;
}
}
class Pick<V> {
private final V value;
private final Class<V> type;
public Pick(V value, Class<V> type) {
this.value = value;
this.type = type;
}
}
和問題所涉及的類:
class PickField<T> extends Field<Pick<T>> {
public PickField(Class<Pick<T>> type) {
super(type);
}
}
現在這似乎被編譯器接受了。 不幸的是,我不知道/理解如何創建一個新的PickField
實例,例如String
picks。
這當然 - 不起作用:
new PickField<String>(Pick.class)
這是不允許的(我想我理解為什么):
new PickField<String>(Pick<String>.class)
那怎么辦呢? 或者整個方法是否以某種方式“ 聞 ”?
我認為PickField
應僅使用Pick
實例進行參數化。
所以這樣做應該沒問題:
class PickField<T extends Pick<T>> extends Field<T> {
public PickField(Class<T> c) {
super(c);
}
}
然后,您可以使用以下方法實例化它:
PickField<SomeSpecificPick> instance = new PickField<>(SomeSpecificPick.class);
其中SomeSpecificPick
定義為:
public class SomeSpecificPick extends Pick<SomeSpecificPick> {
public SomeSpecificPick(SomeSpecificPick value, Class<SomeSpecificPick> type) {
super(value, type);
}
}
更多信息(與主題相關):
這里有各種各樣的問題。
首先,正如您所指出的,您無法在編譯時獲取參數化類的類,因為只為泛型類型編譯了一個類,而不是每個給定類型參數編譯一個類(例如, Pick<String>.class
成語不能編譯,並且實際上沒有意義)。
再次提到, 僅使用Pick.class
參數化PickField<String>
構造函數將不會再次編譯,因為簽名不匹配。
您可以使用運行時慣用法來推斷正確的Pick<T>
參數,但這會產生另一個問題:由於鍵入擦除 , T
的類型參數在運行時將是未知的。
因此,您可以通過顯式轉換來參數化構造函數調用,如下所示:
new PickField<String>(
(Class<Pick<String>>)new Pick<String>("", String.class).getClass()
);
...將使用“未經檢查的強制轉換”警告進行編譯( Type safety: Unchecked cast from Class<capture#1-of ? extends Pick> to Class<Pick<String>>
取消選中強制轉換Type safety: Unchecked cast from Class<capture#1-of ? extends Pick> to Class<Pick<String>>
)。
真正的問題可能是你為什么需要知道Pick
類中的type
值。
有一種方法,但並不是一個好方法。 你需要創建一個這樣的方法:
public static <I, O extends I> O toGeneric(I input) {
return (O) input;
}
然后,您創建對象:
new PickField<String>(toGeneric(Pick.class));
就像我說的,不是一個好方法,因為你基本上只是騙算編譯器,但它的工作原理。
為了將泛型信息作為參數傳遞, Class<T>
是不夠的。 你需要一些額外的力量來實現這一目標。 請參閱這篇文章 ,其中解釋了超類型令牌的含義。
簡而言之,如果您有以下課程:
public abstract class TypeToken<T> {
protected final Type type;
protected TypeToken() {
Type superClass = getClass().getGenericSuperclass();
this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public Type getType() {
return this.type;
}
}
您可以使用它來存儲泛型類型信息,例如Pick<String>.class
(這是非法的)。 訣竅是使用超類的泛型類型信息,可以通過Class.getGenericSuperclass()
和ParameterizedType.getActualTypeArguments()
方法訪問它們。
我稍微修改了Pick
, Field
和PickField
類,以便它們使用超類型令牌而不是Class<t>
。 請參閱修改后的代碼:
class Field<T> {
private final TypeToken<T> type;
public Field(TypeToken<T> type) {
this.type = type;
}
}
class Pick<V> {
private final V value;
private final TypeToken<V> type;
public Pick(V value, TypeToken<V> type) {
this.value = value;
this.type = type;
}
}
class PickField<T> extends Field<Pick<T>> {
public PickField(TypeToken<Pick<T>> type) {
super(type);
}
}
以下是一個示例用法:
TypeToken<Pick<String>> type = new TypeToken<Pick<String>>() {};
PickField<String> pickField = new PickField<>(type);
由於TypeToken
類是抽象的,因此需要對其進行子類化(這解釋了聲明結尾處的{}
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.