Java 枚举(enum)之浅进浅出

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xueshr/article/details/82792597

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='国宝'}

以上就是枚举的主要基本用法,欢迎讨论指正。

猜你喜欢

转载自blog.csdn.net/xueshr/article/details/82792597
今日推荐