java基础加强--实现带有抽象方法的枚举

时间:2021-08-13 19:41:56

在学枚举的时候,看到这样定义枚举感到很奇怪。

public enum WeekDay {

SUN,MON,TUE,WED,THI,FRI,SAT
}

感觉像一个类,但又不是类。。

想看一下这个被编译过的字节码文件里都是什么内容。。

javac WeekDay.java
在被编译后生成了WeekDay.class文件。

然后反编译javap  WeekDay


Compiled from "WeekDay.java"
public final class WeekDay extends java.lang.Enum<WeekDay> {
public static final WeekDay SUN;
public static final WeekDay MON;
public static final WeekDay TUE;
public static final WeekDay WED;
public static final WeekDay THI;
public static final WeekDay FRI;
public static final WeekDay SAT;
public static WeekDay[] values();
public static WeekDay valueOf(java.lang.String);
static {};
}

会发现原来public enum WeekDay被编译器编译成了

public final class WeekDay extends java.lang.Enum<WeekDay> 

所以枚举就相当于一个类,而且是final 的最终类。继承自java.lang.Enum。

枚举值SUN编译器编译成了

public static final WeekDay SUN; 这是一个静态常量,类型是WeekDay。

--------------

那么静态常量的初始化在哪里?

查看Java API会发现java.lang.Enum有个构造函数

构造方法摘要

protected

Enum(String name, int ordinal)
          单独的构造方法。

 

既然WeekDay 是个枚举类,肯定继承了java.lang.Enum。

WeekDay是Enum的子类,子类能调用父类的构造函数进行初始化。

 

枚举类型的每一个值都将映射到 protected Enum(String name, int ordinal) 构造函数中,在这里,每个值的名称都被转换成一个字符串,并且序数设置表示了此设置被创建的顺序。

public enum WeekDay {

SUN,MON,TUE,WED,THI,FRI,SAT
}

这段代码实际上调用了7次 Enum(String name, int ordinal)

new Enum<WeekDay>("SUN",0);

new Enum<WeekDay>("MON",1);

new Enum<WeekDay>("TUE",2);

    ... ...

 可以把 enum 看成是一个普通的 class,它们都可以定义一些属性和方法

不同之处是:enum 不能使用 extends 关键字继承其他类,因为 enum 已经继承了 java.lang.Enumjava是单一继承)。

 

WeekDay继承了java.lang.Enum,当然也能使用Enum的方法。

方法摘要

protected  Object

clone()
          抛出 CloneNotSupportedException。

 int

compareTo(E o)
          比较此枚举与指定对象的顺序。

 boolean

equals(Object other)
          当指定对象等于此枚举常量时,返回 true。

protected  void

finalize()
          枚举类不能有 finalize 方法。

 Class<E>

getDeclaringClass()
          返回与此枚举常量的枚举类型相对应的 Class 对象。

 int

hashCode()
          返回枚举常量的哈希码。

 String

name()
          返回此枚举常量的名称,在其枚举声明中对其进行声明。

 int

ordinal()
          返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。

 String

toString()
          返回枚举常量的名称,它包含在声明中。

static

<T extends Enum<T>>
 T

 

valueOf(Class<T> enumType, String name)
          返回带指定名称的指定枚举类型的枚举常量。

--------------
枚举也相当于一个类。当然也可以定义自己的构造函数。但是这个构造函数必须为private所修饰。

这样可以保证外部代码无法新构造枚举类的实例。

--------------
public enum WeekDay {

SUN,MON,TUE,WED,THI,FRI,SAT;

private WeekDay(){
System.out.println(this.name()+"被初始化");
}

public static void main(String[] args){
WeekDay wd = WeekDay.FRI;
}
}

结果输出:

SUN被初始化

MON被初始化

TUE被初始化

WED被初始化

THI被初始化

FRI被初始化

SAT被初始化

WeekDay内部的SUN,MON,TUE,WED,THI,FRI,SAT;等静态常量一一被初始化。

------------
WeekDay相当于类当然也可以定义自己的成员(包括成员方法和成员函数):

public enum WeekDay {

SUN,MON,TUE,WED,THI,FRI,SAT;

private int ss = 9;

private WeekDay(){
//System.out.println(this.name()+"被初始化");
}

public static void main(String[] args){
WeekDay wd = WeekDay.FRI;
wd.vv();
wd = WeekDay.MON;
wd.vv();

WeekDay.SAT.vv();
}

public void vv(){
System.out.println("vvvvv"+(++ss));
}
  }

结果输出:

 vvvvv10

 vvvvv10

 vvvvv10

 

----------------

发现使用几个枚举值输出的结果都是一样的。

能不能让每个枚举值输出的结果不同呢?

于是就想到了多态

由父类引用指向子类对象,子类重写父类的方法。在运行的时候,实际调用的是子类的方法。

 --------------

在一个类里怎么让父类引用指向子类对象呢?

可以使用匿名内部类。

父类的方法不具体,子类重写父类方法后各自实现的也不同,所以将父类的方法定义为抽象的。父类的方法是抽象的了,当然父类也得是抽象类了。


例子:

public abstract class ListDemo {

ListDemo dd = new ListDemo(){ //new ListDemo()是什么具体的类?不知道,只知道是ListDemo的子类。。
//所以new ListDemo()是匿名内部类

public void zz() {

}

};

public abstract void zz();
}

-------------------------

可以再扩展下:

public abstract class TrafficLamp{

//RED是TrafficLamp类的成员,是TrafficLamp类的一个引用;
/* ---------
* new TrafficLamp(){
* public TrafficLamp nextLamp() {
return GREEN;
}
* };就是匿名内部类,是TrafficLamp的子类对象。
*/
public static final TrafficLamp RED = new TrafficLamp(){

public TrafficLamp nextLamp() {
return GREEN;
}
};

public static final TrafficLamp GREEN = new TrafficLamp(){

public TrafficLamp nextLamp() {
return YELLOW;
}
};
public static final TrafficLamp YELLOW = new TrafficLamp(){

public TrafficLamp nextLamp() {
return RED;
}
};

public abstract TrafficLamp nextLamp();
}

使用javac TrafficLamp.java编译这个程序得到4class文件

 java基础加强--实现带有抽象方法的枚举

类名$数字就代表一个匿名内部类。

-----------

会发现上面的TrafficLamp 怎么那么像枚举呢?

它和枚举比较相似。

那么在枚举中能不能定义抽象方法,并由子类实现呢?

当然是可以的。功能是一样的,而且实现起来会更简单。

public enum TrafficLamp{
/* RED是枚举的一个元素,
* 这个元素可以看做是由TrafficLamp的一个子类来实现的。
* */
RED{

public TrafficLamp nextLamp() {
return GREEN;
}
},

GREEN{

public TrafficLamp nextLamp() {
return YELLOW;
}
},
YELLOW{

public TrafficLamp nextLamp() {
return RED;
}
};

public abstract TrafficLamp nextLamp();
}

使用javac TrafficLamp.java编译这个程序

最后也是得到4class文件

java基础加强--实现带有抽象方法的枚举

这就是实现带有抽象方法的枚举。

如果一下子就看到这样带有抽象方法的枚举会感到很突兀,不知从何而来,为什么这样写呢。有了以上分析的会感觉好懂些。