簡體   English   中英

不能將泛型Java類型的類分配給其類類型以泛型超級類型為上限的變量

[英]Class of a generic Java type cannot be assigned to a variable whose Class type is upper bounded by a generic super type

我使用FloatParameter 。在我的設計中,有一些簡單的類可以對值參數進行建模,例如FloatParameterEnumParameter<E> A具有這些類的通用泛型超類( GenericParameter<T> ),該超類實現參數名稱及其默認值。 子類實現特定於它們的其他屬性,例如FloatParameter范圍。

此外,無論參數的具體類型如何,我都希望使用它們的類型。 但是我仍然想以它們是GenericParameter<T>子類型的方式來綁定類型。 為了做到這一點,我創建了一個諸如process(Class<? extends GenericParameter<?>> paramType)

現在,問題在於EnumParameter.class 無法分配給Class<? extends GenericParameter<?>>類型的變量Class<? extends GenericParameter<?>> Class<? extends GenericParameter<?>>FloatParameter.class 可以

此外,我列出了這些類的代碼,以使其更加清晰和可重復:

public class GenericParameter<T> {
    protected String name;
    protected T defaultValue;
}

public class FloatGenericParameter extends GenericParameter<Float> {
    ...
}

public class TypedGenericParameter<T> extends GenericParameter<T> {
    ...
}

Class<? extends GenericParameter<?>> fgpc = FloatGenericParameter.class; // ok
Class<? extends GenericParameter<?>> tgpc = TypedGenericParameter.class; // error: incompatible types: Class<TypedGenericParameter> cannot be converted to Class<? extends GenericParameter<?>>
Class<? extends GenericParameter> tgpc2 = TypedGenericParameter.class; // warning: [rawtypes] found raw type: GenericParameter

最后,當使用非通用基類時,沒有問題:

public class Parameter {
    ....
}

public class FloatParameter extends Parameter {
    ...
}

public class TypedParameter<T> extends Parameter {
    ...
}

Class<? extends Parameter> fpc = FloatParameter.class; // ok
Class<? extends Parameter> tpc = TypedParameter.class; // ok

請,您有什么建議嗎?

我可以將process(Class<?> paramType)用作解決方法或進行強制轉換,但我想從編譯器的靜態類型檢查中受益。

編輯:

注冊要為每種參數類型生成GUI組件的工廠時,我想使用強制類型轉換。 代碼如下:

addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() { ... })

在這種情況下,編譯器將在編譯時檢查添加的參數類型。 代碼也將更加不言自明。

編輯2:

當前,我正在使用建議的方法為addParameterComponentFactory方法引入類型參數。 簽名如下所示:

public static <P extends GenericParameter<?>> addParameterComponentFactory(Class<P> clazz, ParameterComponentFactory pcf)

通過此定義,我可以指定TypedParameter.classEnumParameter.class也是一種類型參數),並且可以獲得靜態類型檢查。

讓我們從您的API的核心部分開始。 您有一個泛型Parameter<T>類型,該類型表示一些名為T的值的已命名參數。 您具有專門用於編輯或顯示特定類型參數的GUI組件,並且希望能夠注冊工廠來創建這些組件。

class Parameter<T> {
    String name;
    T defaultValue;
}

class ParameterComponent<P extends Parameter> {
    void setParameter(final P p) {}
}

interface ParameterComponentFactory<P extends Parameter> {
    ParameterComponent<P> newComponent();
}

class FloatParameter extends Parameter<Float> {}
class FloatParameterComponent extends ParameterComponent<FloatParameter> {}

class EnumParameter extends Parameter<Enum> {}
class EnumParameterComponent extends ParameterComponent<EnumParameter> {}

如果我對您的理解正確,那么您將難以確定如何聲明一種方法來靜態地強制某種Parameter類型與專用於該類型的GUI組件的工廠之間的關系。 例如,您希望能夠編寫以下代碼:

addComponentFactory(EnumParameter.class, EnumParameterComponent::new);    // OK
addComponentFactory(FloatParameter.class, FloatParameterComponent::new);  // OK
addComponentFactory(FloatParameter.class, EnumParameterComponent::new);   // ERROR!

問題與通用子類型的規則有關,您可以通過使用類型變量而不是嵌入式通配符來解決這些問題。 這應該為您提供所需的類型檢查,而不需要討厭的轉換:

static <P extends Parameter> void addComponentFactory(
    final Class<P> parameterType,
    final ParameterComponentFactory<? extends P> factory) { ... }

說明[1]

解釋引入新的類型P extends Parameter<?>Class<P>使用的P extends Parameter<?> Class<P>和直接聲明Class<? extends Parameter<?>> Class<? extends Parameter<?>>

這很復雜,請多多包涵。 讓我們談談通配符,原始類型和轉換。 考慮以下:

// Scenario 1(a)
GenericParameter raw = /* some value */;
GenericParameter<?> wc = raw;

// Scenario 1(b)
Class raw = GenericParameter.class; 
Class<?> wc = raw;

// Scenario 2
Class<GenericParameter> classOfRaw = GenericParameter.class; 
Class<GenericParameter<?>> classOfWC = classOfRaw;

場景1(a)和1(b)均出於相同的原因進行編譯:因為原始類型G可能未經檢查就轉換G<T_1, ..., T_n>形式的任何參數化類型。

方案2 無法編譯。 但為什么?

在方案2中,第二個分配中的任何一方都不是原始類型。 為了使分配有效 ,必須存在從右手類型到左手類型的身份轉換或擴展轉換 為了擴大引用類型的轉換,左手類型必須是右手類型的超類型。 當這些類型是通用類型時,將應用通用子類型化規則。 具體而言,左側的類型實參必須在右側包含類型實參。

Class<String>Class<? extends Object> Class<? extends Object>有效。 Class<String>Class<? extends Object>的泛型子類型Class<? extends Object> Class<? extends Object>因為? extends Object ? extends Object 包含 String 在方案2中, GenericParameter<?>第二個分配有效, GenericParameter<?>必須包含GenericParameter ,但不是。 T 不是 T<?>的子類型; TT<?> T<?> 因此,根據通用子類型化規則, Class<T>不是Class<T<?>>的子類型,並且該分配無效。

那為什么下面的工作呢?

public static <P extends GenericParameter<?>> addParameterComponentFactory(
    Class<P> clazz, 
    ParameterComponentFactory pcf)

addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() {})

在上面的調用中,對P類型推斷完全由Class<P>參數驅動。 您正在傳遞Class<EnumParameter> ,因此在這種情況下P綁定到原始類型EnumParameter 為了滿足條件P extends GenericParameter<?>要求, GenericParameter<?>必須可以從EnumParameter分配,並且可以通過未經檢查的轉換來分配,就像情況1(a)和1(b)一樣。

[1]這解釋是 明顯的抄襲 等優良堆棧溢出的答案的合並,主要由radiodef

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM