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的用法

  1. Enum的声明,Enum可以声明在一个类之外或者在类内部,但是不能在方法中。
  2. 在创建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.运行结果

结果如下:

posted @ 2021-11-23 09:48  will-yang  阅读(56)  评论(0)    收藏  举报