簡體   English   中英

如何獲得在Java中實現特定接口的正確枚舉?

[英]How can I get the proper enum that implements a particular interface in Java?

我有以下界面:

public interface Moon {
    // Enums can not extend any class in Java,
    // thus I am implementing an interface
    double getMass();
    double getDiameter();
}

這是由我的枚舉實現的(我省略了構造函數和方法實現)

public enum Saturn implements Moon {
    ATLAS(30.2, 6.6),
    PAN(28.2, 4.95);

    private double Diameter;
    private double Mass;

    // constructor and methods implementation
}

和其他行星類似的枚舉:

public enum Mars implements Moon {
    PHOBOS(22.2, 1.08),
    DEIMOS(12.6, 2);

    private double Diameter;
    private double Mass;

    // constructor and methods implementation
}

有兩個字符串:

String planetName = "Mars";
String moonName = "PHOBOS";

我怎樣才能以聰明的方式獲得特定的枚舉?

在只有一個枚舉類的情況下,它是valueOf方法的簡單使用,但是如何檢查實現特定接口的所有枚舉?

Moon something = <??planetName??>.valueOf(moonName);

您可以使用行星名稱到相關枚舉類型的映射,並使用它來執行查找。

例如,使用地圖(肯定有替代方法):

Map<String, Class<? extends Enum>> planetMoonTypes = new HashMap<>();

planetMoonTypes.put("Saturn", Saturn.class);
planetMoonTypes.put("Mars", Mars.class);

使用這樣的映射,您可以使用以下命令查找"PHOBOS"值:

Moon phobos = (Moon) Enum.valueOf(planetMoonTypes.get("Mars"), "PHOBOS");

以上將返回Mars.PHOBOS


編輯:關於添加非月亮枚舉的能力。 您可以封裝地圖並強制使用適當的邊界。 例如,以下使用方法:

class MoonRegistry {

    private final Map<String, Class<? extends Enum>> 
              planetMoonTypes = new HashMap<>();

    {
        this.registerEnum("Saturn", Saturn.class);
        this.registerEnum("Mars", Mars.class);
    }

    public <T extends Enum<T> & Moon> void registerEnum(
            String planetName, Class<T> cls) {
        this.planetMoonTypes.put(planetName, cls);
    }

    public Moon findByPlanetAndName(String planet, String name) {
        return (Moon) Enum.valueOf(this.planetMoonTypes.get(planet), name);
    }
}

同樣,此解決方案不能完全類型安全,因為有多個枚舉子類型(如您所見,原始Enum類型是實例字段的類型)。 但是如果這是正確封裝的並且您的代碼在此類之外不使用原始類型,則可以確保僅添加實現Moon枚舉類型。

如果你真的希望它是動態的,你可以使用Reflection,事件,如果我不推薦它。 你可以

我懷疑你的設計有一個弱點,導致你尋找復雜的方法來獲得你需要的枚舉實例。 每個行星都有一個單獨的枚舉,當它們都是獨特的衛星時,可能沒有多大意義。 最好重新考慮一下設計。 就像是:

interface Body {
    double getMass();
    double getDiameter();
}

enum Planet implements Body {
    MERCURY, VENUS...
}

enum Moon implements Body {
    ATLAS, PHOBOS, DEIMOS...

    public Planet getPlanet();
}

這樣就很容易通過名字獲得行星或衛星。 或者通過以下方式獲取行星的所有衛星:

Arrays.stream(Moon.values())
    .filter(m -> m.getPlanet().equals(this))
    ...

如果您的所有枚舉都在同一個包中,那么此解決方案可以正常工作。

String planetName = "Mars";
String moonName = "PHOBOS";

try {
    Moon moons[] = (Moon[]) Class.forName("your_package_name" + planetName).getEnumConstants();

    // The following line is not really needed, but I've added it as an 
    // illustration as to what you could do with the moons[]
    Moon planet = Arrays.stream(moons).filter(i -> i.toString().equals(moonName))
                          .findFirst().orElse(null);

} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

考慮使用額外的enum Plantes ,將其衛星分配為這樣的枚舉屬性

public enum Planets {
    MARS(Mars.values()), SATURN(Saturn.values());

    private final Enum<?>[] Moons;

    private Planets(final Enum<?>[] Moons) {
        this.Moons = Moons;
    }

    public Moon getMoon(final String moon) {
        return (Moon) Arrays
                .stream(this.Moons)
                .filter(e -> e.name().equals(moon))
                .findFirst()
                .get();
    }
}

它從已定義的枚舉中獲取月亮並將其分配給每個行星的枚舉。 還有一個getMoon() (函數valueOf()已被enum本身使用),它搜索月亮。

你可以像這樣使用它:

    // Outputs 22.2
    System.out.println("" + Planets.valueOf("MARS").getMoon("PHOBOS").getDiameter());

暫無
暫無

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

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