枚举类需要注意的点

文章目录

  • 1. 枚举类
    • 1.1. 枚举类和普通类的区别
    • 1.2. 枚举类中的方法
    • 1.3. 枚举类实现接口
    • 1.4. 包含抽象方法的枚举类

1. 枚举类

枚举类是一种特殊的类:

  • 可以有自己的成员变量、方法
  • 可以实现一个或者多个接口
  • 可以定义自己的构造器

1.1. 枚举类和普通类的区别

  1. 枚举类可以实现一个或多个接口,使用 enum 定义的枚举类默认继承了 java.lang.Enum 类,而不是 Object 类,因此枚举类不能显示继承其他父类
    其中 java.lang.Enum 类实现了 java.io.Serializable 和 java.lang.Comparable 两个接口
  2. 使用 enum 定义非抽象的枚举类默认会使用 final 修饰,因此枚举类不能派生子类。
    对于一个抽象的枚举类而言,只要它包含了抽象方法,那么它就是抽象枚举类,系统会默认使用 abstract 修饰枚举类,而不是使用 final 修饰。
  3. 枚举类的构造方法只能使用 private 访问控制符修饰,如果省略了构造方法的访问控制符,则默认使用 private 修饰。
  4. 枚举类的所有枚举值(实例)必须在枚举类的第一行显式列出,否则这个枚举类永远都不会产生实例。
    所有的枚举值之间使用逗号(,)分开,枚举值列举结束后以分号(;)结束。
    列出这些实例时,系统会自动添加 public static final 修饰,无需显示的添加。

1.2. 枚举类中的方法

  • 枚举类默认有一个 values() 方法,以数组的形式返回该枚举的所有枚举值
  • 枚举类默认有一个 valueOf(String name) 方法,将普通的字符串转换为枚举实例,该字符串必须与枚举值名称相同

由于所有的枚举类默认继承了 java.lang.Enum 类,因此可以使用该类中的所有方法。

方法 描述
ordinal() 返回枚举值在枚举类中的索引值,就是枚举值在枚举类中声明的位置,从0开始
name() 返回枚举实例的名称,即定义枚举类时列出的所有枚举值之一
toString() 返回枚举实例的名称,与name()方法相同,建议使用该方法
compareTo(E) 用于与相同类型的枚举实例比较顺序。如果该枚举实例位于指定枚举实例之后,则返回正数;如果该枚举实例位于指定枚举实例之前,则返回负数;否则返回0
valueOf(Class enumType, String name) 静态方法,用于返回指定枚举类中指定名称的枚举值。名称必须与在枚举类中声明枚举值时所有的标识符完全匹配

枚举类的实例只能是枚举值,而不是随意通过 new 来创建的枚举类对象。

枚举类通常应该设计成不可变的类,也就是说,它的成员变量值不应该允许改变,因此建议将枚举类的成员变量使用 private final 修饰
如果将所有成员变量都使用 final 来修饰,所以必须在构造方法中为这些成员变量指定初始值(或者在定义时显示指定默认值,或者在初始块中指定),因此应该为枚举类显示定义带参数的构造方法。

一旦为枚举类显示定义了带参的构造方法,列出枚举值时就必须对应的传入参数。
在枚举类中列出枚举值时,实际上就是调用构造方法创建枚举类对象,只是这里无需使用 new 关键字,也无需显示调用构造器。

public enum Gender {
     
    MALE("男"), FEMALE("女");
    //等同于如下两句,但是不可以使用如下两句进行声明
    //private static final Gerder FEMALE = new Gender("女");
    //private static final Gerder MALE = new Gender("男");

    private final String name;

    Gender(String name) {
     
        this.name = name;
    }

    public String getName() {
     
        return name;
    }
}

1.3. 枚举类实现接口

枚举类实现一个或多个接口时和普通类实现接口完全一样。

public interface GenderDesc {
     
    void desc();
}

// 枚举类实现接口,并且重写接口中的方法
public enum Gender implements GenderDesc{
     
    MALE("男"), FEMALE("女");

    private final String name;

    Gender(String name) {
     
        this.name = name;
    }

    public String getName() {
     
        return name;
    }

    @Override
    public void desc() {
     
        System.out.println("haha");
    }
}

public class GenderTest {
     
    public static void main(String[] args) {
     
        Gender male = Gender.MALE;
        male.desc(); //haha
        Gender female = Gender.FEMALE;
        female.desc(); //haha
    }
}

如上所述,如果让枚举类来实现接口中的方法,则每个枚举值在调用接口中的方法时都有相同的行为方式。如果需要每个枚举值在调用方法时呈现出不同的行为方式,则可以让每个枚举值分别来实现该方法,每个枚举值有不同的实现,从而让不同的枚举值有不同的行为方式。

// 枚举值重写接口中方法,从而实现每个枚举值调用该方法有不同的实现
public enum Gender implements GenderDesc{
     
    MALE("男") {
     
        @Override
        public void desc() {
     
            System.out.println("male");
        }
    }, FEMALE("女") {
     
        @Override
        public void desc() {
     
            System.out.println("female");
        }
    };

    private final String name;

    Gender(String name) {
     
        this.name = name;
    }

    public String getName() {
     
        return name;
    }
}

public class GenderTest {
     
    public static void main(String[] args) {
     
        Gender male = Gender.MALE;
        male.desc(); //male
        Gender female = Gender.FEMALE;
        female.desc(); //female
    }
}

在这种情况下,当创建FEMALE、MALE枚举值时,并不是直接创建了Gender枚举类的实例,而是相当于创建Gender匿名子类的实例。
编译上面的程序,可以看到生成了Gender.class、Gender$1.class、Gender$2.class三个文件,从而证明FEMALE、MALE实际上是Gender匿名子类的实例,而不是Gender的实例。

1.4. 包含抽象方法的枚举类

定义一个Operation枚举类,该枚举类有四个枚举值,PLUS,MINUS,TIMES,DIVIDE分别代表加减乘除,该枚举类需要定义一个eval方法来完成计算。

从枚举类实现接口来看,需要让枚举值对eval方法有不同的实现,因此可以考虑为Operation枚举类来定义一个eval抽象方法,然后让枚举值进行不同的实现。

public enum Operation {
     
    PLUS {
     
        @Override
        public double evel(double x, double y) {
     
            return x + y;
        }
    }, MINUS {
     
        @Override
        public double evel(double x, double y) {
     
            return x - y;
        }
    }, TIMES {
     
        @Override
        public double evel(double x, double y) {
     
            return x * y;
        }
    }, DIVIDE {
     
        @Override
        public double evel(double x, double y) {
     
            return x / y;
        }
    };

    //为枚举类定义抽象方法,该方法由不同的实例(枚举值)进行实现
    public abstract double evel(double x, double y);
}

枚举类中定义抽象方法时,不能使用 abstract 关键字将枚举类定义成抽象枚举类(因为系统会自动给枚举类加上abstract关键字)。但是因为枚举类需要显示创建枚举值,而不是作为父类,所以定义每个枚举值时必须实现枚举类中的抽象方法,否则编译将会出错。

你可能感兴趣的:(Java)