1.简介 ==Enum 一般用来表示一组相同类型的常量 ==。如:性别、日期、月份、颜色等。对这些属性用常量的好处是显而易见的,不仅可以保证单例,且在比较的时候可以用 ”==” 来替换 equals。在 JDK1.5 之前是没有 Enum 这个类型的,那时候一般用接口常量来替代。
2.Enum究竟是啥 你是否被问到过以下的问题:
枚举允许继承类吗? 枚举允许实现接口吗? 枚举可以用等号比较吗? 可以继承枚举吗? 枚举是单例吗? 当使用compareTo()比较枚举时,比较的是什么? 当使用equals()比较枚举的时候,比较的是什么? 面试官的问题五花八门,但归根结底都是在考察同一个问题:枚举的本质。
那么枚举究竟是啥?
废话不说,先看源代码:
1 2 3 4 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可以声明在一个类之外或者在类内部,但是不能在方法中。 ==<font color="red"> 在创建Enum常量的时候可以指定值,但是这个时候你需要定义一个成员变量构造器。构造器必须是private的,不然会报编译错误. </font> == 5.EumDemo 1)创建一个水果相关的枚举
1 2 3 public enum Fruit { APPLE, PEAR, PEACH, ORANGE; }
再看看Fruit反编译的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 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 }); } }
注意这几行:
1 2 3 4 public static final Fruit APPLE; public static final Fruit PEAR; public static final Fruit PEACH; public static final Fruit ORANGE;
可以看到我们定义的几个成员变量,JVM底层把它转换成Eunm类型.
我们还是再写点代码看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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方法里面调用:
1 2 3 4 5 6 public static void main (String[] args) { Fruit.APPLE.test(); Fruit.PEAR.test(); Fruit.PEACH.test(); Fruit.ORANGE.test(); }
输出结果:
1 2 3 4 I am an apple. I am a pear. I am a peach. I am a fruit.
可以看到,重新定义了test方法的APPLE,PEAR,PEACH覆盖了从父类继承过来的默认行为,而未从新定义test方法的ORANGE却沿袭了父类的行为,多态性在这里展现出来了。
再看看反编译后的文件:
发现多了几个内部类的字节码文件,看看反编译后的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 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 }); } }
注意这段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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(枚举类)实现单例工厂模式,这样就能省去多余的判断步骤和不必要的父类和其他的相关类,大大提高我们的代码效率.
<font color="red"> 练习小Demo **</font>**1.创建Dog和Persion类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package com._521it.Enum.Model;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; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package com._521it.Enum.Model;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.创建单例工厂类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package com._521it.Enum.Singletion;import com._521it.Enum.Model.Dog;import com._521it.Enum.Model.Persion;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.进行测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 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;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.运行结果
结果如下: