枚举的概述
认识枚举
- 枚举是一种特殊类。
枚举类的格式:
修饰符 enum 枚举类名{
名称1,名称2,...;
其他成员...
}
public enum A{ X,Y,Z; ... }
注意:
- 枚举类中的第一行,只能写一些合法的标识符(名称),多个名称用逗号隔开。
- 这些名称,本质是常量,每个常量都会记住枚举类的一个对象。
枚举类的特点:
public enum A{ X,Y,Z; }
实际上完整代码为:
Complied from "A.java" public final class A extends java.lang.Enum<A>{ public static final A X = new A(); public static final A Y = new A(); public static final A Z = new A(); }
具有以下特点:
- 枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象。
- 枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象。
- 枚举都是最终类,不可以被继承。
- 枚举类中,从第二行开始,可以定义类的其他各种成员。
- 编译器为枚举类新增了几个方法,并且枚举类都是继承:java.lang.Enum类的,从enum类也会继承到一些方法。
第一点:枚举类的第一行都是常量,记住的是枚举类的对象
A a = A.Y;
因为枚举类的第一行都是常量,记住的是枚举类的对象,所以我们可以直接用枚举类得到里面的象,例如:枚举类名称.枚举类常量1、枚举类名称.枚举类常量2;A.X、A.Y。
第二点:枚举类的构造器是私有的,不能对外创建对象。
public class Test{ public static void main(String[] args){ A a = new A(); //会报错 //枚举类不能对外创建对象 } }
第三点:枚举类提供了一些额外的API
A[] a1 = A.values(); //拿到全部对象 A a2 = A.valueOf("Z"); //拿到其中一个对象 System.out.println(a2.name()); //输出结果为Z对象的name System.out.println(a2.ordinal()); //索引
都是为枚举类新增的一些API。
拓展:抽象枚举
抽象枚举简单来说,就是枚举类里面定义了抽象方法的枚举类。
抽象枚举在创建自身的对象时,必须要重写方法,所以直接在第一行中进行方法重写:
public enum B{ X(){ @Override public void go(){ } },Y(){ @Override public void go(){ } }; private String name; //第一行之后就可以正常写变量了 public abstract void go(); //抽象方法 public String getName(){ return name; } public String setName(name){ this.name = name; } }
写构造器时,可以不用写修饰符,默认为private。
public enum B{ X(){ @Override public void go(){ } },Y(){ @Override public void go(){ } }; /* private */ B(){ } /* private */ B(String name){ this.name; } private String name; public abstract void go(); //抽象方法 public String getName(){ return name; } public String setName(name){ this.name = name; } }
如果把无参构造器去掉,就会报错,因为前面枚举类创建的对象重写方法时要调用到无参构造器。
当然,也可以调用有参构造器
public enum B{ X(){ @Override public void go(){ } },Y("张三"){ @Override public void go(){ System.out.println(getName() + "在跑~"); } }; B(){ } B(String name){ this.name; } private String name; public abstract void go(); //抽象方法 public String getName(){ return name; } public String setName(name){ this.name = name; } }
public class Test{ public static void main(String[] args){ B y = B.Y; y.go(); } }
运行结果为:
张三在跑~
这个过程是:Y对象在用B枚举类创建自己这个对象,调用B的有参构造器,传入参数“张三”,存储在name变量中;且因为是抽象枚举,创建Y对象时需要重写其所有抽象方法,重写go方法时取到name变量的值“张三”并输出。
用枚举实现单例模式
使用枚举是可以直接实现单例模式的,
复习一下单例设计模式:
一个类可以new出很多对象,但对于某个应用场景下,我们希望这个类只能有一个对象这就是单例设计模式所解决的问题。也就是说,单例设计模式是确保一个类只有一个对象,我们学过饿汉式单例和懒汉式单例,前者是先把对象创建好,后者则在使用该设计模式时再进行创建。
写法:
- 把类的构造器私有。
- 定义一个类变量记住类的一个对象。·
- 定义一个类方法,返回对象。
用枚举类的方式实现单例:
public enum C{ X; //单例 }
枚举的应用场景
- 用来表示一组信息,然后作为参数进行传输。
(可以类比C语言的枚举类型变量)
如果选择定义一个一个的常量来表示一组信息,并作为参数传输,那么其参数值不受约束。
而选择定义枚举表示一组信息,并作为参数传输,代码可读性好,参数值得到了约束,对使用者更友好。
例如:
public class Constant{ public static final int BOY = 0; public static final int GIRL = 1; } public class Test{ public static void main(String[] args){ //check(1); //check(21); //传入参数不受约束 check(Constant.BOY); } public static void check(int sex){ switch(sez){ case Constant.BOY: ... break; case Constant.GIRL: ... break; } } }
如果用常量做信息标志和分类,就存在传入参数不受约束的问题。
所以就开始用枚举了:
public enum Constant2{ BOY,GIRL; //定义枚举类型 } public class Test{ public static void main(String[] args){ //check(1); //check(21); //传入参数不受约束 check(Constant2.BOY); } public static void check(Constant2 sex){ switch(sez){ case BOY: //Constant.BOY前缀可以省略 ... break; case GIRL: ... break; } } }
虽然枚举做信息标志和分类比较好,但是在实际中可能会发现还是很多人用常量,主要是因为常量用起来比较简单,其他原因就是常量也有一些优势,比如可以定义不同类型的常量,使用起来比较灵活。
所以两种方式都会使用到,并没有相互淘汰掉谁。
END