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

本文深入探讨了Java中枚举的实现原理,解释了枚举如何被编译为类,并展示了如何在枚举中定义抽象方法及其实现。通过具体示例说明了枚举与普通类的区别与联系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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文件

 

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

-----------

会发现上面的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文件


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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值