1. 概述

Java 5 引入了枚举(enum) 类型,用于替代整数枚举模式。虽然在技术上可行,但我们在枚举常量上的名称通常不适合出现在日志、数据库或面向客户的部分应用中。本教程将介绍如何在 Java 中实现枚举的 toString() 方法,以便提供备选或装饰性的名称。

2. 默认行为

所有枚举默认继承自 Enum 类,因此枚举的 toString() 行为也源自于此:

public String toString() {
    return name;
}

3. 在枚举类型上覆盖 toString() 方法

由于我们不能直接访问 Enum 类,我们可以在枚举类型声明中控制 toString() 行为的下一个位置:

enum FastFood {
    PIZZA,
    BURGER,
    TACO,
    CHICKEN,
    ;

    @Override
    public String toString() {
        // ...?
    }
}

toString() 方法内部,我们可以访问的变量只有 this.namethis.ordinal。默认行为是打印枚举常量名,而我们不希望打印序号。然而,我们可以将序号映射到装饰后的字符串:

@Override
public String toString() {
    switch (this.ordinal()) {
        case 0:
            return "Pizza Pie";
        case 1:
            return "Cheese Burger";
        case 2:
            return "Crunchy Taco";
        case 3:
            return "Fried Chicken";
        default:
            return null;
    }
}

虽然有效,但用 "0 = Pizza Pie" 来表示并不直观。因为 this 自身就是一个枚举,我们可以简化上述 switch 语句使其更清晰:

@Override
public String toString() {
    switch (this) {
        case PIZZA:
            return "Pizza Pie";
        case BURGER:
            return "Cheese Burger";
        case TACO:
            return "Crunchy Taco";
        case CHICKEN:
            return "Fried Chicken";
        default:
            return null;
    }
}

4. 在枚举常量上覆盖 toString() 方法

我们可以为每个枚举常量覆盖 Enum 类或枚举类型声明中定义的任何方法。由于我们知道 toString()Enum 类中已定义,所以我们可以跳过在枚举类型声明中实现它:

enum FastFood {
    PIZZA {
        @Override
        public String toString() {
            return "Pizza Pie";
        }
    },
    BURGER {
        @Override
        public String toString() {
            return "Cheese Burger";
        }
    },
    TACO {
        @Override
        public String toString() {
            return "Crunchy Taco";
        }
    },
    CHICKEN {
        @Override
        public String toString() {
            return "Fried Chicken";
        }
    }
}

5. 添加别名字段

另一种选择是在枚举类型声明中添加额外的字段,并在创建每个枚举常量时分配值:

enum FastFood {
    PIZZA("Pizza Pie"),
    BURGER("Cheese Burger"),
    TACO("Crunchy Taco"),
    CHICKEN("Fried Chicken"),
    ;

    private final String prettyName;

    FastFood(String prettyName) {
        this.prettyName = prettyName;
    }
}

然后,我们可以在枚举类型的 toString() 方法中直接使用这些值:

@Override
public String toString() {
    return prettyName;
}

6. 从装饰后的字符串创建枚举

如果我们花费这么多精力将枚举转换为装饰后的字符串,那么在相反的方向上构建相同功能也合乎逻辑。与其覆盖 Enum 类的 valueOf() 方法,该方法会比较提供的字符串与枚举常量名,不如我们创建自己的方法,以便根据需要选择不同的行为:

FastFood fromString(String prettyName) {
    for (FastFood f : values()) {
        if (f.prettyName.equals(prettyName)) {
            return f;
        }
    }
    return null;
}

7. 总结

在这篇文章中,我们学习了多种实现枚举 toString() 的方法。如往常一样,文章中使用的完整源代码可以在 GitHub 上找到。