Java在1.5新增了枚举类型,说白了它就是一种特殊的Class;只是它不可以任意的去new实例对象,它的实例对象在定义enum时,就需要定义好了,这样也就限制了这个类的范围;比较常用的就是用来替代 public static final声明的静态常量。
一、定义枚举
(一)常量
使用IDEA的new可以直接创建一个enum出来;比如我们要定义动物园中一些动物常量,那就可以使用枚举来完成。
public enum Zoo {
TIGER, PANDA, CAT, ELEPHANT, ALPACA
}
简单的使用一下这些枚举:
public class TestEnum {
public static void main(String[] args) {
// 可以直接输出
System.out.println(Zoo.CAT);
System.out.println(Zoo.PANDA);
}
}
(二)原理
这些常量就可以被打印出来了, 接下来我们通过反编译来看一看Java是怎么实现的枚举:
先编译TestEnum.java:javac .\TestEnum.java 生成TestEnum.class和Zoo.class这两个文件;
然后反编译Zoo.class:javap .\Zoo.class,生成如下代码:
public final class Zoo extends java.lang.Enum<Zoo> {
public static final Zoo TIGER;
public static final Zoo PANDA;
public static final Zoo CAT;
public static final Zoo ELEPHANT;
public static final Zoo ALPACA;
public static Zoo[] values();
public static Zoo valueOf(java.lang.String);
static {};
}
通过反编译Java帮我们生成了一个继承 java.lang.Enum的final型的Class,以及之前定义的实例对象,通过代码可以看出来我们定义的枚举对象,实际上就是public static final静态常量;其实Java还会强制把枚举的构造方法默认成私有的,综上,枚举实际上就是一个特殊的常量类,这个类不可以被使用者去new新的实例。
(三)成员变量、自定义方法
我们在使用静态常量的时候往往需要使用其数值,其实枚举实例也可以有属于它自己的值,我们可以像定义普通类一样去给枚举加上成员变量和方法,但要注意的是它的构造方法必须是私有的,以防止被外部调用。
public enum Zoo {
// 注意:实例后的 ‘;' 如果不加这个;号,编译器会报错;
// 同时也要保证实例定义在枚举的最上方,否则也会报错。
TIGER(1, "凶猛"), PANDA(2, "国宝"), CAT(3, "可爱"),
ELEPHANT(4, "庞大"), ALPACA(5, "神兽");
private int num;
private String desc;
private Zoo(int num, String desc) {
this.num = num;
this.desc = desc;
}
// 普通方法
public static String getDesc(int num) {
// 枚举的values方法,可以返回一个枚举实例数组
Zoo[] values = Zoo.values();
for (Zoo value : values) {
if(value.getNum() == num) {
return value.getDesc();
}
}
return null;
}
// 枚举中也可以重写父类方法
@Override
public String toString() {
return "Zoo{" +
"num=" + num +
", desc='" + desc + '\'' +
'}';
}
// get&&set方法
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
// 测试
public class TestEnum {
public static void main(String[] args) {
// 可以直接输出
System.out.println(Zoo.CAT);
System.out.println(Zoo.PANDA);
int num = Zoo.PANDA.getNum();
System.out.println(num);
// 利用序号获得PANDA的描述
System.out.println(Zoo.getDesc(num));
}
}
输出结果:
Zoo{num=3, desc='可爱'}
Zoo{num=2, desc='国宝'}
2
国宝
枚举也支持定义抽象方法,这时的枚举类似一个抽象类,它的每一个枚举实例都需要实现该方法,这样不同的实例就有不同的行为方式。
public enum Zoo2 {
TIGER{
@Override
public String eat(){
return "吃肉";
}
},
PANDA{
@Override
public String eat(){
return "吃竹子";
}
};
// 定义抽象方法
public abstract String eat();
// 测试
public static void main(String[] args) {
System.out.println(Zoo2.TIGER + Zoo2.TIGER.eat());
System.out.println(Zoo2.PANDA + Zoo2.PANDA.eat());
}
}
输出结果:
TIGER吃肉
PANDA吃竹子
(四)枚举实现接口
由于所有的枚举都会继承java.lang.Enum类且Java遵循单继承规则,所以枚举不会再继承其它的类,但是枚举可以实现接口。
// 定义一个接口
public interface Food {
void eat();
}
public enum Zoo3 implements Food{
TIGER, PANDA, CAT;
@Override
public void eat() {
System.out.println(this + "吃饲料");
}
public static void main(String[] args) {
Zoo3.TIGER.eat();
Zoo3.CAT.eat();
}
}
输出结果:
TIGER吃饲料
CAT吃饲料
枚举除了可以实现接口以外,还可以利用接口把相似类型的枚举统一的组织起来,定义在同一个接口中。
public interface Zoo4 {
enum Carnivore implements Zoo4 {
TIGER, LION, CAT
}
enum Herbivore implements Zoo4 {
ELEPHANT, ALPACA
}
}
这样写出来的代码更易读;枚举也可以嵌套枚举,这样也易于管理这些枚举:
public enum Animals {
FEROCITY(Zoo4.Carnivore.class),
LOVELINESS(Zoo4.Herbivore.class);
private Zoo4[] values;
// 把类的实例对象放进枚举里
private Animals(Class<? extends Zoo4> animal) {
values = animal.getEnumConstants();
}
public interface Zoo4 {
enum Carnivore implements Zoo4 {
TIGER, LION, CAT
}
enum Herbivore implements Zoo4 {
ELEPHANT, ALPACA
}
}
}
(五)枚举与switch
从JDK 1.7开始,switch变得丰富了,接下来我们看看它和枚举的一起使用。
public enum Zoo {
TIGER, PANDA, CAT, ELEPHANT, ALPACA
}
public class EnumSwitch {
public static void main(String[] args) {
print(Zoo.PANDA);
}
public static void print(Zoo zoo) {
switch (zoo) {
case TIGER:
System.out.println("老虎");
break;
case PANDA:
System.out.println("熊猫");
break;
case ELEPHANT:
System.out.println("大象");
break;
}
}
}
二、Enum的常用方法
public class TestEnum {
public static void main(String[] args) {
// 1. compareTo()方法比较此枚举与指定对象的顺序
int compareTo = Zoo.PANDA.compareTo(Zoo.CAT);
System.out.println(compareTo);
// 2. equals()方法判断指定对象是否等于此枚举常量
boolean equals = Zoo.TIGER.equals(Zoo.PANDA);
System.out.println(equals);
// 3. getDeclaringClass()方法返回此枚举常量的枚举类型相对应的Class对象
Class<Zoo> aClass = Zoo.PANDA.getDeclaringClass();
System.out.println(aClass);
// 4. ordinal()方法返回枚举对象在枚举中的序号(从0开始)
int ordinal = Zoo.TIGER.ordinal();
System.out.println(ordinal);
// 5. name()方法返回枚举常量的名称
String name = Zoo.PANDA.name();
System.out.println(name);
// 6. values()方法返回枚举实例对象数组
Zoo[] values = Zoo.values();
// 7. valueOf()方法返回一个指定枚举常量
Zoo panda = Zoo.valueOf("PANDA");
System.out.println(panda);
}
}
输出结果:
-1
false
class Zoo
0
PANDA
[LZoo;@1b6d3586
Zoo{num=2, desc='国宝'}
以上就是枚举的主要基本用法,欢迎讨论指正。