簡體   English   中英

如何從通用枚舉類型檢索常量的接口?

[英]How do I retrieve the interface of the constants from a generic enum type?

我為一個必須處理通用枚舉的類指定一個方法的參數(我的意思是,該類可能是庫的一部分,並且用戶將為該類方法提供用戶定義的枚舉,其特定類型對於正在設計的類是未知的-我們將此類稱為“庫類”)。

我想在語法上盡可能地限制該參數類型,以便只允許使用正確的類型。

我的要求是,該類型必須是實現特定接口EnumKind的枚舉:

public interface EnumKind {

    String getText();

}

到目前為止,我已經能夠編寫這種類型的代碼:

Class<? extends Enum<? extends EnumKind>> t;

有了該聲明,並具有以下內容:

public enum MyEnumKind implements EnumKind {

    // ...

    public String getText() {
        // TODO Auto-generated method stub
        return null;
    }

}

public class MyClassKind implements EnumKind {

    @Override
    public String getText() {
        // TODO Auto-generated method stub
        return null;
    }

}

public enum MyEnum {

}

只有t = MyEnumKind.class是正確的,其他分配(例如t = MyClassKind.classt = MyClassKind.class編譯器拒絕,這是我想要的行為。

現在,在我的方法主體中,我可以成功執行以下操作:

Enum<? extends EnumKind>[] tt = t.getEnumConstants();

但是我還沒有找到一種直接檢索EnumKind的方法來訪問每個枚舉常量getText()方法。

我如何在沒有顯式轉換的情況下獲取EnumKind元素數組? 該類型聲明是我能寫的最好的,還是可以改進它?
如果無法避免顯式強制轉換,那么我可以100%安全地聲明類型聲明將避免引發任何ClassCastException (或任何類似異常)的可能性嗎?


編輯


我將進一步說明,因為我遇到了另一個障礙。

EnumKind接口要求枚舉將字符串與每個枚舉常量關聯,即:

public enum MyEnumKind implements EnumKind {

    A("#A#"),
    B("#B#"),
    C("#C#");

    private String text;

    private Token(String text) {
        this.text = text;
    }

    @Override
    public String getText() {
        return text;
    }

}

接下來,我想檢索對應於特定字符串的枚舉常量,例如

? enumValue = getValueFor("#A#");

enumValue (它的類型應該是什么?)在這里應該表示MyEnumKind.A ,並且不需要知道實際值,因為enumValue將傳遞給另一個方法。

我已經像這樣設計了我的圖書館類(在@JoopEggen回答之后):

public class EnumManager<T extends Enum<?> & EnumKind> {

    private Class<T> en;

    public EnumManager(Class<T> en) {
        this.en = en;
    }

   protected ? getValueFor(String s) {
        for(EnumKind ek : en.getEnumConstants()) {
            if(s.equals(ek.getText())) {
                // I found the enum constant I need... and now?
                return ? ;
            }
        }

    }

    //...

我應該如何完成該代碼?

是的,這是安全的,因為Number[]Integer[]的超類(與List<Number> 並非 List<Integer>的超類相反)。

因此,如果所宣稱的組件類型tt (聲明的類型的元件中的tt )實現EnumKind ,這種元件的陣列延伸EnumKind[]因此,這是安全的:

EnumKind[] tt = (EnumKind[]) t.getEnumConstants(); // Casting to superclass: OK

您不會收到任何警告,因為這是安全的,並且永遠不會收到ClassCastException

要使用.getText T也必須“擴展” EnumKind。 枚舉包裝器不提供此功能。

public static class MyC<T extends Enum<?> & EnumKind> {
    public void f(T t) {
        System.out.println("-> " + t.getText());
    }
}

在上方可以看到extends CLASS & INTERFACE 額外的限制必須是接口。


問題編輯后:

protected T getValueFor(String s) {
    for (T t : en.getEnumConstants()) {
        if (s.equals(ek.getText())) {
            return t;
        }
    }
}

使用靜態HashMap可能更好。

恐怕整個代碼可能會過度設計。 遵循帶有太多工件的簡單設計會更好。

您想要類似AbstractEnum的東西,

public enum EnumABC {
    A("a"), B("b"), C("c");

    private static final Map<String, EnumABC> textToEnum = new HashMap<>();
    static {
        for (EnumABC value : values()) {
            EnumABC oldValue = textToEnum.put(value.text, value);
            if (oldValue != null) {
                throw new IllegalArgumentException(
                        String.format("Enum %s: same value %s for %s and %s",
                                value.getClass().getName(),
                                value.text,
                                oldValue,
                                value));
            }
        }
    }

    public static EnumABC fromText(String text) {
        EnumABC value = textToEnum.get(text);
        return value;
    }

    private final String text;

    private EnumABC(String text) {
        this.text = text;
    }
}

祝好運。

更簡單:

@Override
public String getText() {
    String s = toString();
    return "#" + s.replace('_', ' ') + "#";
}

通用方法如何:

static <T extends Enum<T> & EnumKind> T helper(Class<T> t, String s) {
    EnumKind[] tt = t.getEnumConstants();
    // do what you need to do here
}

暫無
暫無

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

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