【问题标题】:Can I add a function to enums in Java?我可以向 Java 中的枚举添加函数吗?
【发布时间】:2011-01-28 06:18:15
【问题描述】:

我有一个枚举,看起来像

public enum Animal {
  ELEPHANT,
  GIRAFFE,
  TURTLE,
  SNAKE,
  FROG
}

我想做类似的事情

Animal frog = Animal.FROG;
Animal snake = Animal.SNAKE;

boolean isFrogAmphibian = frog.isAmphibian(); //true
boolean isSnakeAmphibian = snake.isAmphibian(); //false

boolean isFrogReptile = frog.isReptile(); //false
boolean isSnakeReptile = snake.isReptile(); //true

boolean isFrogMammal = frog.isMammal(); //false
boolean isSnakeMammal = snake.isMammal(); //false

出于教学目的,我简化了示例,但这对我的真实示例非常有用。我可以用 Java 做吗?

【问题讨论】:

    标签: java function enums


    【解决方案1】:

    是的,Enum 是 Java 中的一个类:

    public enum Animal 
    {
      ELEPHANT(true),
      GIRAFFE(true),
      TURTLE(false),
      SNAKE(false),
      FROG(false);
    
      private final boolean mammal; 
      private Animal(final boolean mammal) { this.mammal = mammal; }
      public boolean isMammal() { return this.mammal; }
    }
    

    但在你的情况下,对于一个真实的系统,我也会将其设为 Enum,因为有一组固定的动物类型。

    public enum Type
    {
      AMPHIBIAN,
      MAMMAL,
      REPTILE,
      BIRD
    }
    
    public enum Animal 
    {
      ELEPHANT(Type.MAMMAL),
      GIRAFFE(Type.MAMMAL),
      TURTLE(Type.REPTILE),
      SNAKE(Type.REPTILE),
      FROG(Type.AMPHIBIAN);
    
      private final Type type; 
      private Animal(final Type type) { this.type = type; }
      public boolean isMammal() { return this.type == Type.MAMMAL; }
      public boolean isAmphibian() { return this.type == Type.AMPHIBIAN; }
      public boolean isReptile() { return this.type == Type.REPTILE; }
      // etc...
    }
    

    还请注意,将任何实例变量设为final 也很重要。

    您可以在Java Language Specification 中找到有关它的更多详细信息。

    【讨论】:

    • 如果我想要不同的类别,比如哺乳动物、两栖动物、爬行动物怎么办?
    • 每个都需要多个布尔标志,或者您可以按照我在解决方案中的建议创建该类别和枚举。
    • 不是方法,构造函数你不应该能够在自身之外创建枚举的实例。将 CONSTRUCTOR 设为私有意味着只有其自身的静态实例才能创建实例。
    • 显式总比隐式好
    • 为什么将其实例变量声明为 final 很重要?
    【解决方案2】:

    除了使用上述向枚举类型添加字段的技术外,您还可以使用基于纯方法的方法和多态性。这更像是“OOP 风格”,但我不会说它一定更好。

    不幸的是,您可能(见下面的评论)需要定义一个接口:

    public interface AnimalTraits {
        default boolean isAmphibian()   { return false; };
        default boolean isReptile()     { return false; };
        default boolean isMammal()      { return false; };
    }
    

    但是你可以让他们在你的每个枚举元素中实现接口:

    public enum Animal implements AnimalTraits {
    
         ELEPHANT   { @Override public boolean isMammal()    { return true; } },
         GIRAFFE    { @Override public boolean isMammal()    { return true; } },
         TURTLE     { @Override public boolean isReptile()   { return true; } },
         SNAKE      { @Override public boolean isReptile()   { return true; } },
         FROG       { @Override public boolean isAmphibian() { return true; } }
    }
    

    请注意,我在界面中使用默认实现来减少您在枚举中所需的输入量。

    关于接口的必要性:我尝试将接口中的方法添加为枚举顶部的抽象方法,Eclipse 似乎允许它并坚持在枚举元素中实现,但后来未能正确编译。所以看起来没有接口应该是可能的,但可能还没有在编译器中实现。

    【讨论】:

    • 其实你不需要创建接口,也不需要Java8。看我的回答。
    【解决方案3】:

    我还有一个选择:

    public enum Animal {
        ELEPHANT {
            @Override
            boolean isMammal() {
                return true;
            };
            @Override
            boolean isReptile() {
                return false;
            }
        },
        SNAKE {
            @Override
            boolean isMammal() {
                return false;
            };
            @Override
            boolean isReptile() {
                return true;
            }
        };
    
        abstract boolean isMammal();
        abstract boolean isReptile();
    }
    

    不需要外部接口,我很确定(未测试)它也适用于 Java7。

    【讨论】:

    • 这是最完整的答案! +1
    【解决方案4】:

    是的,你可以。它看起来像这样:

    public enum Animal {
      ELEPHANT(false),
      GIRAFFE(false),
      TURTLE(false),
      SNAKE(false),
      FROG(true);
    
      private final boolean isAmphibian;
    
      Animal(boolean isAmphibian) {
        this.isAmphibian = isAmphibian;
      }
    
      public boolean isAmphibian() {
        return this.isAmphibian;
      }
    }
    

    那么你可以这样称呼它:

    Animal.ELEPHANT.isAmphibian()

    【讨论】:

    • 枚举的构造函数应该是私有的
    • 不是“应该是私有的”,而是必须是私有的。
    • 这很奇怪——java.sun.com/j2se/1.5.0/docs/guide/language/enums.html 的 Planet 示例没有在构造函数上使用 private 修饰符。你确定吗?
    • 不需要。它们隐含地已经是私有的。枚举无论如何都是不可实例化的。
    • 不,不是私人的。包私有。或者我相信...?
    猜你喜欢
    • 2015-11-29
    • 2015-03-24
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    • 2010-10-03
    • 2012-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多