簡體   English   中英

為什么不能將通配符與接收參數化參數的方法一起使用?

[英]Why can't I use wildcard with methods receiving a parameterized argument?

例如,我使用Measure.doubleValue(Unit<?> unit)方法,該方法返回以指定Unit表示的度量的double Measure.doubleValue(Unit<?> unit)值。 如果我將Unit<?>變量傳遞給它,則會收到仍然非常隱秘的錯誤消息:

The method doubleValue(Unit<capture#27-of ?>) in the type Measurable<capture#27-of ?> is not applicable for the arguments (Unit<capture#28-of ?>)

如果有人可以解釋#27-of ?內容,我將不勝感激#27-of ? (或任何其他數字)的意思,並且是否有一種優雅的方法可以消除這種情況。 到目前為止,我刪除了<?>並設置了調用方法@SuppressWarnings("unchecked") (因此我傳遞了一個未經檢查的Unit而不是Unit<?> ),並且一切都按預期進行,但是我對此感到很好奇,我覺得抑制警告不是一個好習慣(不是有點像空的捕獲塊嗎?)。

謝謝!

編輯:添加一些代碼。

(很抱歉,這很長,但是詳細說明了我遇到的問題。)

我正在使用JSR-275 0.9.4版 (最新)。

所以...如果我寫這個(非常愚蠢的例子):

Measure measure = Measure.valueOf("3 m");
measure = Measure.valueOf(measure.doubleValue(Unit.valueOf("km")), Unit.valueOf("km"));
System.out.println(measure);

它可以工作並打印“ 0.0030 km”。 但我得到警告“ 措施是一個原始類型引用泛型類型測量<Q>應進行參數設置。”在第一Measure發生和警告“ 類型安全:該方法的doubleValue(單位)所屬的原始類型可測量引用通用。類型Measurable <Q>應該在measure.doubleValue(Unit.valueOf("km")) ”上進行參數化

看到這些警告,我想我可以這樣調整(僅第一行):

Measure<Length> measure = Measure.valueOf("3 m");

然后我在分配的右側收到錯誤消息“ 類型不匹配:無法從Measure <capture#1-of?>轉換為Measure <Length> ”。 它(Eclipse)為我提供了將正確的部分轉換為(Measure&lt;Length>) 但是然后我在右側部分收到警告消息“ 類型安全:未經檢查的從Measure <capture#1-of轉換為Measure <Length> ”。 建議修復: @SuppressWarnings ,我希望避免使用(我想是出於偏執的原因)。

因此,我返回到Measure measure = Measure.valueOf("3 m"); 並嘗試將通配符賦予Measure ,顯然,此刻不知道“ 3 m”是什么意思。 它可以是Length ,也可以是MassTime 所以我得到:

Measure<?> measure = Measure.valueOf("3 m");

在這條線上沒有警告或錯誤; 太棒了。 但是,在第二行:

measure = Measure.valueOf(measure.doubleValue(Unit.valueOf("km")), Unit.valueOf("km"));

我收到doubleValue錯誤消息:“ 類型為Measurable <capture#3-of的方法doubleValue(Unit <capture#3-of?>)不適用於參數(Unit <capture#4-of? >) “。 建議將Unit.valueOf("km")(Unit<?>) 精細。 現在,我在完全相同的位置收到錯誤消息:“ 類型為Measurable <capture#3-of?>的方法doubleValue(Unit <capture#3-of?>)不適用於參數(Unit <capture#5 -of?>) ”。 請注意,數字已更改,因此這不是完全相同的參數,而是相似的原因。 然后,它執行完全相同的建議,因為它已經完成了,因此不會導致代碼中的任何更改。

這就是困擾我的原因。 使它工作的唯一方法似乎是@SuppressWarnings或忽略它們。 奇怪嗎?

度量值類看起來像這樣嗎?

class Measure<T> {

  double doubleValue(Unit<T> unit) {
    ...
  }

}

在這種情況下,引用類型為Measure<?>並不意味着您可以將任何類型的Unit傳遞給doubleValue方法。 相反,這意味着Measure實例具有未知的泛型類型,並且將Unit傳遞給其doubleValue方法並不安全,因為編譯器無法確保類型兼容。

通配符並不意味着“任何類型”; 它的意思是“未知類型”。


更新:

valueOf(CharSequence)返回未知類型的Measure Measure<?> 要將其安全地轉換為所需的Measure類型,必須使用Measure.asType()方法。 與由Unit.valueOf(CharSequence)方法創建的目標Unit Unit.valueOf(CharSequence)

Measure<?> unknownMeasure = valueOf("3 m");
Unit<?> unknownUnit = Unit.valueOf("km");
Measure<Length> length = unknownMeasure.asType(Length.class);
Unit<Length> kilometer = unknownUnit.asType(Length.class);
length.doubleValue(kilometer);

查看Measure類文檔中的示例。 它們將提供一些額外的深度。

Java泛型中的通配符表示“未知類型”。 在這里,將doubleValue()方法定義為接受Unit<something1> ,其中方法未指定something1 然后,您將一些未知的something2的值傳遞給調用方,它稱為Unit<something2> 編譯器錯誤消息表示沒有任何東西可以保證something1something2指定相同的內容。

嘗試這個:

<T> double doubleValue(Unit<T> unit)
{
    ...
}

這意味着doubleValue() 不在乎 T是什么。

為了擴展其他(出色的)答案,但是要具體一些JSR-275(我現在正在將其用於項目)。

這一點很有趣

建議修復:@SuppressWarnings,我希望避免使用(我想是出於偏執的原因)。

您是對偏執的想法是正確的,但是請考慮一下:您要告訴Measure類解析任意String ,並返回任何類型的Measure 顯然,在這種情況下,您可能會或可能不會獲得Measure<Length> (可能會傳遞“ 3 kg”),因此,留給庫的唯一選擇是返回Measure<?> 如果您想要一個Measure<Length> ,那么您必須以某種方式將其強制為-可能無法保證在編譯時是安全的。

在這種情況下,我認為@SuppressWarnings是完全可以接受的, 假設您知道字符串將始終是有效長度。 如果不是這樣,您將不可避免的ClassCastException推遲到以后,這很糟糕。

但是 ,更好的(呼啦!)JSR-275確實為您提供了解決方法,將錯誤處理推到了正確的位置(在獲得Measure ,而不是在使用它后的某個時候)。 嘗試

Measure<Length> = Measure.valueOf("3 m").asType(Length.class);

asType返回相應的Measure通用類型,或者如果解析的單元的尺寸不是length,則失敗,但異常-這幾乎可以肯定是您想要的,對吧?

我認為這可以解決您的問題。

我無法重現您的問題,即以下代碼可以正常編譯(至少使用eclipse):

static double doubleValue(Unit<?> unit) {
    return 0;
}

static void bla(Unit<?> u) {
    doubleValue(u);
}

public static void main(String[] args) {
    doubleValue(new Unit<String>());
}

暫無
暫無

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

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