欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

[转载] Java中枚举类型的使用 - enum

程序员文章站 2022-04-28 10:28:34
本文对Java中的枚举类型(enum)作了比较详细的介绍, 并作了代码示例, 包括JVM在编译时添加的特性、向枚举类中添加方法、接口内部创建枚举、枚举类中使用枚举等方面. ......

目录

本文转载自博客 - java枚举类型, 博主对原文内容及结构作了一定的修改.

1 枚举类的编译特性

从jdk 5开始, java中多了一个关键字——enum: 可以将一组具有名称的值(包括string、integer等)的有限集合创建为一种新的类型, 而这些具名的值可以作为常规的程序组件使用.

这些具名的值称为枚举值, 这种新的类型称为枚举类型.

下面是一个简单的表示星期几的枚举:

public enum day {
    sunday, monday, tuesday, wednesday, thursday, friday, saturday
}

创建enum时, 编译器会自动为enum类添加一些特性, 比如:

a) 创建tostring()方法: 以便显示某个枚举实例的名字;

b) 创建name()方法: 获取枚举类型中某个实例的名称;

c) 创建ordinal()方法: 表示某个特定枚举常量的申明顺序, 从0开始;

d) 创建values()方法: 按照枚举常量的申明顺序产生这些常量构成的数组…...

关于这些特性, 编写测试方法如下:

public static void main(string[] args) {
    // 获取枚举类型的父类型
    system.out.println(day.class.getsuperclass());
    // 遍历枚举类型中的值
    for (day day : day.values()) {
        system.out.println(day.name() + ", ordinal: " + day.ordinal());
    }
}

程序的输出结果是:

class java.lang.enum   // 所有enum的父类都是它
sunday, ordinal: 0     // ordinal()方法从0开始计数
monday, ordinal: 1
tuesday, ordinal: 2
wednesday, ordinal: 3
thursday, ordinal: 4
friday, ordinal: 5
saturday, ordinal: 6

从输出结果可以看到: 枚举类型day的父类是java.lang.enum——我们的代码中并没有指明extends动作, 所以这是由编译器完成的.

由于枚举实例已经继承了java.lang.enum, 而java又不支持多继承, 所以enum不能再继承其他的类, 但是能实现接口.

==> 所以, enum只是看起来像一种新的数据类型, 除了上面讲到的这些特殊的编译行为, 并没有什么特殊的地方.

2 向枚举类中添加方法

除了不能继承一个enum外, 基本上可以把enum当作一个普通的类来处理, 也就是说可以向enum中添加方法, 比如返回其自身描述的方法, 还可以添加main方法.

下面是一个演示enum添加自定义方法和实现接口的示例:

(1) 定义一个对象描述信息的接口:

interface objectdescription {
    string todo();
}

(2) 创建枚举类:

 public enum signal implements objectdescription {
    red("红灯", "敢过去就是6分, 还要罚款哦"), 
    yellow("黄灯", "黄灯你也不敢过"), 
    green("绿灯", "绿灯也得小心过啊");

    private string name;
    private string description;

   /**
    * 构造方法, 对内部变量进行初始化
    */
    signal(string name, string description) {
        this.name = name;
        this.description = description;
    }

    private string getname() {
        return name;
    }

    private string getdescription() {
        return description;
    }

    @override
    public string todo() {
        return "signal类用于表示交通信号灯, [" + this + "] 表示 [" + this.getname() + "]";
    }

    public static void main(string[] args) {
        // 调用实现的接口中的方法
        for (signal signal : signal.values()) {
            system.out.println(signal.todo());
        }
        // 调用自定义的方法
        for (signal signal : signal.values()) {
            system.out.println(signal.getname() + ": " + signal.getdescription());
        }
    }
}

(3) 运行结果如下:

signal类用于表示交通信号灯, [red] 表示 [红灯]
signal类用于表示交通信号灯, [yellow] 表示 [黄灯]
signal类用于表示交通信号灯, [green] 表示 [绿灯]
红灯: 敢过去就是6分, 还要罚款哦
黄灯: 黄灯你也不敢过
绿灯: 绿灯也得小心过啊

使用注意事项:

a) 如果要自定义方法, 就必须在enum实例序列的最后添加一个分号, 同时java要求必须先定义enum实例, 否则编译时会报错.

