JAVA_浅析枚举
1.简介
Enum 一般用来表示一组相同类型的常量。如:性别、日期、月份、颜色等。对这些属性用常量的好处是显而易见的,不仅可以保证单例,且在比较的时候可以用 ”==” 来替换 equals。在 JDK1.5 之前是没有 Enum 这个类型的,那时候一般用接口常量来替代。
2.Enum究竟是啥
你是否被问到过以下的问题:
- 枚举允许继承类吗?
- 枚举允许实现接口吗?
- 枚举可以用等号比较吗?
- 可以继承枚举吗?
- 枚举是单例吗?
- 当使用compareTo()比较枚举时,比较的是什么?
- 当使用equals()比较枚举的时候,比较的是什么?
面试官的问题五花八门,但归根结底都是在考察同一个问题:枚举的本质。
那么枚举究竟是啥?
废话不说,先看源代码:
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
//*******
}
从源代码可以看出Enum的本质是一个抽象类,所以上述问题基本上都迎刃而解了.
3.Enum的特性
- Enum常量隐式的加上了static和final,一旦被创建就无法修改
- Enum提供了是类型安全的(type-safe)
- Enum隐式的加上了values()方法,返回一个数组包含所有的Enum常量
- 两个Enum常量可以使用
==或equals()方法比较 - Enum可以用在switch语句中,就像int,String。
- Enum有自己的名称空间
- Enum可以实现Java接口
- 可以在Enum中定义构造器
4.Enum的注意事项
Enum的用法
1 . Enum的声明,Enum可以声明在一个类之外或者在类内部,但是不能在方法中。
Enum的用法
- Enum的声明,Enum可以声明在一个类之外或者在类内部,但是不能在方法中。
- 在创建Enum常量的时候可以指定值,但是这个时候你需要定义一个成员变量构造器。构造器必须是private的,不然会报编译错误.
5.EumDemo
1)创建一个水果相关的枚举
public enum Fruit {
APPLE, PEAR, PEACH, ORANGE;
}
再看看Fruit反编译的结果:
package test;
public final class Fruit extends Enum {
private Fruit(String s, int i) {
super(s, i);
}
public static Fruit[] values() {
Fruit afruit[];
int i;
Fruit afruit1[];
System.arraycopy(afruit = ENUM$VALUES, 0, afruit1 = new Fruit[i = afruit.length], 0, i);
return afruit1;
}
public static Fruit valueOf(String s) {
return (Fruit)Enum.valueOf(test/Fruit, s);
}
public static final Fruit APPLE;
public static final Fruit PEAR;
public static final Fruit PEACH;
public static final Fruit ORANGE;
private static final Fruit ENUM$VALUES[];
static {
APPLE = new Fruit("APPLE", 0);
PEAR = new Fruit("PEAR", 1);
PEACH = new Fruit("PEACH", 2);
ORANGE = new Fruit("ORANGE", 3);
ENUM$VALUES = (new Fruit[] {
APPLE, PEAR, PEACH, ORANGE
});
}
}
注意这几行:
public static final Fruit APPLE;
public static final Fruit PEAR;
public static final Fruit PEACH;
public static final Fruit ORANGE;
可以看到我们定义的几个成员变量,JVM底层把它转换成Eunm类型.
我们还是再写点代码看看:
public enum Fruit {
APPLE {
public void test() {
System.out.println("I am an apple.");
}
},
PEAR {
public void test() {
System.out.println("I am a pear.");
}
},
PEACH {
public void test() {
System.out.println("I am a peach.");
}
},
ORANGE;
public void test() {
System.out.println("I am a fruit.");
}
}
其中,只有Orange没有Overide test()方法;
在main方法里面调用:
public static void main(String[] args) {
Fruit.APPLE.test();
Fruit.PEAR.test();
Fruit.PEACH.test();
Fruit.ORANGE.test();
}
输出结果:
I am an apple.
I am a pear.
I am a peach.
I am a fruit.
可以看到,重新定义了test方法的APPLE,PEAR,PEACH覆盖了从父类继承过来的默认行为,而未从新定义test方法的ORANGE却沿袭了父类的行为,多态性在这里展现出来了。
再看看反编译后的文件:
发现多了几个内部类的字节码文件,看看反编译后的代码:
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3)
// Source File Name: Fruit.java
package test;
import java.io.PrintStream;
public class Fruit extends Enum {
private Fruit(String s, int i) {
super(s, i);
}
public void test() {
System.out.println("I am a fruit.");
}
public static Fruit[] values() {
Fruit afruit[];
int i;
Fruit afruit1[];
System.arraycopy(afruit = ENUM$VALUES, 0, afruit1 = new Fruit[i = afruit.length], 0, i);
return afruit1;
}
public static Fruit valueOf(String s) {
return (Fruit)Enum.valueOf(test/Fruit, s);
}
Fruit(String s, int i, Fruit fruit) {
this(s, i);
}
public static final Fruit APPLE;
public static final Fruit PEAR;
public static final Fruit PEACH;
public static final Fruit ORANGE;
private static final Fruit ENUM$VALUES[];
static {
APPLE = new Fruit("APPLE", 0) {
public void test()
{
System.out.println("I am an apple.");
}
};
PEAR = new Fruit("PEAR", 1) {
public void test()
{
System.out.println("I am a pear.");
}
};
PEACH = new Fruit("PEACH", 2) {
public void test()
{
System.out.println("I am a peach.");
}
};
ORANGE = new Fruit("ORANGE", 3);
ENUM$VALUES = (new Fruit[] {
APPLE, PEAR, PEACH, ORANGE
});
}
}
注意这段代码:
static
{
APPLE = new Fruit("APPLE", 0) {
public void test()
{
System.out.println("I am an apple.");
}
};
PEAR = new Fruit("PEAR", 1) {
public void test()
{
System.out.println("I am a pear.");
}
};
PEACH = new Fruit("PEACH", 2) {
public void test()
{
System.out.println("I am a peach.");
}
};
ORANGE = new Fruit("ORANGE", 3);
这个时候的APPLE,PEAR,PEACH已经以匿名内部类的方式对Fruit进行了Overide,自然体现出了多态,多出的那三个疑似内部类的class文件也就是它们!而ORANGE,没有重写test方法,仍然以一个Fruit实例的形式出现。
6.反思-Enum多态体现的好处
其实通过上面我们可以通过Enum(枚举类)实现单例工厂模式,这样就能省去多余的判断步骤和不必要的父类和其他的相关类,大大提高我们的代码效率.
练习小Demo
1.创建Dog和Persion类
package com._521it.Enum.Model;
/**
* @Auther: yangxiangnan
* @Date: 2019/7/17 14:47
* @Description:
*/
public class Dog {
private String name;
private String age;
public Dog() {
System.out.println("狗狗的无参数构造器");
}
public Dog(String name, String age) {
this.name = name;
this.age = age;
System.out.println("狗狗的有参数构造器");
}
public void bark(){
System.out.println("汪汪");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
package com._521it.Enum.Model;
/**
* @Auther: yangxiangnan
* @Date: 2019/7/17 14:51
* @Description:
*/
public class Persion {
private String name;
private String age;
public Persion() {
System.out.println("人的无参数构造器");
}
public Persion(String name, String age) {
this.name = name;
this.age = age;
System.out.println("人的有参数构造器");
}
public void speak(){
System.out.println("说话");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
2.创建单例工厂类
package com._521it.Enum.Singletion;
import com._521it.Enum.Model.Dog;
import com._521it.Enum.Model.Persion;
/**
* @Auther: yangxiangnan
* @Date: 2019/7/17 14:52
* @Description:
*/
public enum SingletonInstanceFactory {
INSTANCE_FACTORY;
private Persion persion;
private Dog dog;
private SingletonInstanceFactory(){
persion = new Persion();
dog = new Dog();
}
public Persion getPersion(){
return persion;
}
public Dog getDog(){
return dog;
}
}
3.进行测试
package com._521it.Enum;
import com._521it.Enum.Model.Dog;
import com._521it.Enum.Model.Persion;
import com._521it.Enum.Singletion.SingletonInstanceFactory;
import org.junit.Test;
/**
* @Auther: yangxiangnan
* @Date: 2019/7/17 17:18
* @Description:
*/
public class Demo {
@Test
public void test01(){
Dog dog1 = SingletonInstanceFactory.INSTANCE_FACTORY.getDog();
Dog dog2 = SingletonInstanceFactory.INSTANCE_FACTORY.getDog();
System.out.println("dog1 = " + dog1);
System.out.println("dog2 = " + dog2);
dog1.bark();
dog2.bark();
System.out.println(dog1 == dog2);
Persion persion1 = SingletonInstanceFactory.INSTANCE_FACTORY.getPersion();
Persion persion2 = SingletonInstanceFactory.INSTANCE_FACTORY.getPersion();
System.out.println("persion1 = " + persion1);
System.out.println("persion2 = " + persion2);
persion1.speak();
persion2.speak();
System.out.println(persion1 == persion2);
}
}
4.运行结果
结果如下:


浙公网安备 33010602011771号