首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >强制实现枚举的Java接口-如何实现?

强制实现枚举的Java接口-如何实现?
EN

Stack Overflow用户
提问于 2018-05-19 18:41:23
回答 2查看 986关注 0票数 1

在这种情况下,我想使用一个名为Abstraction的对象实例,它是一个Java接口,如下所示:

代码语言:javascript
复制
public interface Abstraction {
   public enum Actions {
   }
}

这个想法是,任何实现抽象的类都必须实现枚举操作(我意识到这是行不通的)。

实现接口的类可能如下所示:

代码语言:javascript
复制
public class AbstractionA implements Abstraction {
   public enum Actions {
    f, c, r, a
   }
}

在另一个类中,我想创建一个抽象对象,如下所示:

代码语言:javascript
复制
Abstraction abs = new AbstractionA();

然后能够访问适用于所创建的抽象对象的枚举值,例如

代码语言:javascript
复制
abs.Action.r;

我意识到我的方法都是错误的,但看不到处理这种情况的合适方法。如果接口的不同实现具有我通常希望放在枚举中的不同选项子集,那么我如何实现这样的东西呢?也许我可以在接口中使用所有可能的选项实现枚举,然后以某种方式将接口的实现限制为使用这些枚举值的子集?

EDIT:另一个示例实现可能是

代码语言:javascript
复制
public class AbstractionB implements Abstraction {
   public enum Actions {
    f, c, b, r, a
   }
}

我想我已经想出了一个前进的方向:

代码语言:javascript
复制
public interface Abstraction {
   public enum Actions {
    f, c, b, r, s, a  
   }
   public Actions[] availableActions();
}

然后通过以下方式实现:

代码语言:javascript
复制
public class HunlAbstractionA implements Abstraction{
   @Override
   public Actions[] availableActions()
   {
    Actions[] actions = new Actions[] {Actions.f, Actions.c, Actions.r, Actions.a};
    return actions;
   }
}

这样,我就可以访问接口枚举中列出的所有可能的操作,并可以进行检查以确保要处理的操作是所创建类的availableActions之一。

EN

回答 2

Stack Overflow用户

发布于 2018-05-19 21:01:51

推荐

我推荐以下方法。

这种方法使用泛型和反射的组合来帮助明确地指示实现或选择适当的枚举的需要,它还允许您选择保留有关枚举类型的信息,同时隐藏有关特定抽象实现的所有其他信息。

代码语言:javascript
复制
/**
 * An abstraction with an implementation-defined enum
 * @param <E> your custom enum.
 */
interface Abstraction<E extends Enum> {

    //this gives you the enum constants as a list
    Class<E> getEnumType();

}

class AbstractionA implements Abstraction<AbstractionA.EnumA> {
    enum EnumA {
        FOO,
        BAR
    }

    @Override
    public Class<EnumA> getEnumType() {
        return EnumA.class;
    }
}

class AbstractionB implements Abstraction<AbstractionB.EnumB> {
    enum EnumB {
        FOO,
        BAR
    }

    @Override
    public Class<EnumB> getEnumType() {
        return EnumB.class;
    }
}

注意,不幸的是,由于type erasure,我们可以提供getEnumType()的默认实现。

使用示例

代码语言:javascript
复制
class Main {
    public static void main(String[] args) {
        Abstraction myAbstractionA = new AbstractionA();
        Abstraction<AbstractionB.EnumB> myAbstractionB = new AbstractionB();

        Class enumAType = myAbstractionA.getEnumType();
        Class<AbstractionB.EnumB> enumBType = myAbstractionB.getEnumType();
        Object[] enumsA = enumAType.getEnumConstants();
        AbstractionB.EnumB[] enumsB = enumBType.getEnumConstants();
        System.out.printf("Enums of the same order are still non-identical: %s", enumsA[0].equals(enumsB[0]));
        System.out.println();

        Enum enumA = ((Enum)enumsA[0]);
        Enum enumB = ((Enum)enumsB[1]);
        System.out.printf("We can get enum constants in order, and get the orderinal of the enum: A=%s, B=%s", enumA.ordinal(), enumB.ordinal());
        System.out.println();

        enumA = Enum.valueOf(enumAType, "FOO");
        enumB = Enum.valueOf(enumBType, "BAR");
        System.out.printf("We can get enum constants by name and get the name out of the enum: A=%s, B=%s", enumA.name(), enumB.name());
        System.out.println();
    }
}

替代方案

如果您可以使用抽象类而不是接口,那么您可能更喜欢类似于this related answer的解决方案。

编辑枚举:如果您希望跨操作共享一组通用常量,则可能应该对这些常量使用全局/共享枚举,并在自定义抽象中仅定义扩展本身。如果您将它们全部转换为枚举并根据需要使用.equals(),这在大多数情况下都应该有效。

背景

正如您所说的,您知道,不可能放置接口的成员对象(变量或类)。

然而,好消息是java实际上很好地支持了你想要的行为。

这里有3个与我的建议相关的关键特性:

枚举是对象

首先,java中的枚举是完全成熟的Object,它们都是对java.lang.Enum的扩展,并且都实现了.equals()

因此,您可以将不同的任何枚举类的值存储在java.lang.Enum类型的变量中,并将它们与.equals()进行比较。

而且,如果您想假装不同枚举类的值是相同的,因为它们共享相同的名称(或者是它们各自类中的第n个常量),那么您也可以这样做。

请注意,这也意味着自定义枚举可以像任何其他类一样包含复杂的数据和行为,而不仅仅是用作唯一标识符。

有关详细信息,请参阅Enum API documentation

Java反射

其次,Java具有广泛的反射支持。出于我们的目的,java.lang.Class有一个名为getEnumConstants()的方法,用于获取枚举常量(如果类不是枚举,则为null )。有关详细信息,请参阅Class API documentation

循环依赖

第三,至少在泛型方面,Java在循环依赖方面是允许的,因此您可以根据泛型的专门化来定义泛型接口。Java不会介意的。

票数 2
EN

Stack Overflow用户

发布于 2018-05-19 18:55:37

接口是您希望任何人提供该约定的实现的约定。在您的示例代码中,您没有一个方法,而是一个名为Action的枚举的定义。

通常,枚举是一组常量,因此我们不希望多个类为同一常量提供不同的实现。

因此,您可能需要重新考虑您的方法,并找出更好的方法。希望这能帮助你朝着正确的方向前进。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50424379

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档