簡體   English   中英

在Java中鍵入范圍有限的變量

[英]Type variables with limited scope in Java

我想知道是否有可能在Java的方法范圍內引入類型變量。 也就是說,限制它們在方法體內的范圍。

然而,不是試圖在抽象中描述問題,而是讓我用我的具體問題來說明。 我有幾個類看起來像這樣:

public class Settings {
    public static abstract class Setting<T> {
        public T value;
        public abstract T fallbackvalue();
    }

    private final List<Setting<?>> settings;
}

我現在想在Settings編寫一個函數,用於將所有設置的值設置為抽象方法提供的回退值。 我的第一個想法是這樣做:

public void reset() {
    for(Setting<?> setting : settings)
        setting.value = setting.fallbackvalue();
}

然而,在第二個想法中,為什么這不起作用是相當明顯的; set.value的<?>捕獲與setting.fallbackvalue()捕獲不同。 因此,我需要一些方法來統一捕獲。 可能像這樣解決它:

private static <T> void reset1(Setting<T> s) {
    s.value = setting.fallbackvalue();
}

public void reset() {
    for(Setting<?> setting : settings)
        reset1(setting);
}

reset1的顯式類型變量<T>可以方便地統一捕獲,但顯然世界上最丑的東西是引入這個函數,污染命名空間,使屏幕變得雜亂,使代碼只是為了滿足類型系統而不易讀取。

我無法在reset體內做到這一點嗎? 我想做的只是這樣的事情:

public void reset() {
    for(Setting<?> setting : settings) {
        <T> {
            Setting<T> foo = setting;
            foo.value = foo.fallbackvalue();
        }
    }
}

它不是世界上最漂亮的東西,但至少在我看來,它比上面的變體要小得多。 唉,這是不可能的; 但那有什么可能呢?

在不改變代碼的其他方面的情況下,沒有辦法做你要求的。 但是(為了解決您的特定問題),您可以在內部Setting類中編寫一個reset方法:

public void reset() {
    value = fallbackvalue();
}

那么你的循環(在Settings類的reset方法中)就是:

for (Setting<?> setting : settings)
    setting.reset();

沒有...

雖然通配符捕獲確實引入了新類型變量,但它們僅適用於編譯器; 程序員無法直接訪問它們。

目前,只有類/方法可以引入類型變量。 因此,將帶有通配符的表達式類型轉換為不帶通配符的類型的唯一方法是通過方法(或帶有鑽石推理的構造函數new Foo<>(setting)傳遞表達式,這基本上是相同的機制)

你的reset1是普遍接受的做法。 它被稱為“捕獲助手”,並且是泛型中經常被引用的模式。 它通常出現在以下情況中:

public void swap(List<?> list, int i, int j) { // swap elements i and j of the list
    // how to write?
}

在這種情況下,您需要從參數化類型中獲取某些內容,並將某些內容放回該類型中。 通配符只是不允許你這樣做。 這就像你的情況一樣,因為你也得到一些東西並放入一些內容。我們知道類型必須相同,但通配符太弱而無法強制執行。 只有顯式類型變量才允許我們這樣做:

public <T> void swap(List<T> list, int i, int j) {
    T tmp = list.get(i);
    list.set(i, list.get(j));
    list.set(j, tmp);
}

但是,我們不希望這個無關的<T>僅在參數列表中的一個位置使用。 對外界來說, swap(List<?> list, int i, int j)應該可以正常工作。 我們需要使用這個<T>類型參數是一個沒有人需要知道的實現細節。 因此,要隱藏它,我們使用帶通配符的函數包裝泛型函數:

private <T> void swap_private(List<T> list, int i, int j) { ... }
public void swap(List<?> list, int i, int j) {
    swap_private(list, i, j);
}

這似乎是浪費,但事實就是如此。

鑒於你的情況和這個情況之間的類似情況,以及捕獲助手是這種情況下的規范解決方案這一事實,我可以自信地告訴你,不,沒有更好的方法來做到這一點。

暫無
暫無

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

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