b) enum的构造器只能是private, 它只能在enum内部被用来创建enum实例, 一旦enum定义结束, 编译器就不允许再使用其构造器来创建任何实例了.

3 接口内部创建枚举

无法使用继承限制了枚举的使用, 比如需要用enum表示食物, 但同时需要区分水果、点心等类型, 这个时候就没不够灵活了.

我们通过在一个接口内部创建实现该接口的枚举, 从而达到对元素进行分类组织的目的:

public interface food {
    /**
     * 开胃菜
     */
    enum appetizer implements food {
        salad, soup, spring_rolls;
    }
  
    /**
     * 主菜
     */
    enum maincourse implements food {
        rice, noodles, vindaloo, beef;
    }

    /**
     * 甜品
     */
    enum dessert implements food {
        tiramisu, ice_cream, biscuit, fruit;
    }
  
    /**
     * 咖啡
     */
    enum coffee implements food {
        black_coffee, decaf_coffee, latte;
    }
}

enum而言, 实现接口是使其子类化的唯一方法. 通过上面的形式, 成功地完成了对不同食物的分组, 并且它们都是food.

4 枚举类中使用枚举

下面是一个枚举的随机选择器, 是一个工具类:

public class enums {
    private static random rand = new random(47);

    public static <t extends enum<t>> t random(class<t> enumclazz) {
        return random(enumclazz.getenumconstants());
    }

    public static <t> t random(t[] values) {
        return values[rand.nextint(values.length)];
    }
}

结合工具类及上面food接口的内容, 下面通过枚举的枚举实现一个产生随机菜单的例子:

public enum course {
    appetizer(food.appetizer.class),
    maincourse(food.maincourse.class), 
    dessert(food.dessert.class), 
    coffee(food.coffee.class);
    
    private food[] values;

    course(class<? extends food> kind) {
        // 返回枚举中所有的元素, 及所有实例构成的数组, 如果kind不是枚举返回null
        values = kind.getenumconstants();
    }

    public food randomselection() {
        return enums.random(values);
    }

    public static void main(string[] args) {
        // 产生5份随机菜单
        for (int i = 0; i < 5; i++) {
            for (course c : course.values()) {
                food food = c.randomselection();
                system.out.println(food + "  ");
            }
            system.out.println("---------------");
        }
    }
}

5 扩展: 验证values()不是通过父类继承的

下面的代码用来验证values()方法是enum自身的, 而不是继承自父类java.lang.enum的:

public enum signal implements objectdescription {
    red("红灯", "敢过去就是6分, 还要罚款哦"), 
    yellow("黄灯", "黄灯你也不敢过"), 
    green("绿灯", "绿灯也得小心过啊");

    private string name;
    private string description;

    signal(string name, string description) {
        this.name = name;
        this.description = description;
    }

    private string getname() {
        return name;
    }

    private string getdescription() {
        return description;
    }

    @override
    public string todo() {
        return "signal类用于表示交通信号灯, [" + this + "] 表示 [" + this.getname() + "]";
    }

    public static void main(string[] args) {
        set<method> methodset = new hashset<method>();
        // 获取本类的所有方法
        method[] signalmethods = signal.class.getmethods();
        for (method m : signalmethods) {
            methodset.add(m);
        }
        // 获取父类中的方法
        method[] superclassmethods = signal.class.getsuperclass().getmethods();
        // 去除本类中继承的父类方法
        for (method m : superclassmethods) {
            methodset.remove(m);
        }
        // 遍历输出本类中独有的方法
        for(method m : methodset) {
            system.out.println(m);
        }
    }
}

结果如下, 其中各个字段的含义依次为访问权限 [是否静态] 返回值类型的全限定名称 方法的全限定名称:

public static com.healchow.signal com.healchow.signal.valueof(java.lang.string)
public static com.healchow.signal[] com.healchow.signal.values()
public static void com.healchow.signal.main(java.lang.string[])
public java.lang.string com.healchow.signal.todo()

版权声明

本文版权归原作者所有, 如有侵权, 请联系博主, 定当立即删除.

若要转载, 请在文章页面明显位置标明原始链接, 否则一切责任自负.