【问题标题】:Generic Enum Type for anything extended任何扩展的通用枚举类型
【发布时间】:2020-07-10 21:17:11
【问题描述】:

我喜欢做一个可以接受任何东西的通用枚举。

对于这个例子,我使用了 TaskStatus,但在未来,我更喜欢使用 Generic Enum,例如; StudentStatus,这个学生身份可以自己带一个id和描述,它会自动转换。此外,迭代每个对象并最终自动返回。我有机会吗?

 @Getter
 @AllArgsConstructor(access = AccessLevel.PRIVATE)
  public enum TaskStatusEnum{
    
        READY(1, "Ready"),
        ON_GOING (2,"On going");
        
        private final long id;
        private final String description;
        
        
        public static TaskStatusEnum get (long id)
        {
            for (TaskStatusEnum status : TaskStatusEnum.values()) {
                if (status.id == id) {
                    return id;
                }
            }
            return null;
        }

【问题讨论】:

  • “扩展”是什么意思。您的意思是在此处显示的两个枚举之外动态添加第三个或第四个枚举?还是您在定义另一个枚举时将一个枚举子类化?
  • 我喜欢创建新的枚举并为枚举命名,当我扩展通用枚举时,它必须自动填充
  • 我还是没跟上。你知道枚举基本上是一种自动实例化一些静态命名对象的便捷方式吗?
  • TaskStatus 枚举是否可以作为通用枚举的子类?
  • 没有你的枚举的子类化。查看我的答案。

标签: java spring spring-boot jpa enums


【解决方案1】:

我不确定你到底想要什么。您可以在枚举上使用接口,然后您可以将接口用作状态,而不必关心状态类到底是什么。

public interface Status<E extends Enum<E> & Status<E>> {

    public long getId();
    public String getDescription();

}

学生身份:

public enum StudentStatus implements Status<StudentStatus>{

    NEW(0, "new");

    ;

    private long id;
    private String description;

    private StudentStatus(long id, String description) {
        this.id=id;
        this.description = description;
    }

    @Override
    public long getId() {
        return id;
    }

    @Override
    public String getDescription() {
        return description;
    }

}

任务状态:

public enum TaskStatus implements Status<TaskStatus>{

    OPEN(0, "open");

    ;

    private long id;
    private String description;

    private TaskStatus(long id, String description) {
        this.id=id;
        this.description = description;
    }

    @Override
    public long getId() {
        return id;
    }

    @Override
    public String getDescription() {
        return description;
    }
}

通过id查找状态的通用方法

public abstract class StatusUtil {

public static <E extends Enum<E> & Status<E>> E get(Class<E> statusClass, long id) {
        return Arrays.asList((E[]) statusClass.getEnumConstants())
            .stream()
            .filter(item -> item.getId() == id)
            .findAny()
            .orElse(null);
    }
}

示例如何使用:

public class Test {

    public static void main(String... args) {
        StudentStatus studentStatus = StatusUtil.get(StudentStatus.class, 0);
        TaskStatus taskStatus = StatusUtil.get(TaskStatus.class, 0);
    
        List<Status> statusList = Arrays.asList(studentStatus, taskStatus);
        statusList.forEach(status -> System.out.println(status.getClass().getName()+"\t"+status.getId()+"\t"+status.getDescription()));
    }
}

如果你使用8以下的JAVA:

public interface Status<E extends Enum<E>> {

    public long getId();
    public String getDescription();

} 

statusUtil:

public abstract class StatusUtil {

    public static <E extends Enum<E>> E get(Class<E> statusClass, long id) {
    for(E item: (E[]) statusClass.getEnumConstants()) {
        if(item.getId() == id) {
            return item;
        }
    }
    return null;
}

} 测试:

    public static void main(String... args) {
    StudentStatus studentStatus = StatusUtil.get(StudentStatus.class, 0);
    TaskStatus taskStatus = StatusUtil.get(TaskStatus.class, 0);
    
    List<Status> statusList = Arrays.asList(studentStatus, taskStatus);
    for(Status status: statusList) {
        System.out.println(status.getClass().getName()+"\t"+status.getId()+"\t"+status.getDescription());
    }
}

当枚举具有相同的方法并且您需要通用接口时,您可以使用它

【讨论】:

  • 感谢您准确回答我的需要,但我需要在我的 foreach 示例中使用 get 方法进行映射,并为我使用的枚举命名方法; taskResponse.setTaskStatus(TaskStatus.get(taskList.getTaskStatus()).name());对于地图结构
【解决方案2】:

您的枚举实际上是 final(不允许子类)

显然你在问TaskStatus 枚举是否可以被子类化。例如,创建一个继承自 TaskStatus 的 StudentStatus。

➥ 不,Java 中的枚举不能被子类化。

您的枚举定义实际上是Enum 的子类。这发生在后台magically handled by the compiler。 继承到此为止。您的枚举定义实际上是final,不允许进一步的子类。

枚举定义可以实现interface。来自多个枚举定义的实例可以被视为同一个接口的所有对象。见Answer by Victor1125。

Java 中的枚举是一种自动实例化一个或多个名称对象的便捷方式,用于表示在编译时已知的一组有限值。当Java classloader 加载它们的定义类时,这些实例都会立即存在。这些对象保留在内存中。

您不能在运行时动态添加更多实例。枚举对象的整个域是在编译时定义的。 (例外:一些疯狂扭曲的反射/自省代码可能能够创建更多实例,但我不会去那里。)

如果您想要继承或动态创建实例,请不要使用枚举。 使用常规类和子类,收集到集合或列表中。 集合或列表可以用泛型标记 (&lt; … &gt;) 以允许其包含元素的超类。例如Set&lt; Animal &gt; 可以包含子类Dog、Cat 和Bird 的对象。

顺便说一句,您现在可以在 3 个位置定义枚举:它自己的类,嵌套在另一个类中,现在在 Java 16(Java 15 中预览)中,本地方法中。

提示:无需在枚举名称中加上“枚举”。努力为您的枚举类和枚举对象创造自然阅读的名称。他们碰巧是一个枚举的事实应该消失在背景中。例如:参见Month (Month.JANUARY) 和DayOfWeek (DayOfWeek.MONDAY)。

【讨论】:

  • 您好 Basil,代码似乎可以工作,但我不知道如何使用 mapsturct 转换该枚举。我正在编写的枚举正在工作 taskResponse.setTaskStatus(TaskStatus.get(taskList.getTaskStatus()).name());但我不知道如何处理扩展的
  • @John 你用你未定义的taskList 和无法解释的“扩展的”迷失了我。
  • 谢谢 Basil 我已经整理好了。我在解释基类。但是我无法处理空警告。我可以在下面的 StaticUtils 类上处理 null 吗
【解决方案3】:

如何处理 StatusUtil.class 上的空点

StatusUtil:

公共抽象类 StatusUtil {

 public static <E extends Enum<E>> E get(Class<E> statusClass, long id) {
    for(E item: (E[]) statusClass.getEnumConstants()) {
        if(item.getId() == id) {
            return item;
        }
    }
    return null;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-04
    • 1970-01-01
    相关资源
    最近更新 更多