如何获得在Java中实现特定接口的正确枚举?

如何获得在Java中实现特定接口的正确枚举?,java,enums,Java,Enums,我有以下界面: public interface Moon { // Enums can not extend any class in Java, // thus I am implementing an interface double getMass(); double getDiameter(); } 这是由我的枚举实现的(我省略了构造函数和方法实现) 和其他行星的类似枚举: public enum Mars implements Moon {

我有以下界面:

public interface Moon {
    // Enums can not extend any class in Java,
    // thus I am implementing an interface
    double getMass();
    double getDiameter();
}
这是由我的枚举实现的(我省略了构造函数和方法实现)

和其他行星的类似枚举:

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);
Moon something=.valueOf(moonName);

您可以使用行星名称到相关枚举类型的映射,并使用该映射执行查找

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

上面的代码将返回火星火卫一


编辑:关于添加非月球枚举的功能。可以封装贴图并强制使用适当的边界。例如,下面使用的方法:

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);
    }
}
类注册表{

私有最终地图如果你真的希望它是动态的,如果我不推荐的话,你可以使用反射、事件来实现。你也可以

  • ,对它们进行迭代,并检查它们是否有名为PHOBOS的实例
  • 一个缺点是,如果您将类
    Mars
    移动到另一个包中,它就会崩溃
  • ,保留名为
    Mars
    的一个,它实现了
    Moon
    并查找实例。这有点过分了

我怀疑您的设计中存在一个弱点,这导致您需要寻找复杂的方法来获取所需的枚举实例。当每个行星都是独特的卫星时,为它们分别设置枚举可能没有多大意义。最好重新考虑一下设计。例如:

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
,并将其卫星指定为enum属性,如下所示

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();
    }
}

老实说,通过反射获取所有实现类的想法简直是太可怕了。Stool,回答得很好!这看起来很好也很干净。但是,正如我所看到的,这个映射确保了映射中的类是枚举(
扩展了enum
),但它不限于实现
Moon
接口的类。因此,我可以在没有警告的情况下向该映射添加任何枚举。@matandked没错。您可以使用泛型方法扩展解决方案,使其具有适当的边界。我将进行编辑。@matandked检查编辑(当然还有最后的备注:-))@鲍恩:谢谢:-)我会纠正的-我不知道我是怎么想出来的:这是一个很好的建议。我们需要把所有的东西都投射到
对象上吗
/不可能使用
月亮
isntead吗?是的,我们可以。我编辑了答案来说明同样的问题。
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();
}
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();
    }
}
    // Outputs 22.2
    System.out.println("" + Planets.valueOf("MARS").getMoon("PHOBOS").getDiameter());