实例(也叫对象)有限且固定不变的类,在Java里被称为枚举类。
例如,季节类,它只有4个实例(春、夏、秋、冬),并且这4个实例不会改变。可以用枚举类来表示:
public enum SeasonEnum{ SPRING,SUMMER,FALL,WINTER; }
- 1
- 2
- 3
枚举类是一种特殊的类,它一样可以有自己的成员变量、方法,可以实现一个或多个接口,也可以有自己的构造器。
(1)就如上面所说的,有些类的实例有限且固定,需要有一种特定且方便的方式来表示这种类。
(2)使用枚举类可以使程序更加健壮,避免创建对象的随意性。
(3)避免一些常量值的意义不明确
(1) 枚举类默认继承 java.lang.Enum 类,而不是 Object 类,因此枚举类不能显示继承其他父类。 (2) 使用 enum 定义的非抽象的枚举类默认会使用 final 修饰,因此非抽象枚举类不能派生子类(即不能被继承)。 > final关键字回顾:final修饰的类不能被继承、修饰的方法不能被重写、修饰的属性其值不能改变。 (3) 枚举类的构造器只能使用 private 访问控制符,如果忽略访问控制符的话,则默认使用 private 修饰;如果强制指定其他的访问控制符(例如public、procted等),则会报错。 (4) 枚举类的所有实例必须在枚举类的第一行显示列出,否则这个枚举类永远都不可能产生实例。列出的这些实例,系统会自动给它们加上 public static final 修饰。枚举类的实例以逗号分隔,分号结束,这些列出的枚举值代表了该枚举类的所有可能的实例
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
public enum Weekday {
SUN(0),MON(1),TUS(2),WED(3),THU(4),FRI(5),SAT(6);
private int value;
private Weekday(int value){
this.value = value;
}
public static Weekday getNextDay(Weekday nowDay){
int nextDayValue = nowDay.value;
if (++nextDayValue == 7){
nextDayValue =0;
}
return getWeekdayByValue(nextDayValue);
}
public static Weekday getWeekdayByValue(int value) {
for (Weekday c : Weekday.values()) {
if (c.value == value) {
return c;
}
}
return null;
}
}
class Test2{
public static void main(String[] args) {
System.out.println("nowday ====> " + Weekday.SAT);
System.out.println("nowday int ====> " + Weekday.SAT.ordinal());
System.out.println("nextday ====> " + Weekday.getNextDay(Weekday.SAT)); // 输出 SUN
//输出:
//nowday ====> SAT
//nowday int ====> 6
//nextday ====> SUN
}
}
Weekday可以调用的方法和参数。发现它有两个方法:value()和valueOf()。还有我们刚刚定义的七个变量。
public enum Weekday {
SUN,MON,TUS,WED,THU,FRI,SAT
}
class Test3{
public static void main(String[] args) {
//它的作用是传来一个字符串,然后将它转变为对应的枚举变量。前提是你传的字符串和定义枚举变量的字符串一抹一样,区分大小写。如果你传了一个不存在的字符串,那么会抛出异常。
System.out.println(Weekday.valueOf("mon".toUpperCase()));
//MON
//这个方法会返回包括所有枚举变量的数组。在该例中,返回的就是包含了七个星期的Weekday[]。可以方便的用来做循环。
for (Weekday w : Weekday.values()){
//默认请款下,枚举类会给所有的枚举变量一个默认的次序,该次序从0开始,类似于数组的下标。而.ordinal()方法就是获取这个次序(或者说下标)
System.out.println(w + ".ordinal() ====>" +w.ordinal());
}
//SUN.ordinal() ====>0
//MON.ordinal() ====>1
//TUS.ordinal() ====>2
//WED.ordinal() ====>3
//THU.ordinal() ====>4
//FRI.ordinal() ====>5
//SAT.ordinal() ====>6
//该方法用来比较两个枚举变量的”大小”,实际上比较的是两个枚举变量的次序,返回两个次序相减后的结果,如果为负数,就证明变量1”小于”变量2 (变量1.compareTo(变量2),返回【变量1.ordinal() - 变量2.ordinal()】)
System.out.println("Weekday.MON.compareTo(Weekday.FRI) ===> " + Weekday.MON.compareTo(Weekday.FRI));
System.out.println("Weekday.MON.compareTo(Weekday.MON) ===> " + Weekday.MON.compareTo(Weekday.MON));
System.out.println("Weekday.MON.compareTo(Weekday.SUM) ===> " + Weekday.MON.compareTo(Weekday.SUN));
//Weekday.MON.compareTo(Weekday.FRI) ===> -4
//Weekday.MON.compareTo(Weekday.MON) ===> 0
//Weekday.MON.compareTo(Weekday.SUM) ===> 1
//它和toString()方法的返回值一样
//唯一的区别是,你可以重写toString方法。name变量就是枚举变量的字符串形式。
System.out.println("Weekday.MON.name() ====> " + Weekday.MON.name());
//Weekday.MON.name() ====> MON
}
}
public enum Weekday {
MON(1,"mon"),TUS(2,"tus"),WED(3,"wed"),THU(4,"thu"),FRI(5,"fri"),SAT(6,"sat"),SUN(0,"sun");
private int value;
private String label;
private Weekday(int value,String label){
this.value = value;
this.label = label;
}
}
public enum TrafficLamp {
RED(30) {
@Override
public TrafficLamp getNextLamp() {
return GREEN;
}
}, GREEN(45) {
@Override
public TrafficLamp getNextLamp() {
return YELLOW;
}
}, YELLOW(5) {
@Override
public TrafficLamp getNextLamp() {
return RED;
}
};
private int time;
private TrafficLamp(int time) {
this.time = time;
}
//一个抽象方法
public abstract TrafficLamp getNextLamp();
}
因为RED本身就是一个TrafficLamp对象的引用。实际上,在初始化这个枚举类的时候,你可以理解为执行的是
TrafficLamp RED = new TrafficLamp(30)
,但是因为TrafficLamp里面有抽象方法,还记得匿名内部类么?TrafficLamp RED = new TrafficLamp(30){ @Override public TrafficLamp getNextLamp() { return GREEN; } };
- 1
- 2
- 3
- 4
- 5
- 6
而在枚举类中,我们只需要像上面那样写【
RED(30){}
】就可以了,因为java会自动的去帮我们完成这一系列操作。
enum Signal {
GREEN, YELLOW, RED
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch (color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}
虽然枚举类不能继承其他类,但是还是可以实现接口的
public interface Behaviour {
void print();
String getInfo();
}
public enum Color implements Behaviour {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
// 接口方法
@Override
public String getInfo() {
return this.name;
}
// 接口方法
@Override
public void print() {
System.out.println(this.index + ":" + this.name);
}
}
public interface Food {
enum Coffee implements Food {
BLACK_COFFEE, DECAF_COFFEE, LATTE, CAPPUCCINO
}
enum Dessert implements Food {
FRUIT, CAKE, GELATO
}
}
public enum EasySingleton{
INSTANCE;
}
public class DoubleCheckedLockingSingleton{
private volatile static DoubleCheckedLockingSingleton INSTANCE;
private DoubleCheckedLockingSingleton(){}
public DoubleCheckedLockingSingleton getInstance(){
if(INSTANCE == null){
synchronized(DoubleCheckedLockingSingleton.class){
//double checking Singleton instance
if(INSTANCE == null){
INSTANCE = new DoubleCheckedLockingSingleton();
}
}
}
return INSTANCE;
}
}
public class Singleton{
private static final Singleton INSTANCE = new Singleton();
private Singleton(){}
public static Singleton getSingleton(){
return INSTANCE;
}
}
参考:博文1