Java关键字之enum

       使用枚举之前必须了解一下,枚举的定义是什么。《Java编程思想》上说,枚举可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用。这句话是个什么意思呢? 你比如说季节类,它只能有春夏秋冬四个对象;星期类,他只有周一到周天七个对象。诸如这种对象的个数有限的,我们都可以用枚举实现它。

      首先看一个简单的枚举定义的例子:

  

enum Season{
	SPRING,SUMMER,AUTUMN,WINTER
}

我们先不着急的使用这个enum,我们先看下字节码部分(这里只贴出来一部分)



     看着图片我们可以发现以下信息:

   1.Season被定义成为了一个类。 而且被声明为final,这说明他不可以被继承;  且继承了Enum类,说明他也不能在继承其他的类; 因此------>枚举不可以继承别的类,不可以被继承;

   2.发现四个季节都被定义为static final类型,说明在链接阶段就已经初始化,且不可以在运行中改变他的值。

   3.发现2个static函数,values()和valueOf(),干什么用的后面再说。

   4.一个static代码块,里面调用了构造函数。就是invokespecail那一句。了解jvm的同学的可能会奇怪,一般情况下,构造函数是public的,应该用invokevirtual调用,而invokespecail一般调用非public方法的(比如private修饰的)<想了解的可以看下我写的静态分配和动态分派 的博客>;了解这点内容的就知道,enum类的构造方法是private的;所以不可以直接new;


   基本上看了javap出来的字节码我们大致可以知道上述四点内容。下来,我们开始使用枚举。为了代码比较有权威性,我尽量使用《Thinking in Java》的代码。

enum Shrubber {
	GRAND,CRAWLING,HANGING
}

public class EnumClass {
	public static void main(String[] args) {
		//获取enum的每个实例
		for(Shrubber s:Shrubber.values()){
			//打印每个具体值的位置
			System.out.println(s.ordinal());
			//打印具体的值。用name函数
			System.out.println(s.name());
			//打印所属枚举的类名
			System.out.println(s.getDeclaringClass());
			//判断 两个枚举常量是否相等
			System.out.println(s.equals(Shrubber.GRAND));
			System.out.println(s == Shrubber.GRAND);
		}
		//根据给定的名字返回对应enum的实例,如果枚举不存在,则抛出异常。
		System.out.println(Enum.valueOf(Shrubber.class, "GRAND"));
	}
}

输出:
0
GRAND
class BasicEnum.Shrubber
true
true
1
CRAWLING
class BasicEnum.Shrubber
false
false
2
HANGING
class BasicEnum.Shrubber
false
false
GRAND

上面列出了几种常用的方法,具体方法可以查JDK,这出不深入讲解。在上面我们发现,我们获取一个枚举的实例的时候,并没有通过new得到,因为构造方法是private的。 我们使用的是values()方法,通过他可以获取enum实例,这是一种方法。这也是字节码里面提到的一个static方法。

 

.2.<Thinking in Java>提到了静态导入,其作用是可以直接访问枚举类内的变量,但是至于实际中好用不好用很难讲。自己在使用时一般不加这个,因为代码看起来会很奇怪。

public enum Spiciness {
	NOT,MILD,MEDIUM,HOT,FLAMING
}

//这里静态导入
import static StaticImport.Spiciness.*;

public class Burrito {
	Spiciness degree;
	public Burrito(Spiciness degree){
		this.degree=degree;
	}
	public String toString(){
		return "Burrito is"+degree;
	}
	public static void main(String[] args) {
		// 这里访问不需要再写enum的类名
		System.out.println(new Burrito(NOT));
	}
}

上面的代码如果开始不知道枚举类存在的话,让你看起来会很奇怪,这个NOT从哪来的?因为一般都是用 public static final这样的语句来修饰,如果在java文件内没有找到就会让你很疑惑,除非注意到了静态导入。


3.我们通过字节码可以知道,enum实际上是一个final的类,既然是类,我们就可以在里面重写方法,甚至是main方法。但是要注意一点,在我们要先定义enum实例,在定义方法或者属性。

 

4.switch(exp),exp只能为一个整型表达式或者枚举常量。整型表达式是指int的基本类型或者可以被Integer包装的类型,例如byte,short,char(他们可以被转化为int)。所以在switch中使用枚举也是枚举的常用地方。很简单,举个例子就行了。没什么要注意的地方。

public enum Signal {
	GREEN,YELLOW,RED;
}	

public class TrafficLight {
	//获取一个enum引用的方法
	Signal color = Signal.RED;
	public void change(){
		switch(color){
		case RED:
			color = Signal.GREEN;
			break;
		case GREEN:
			color = Signal.RED;
			break;
		case YELLOW:
			color = Signal.YELLOW;
			break;
		}
	}
	public String toString(){
		return color.name();
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TrafficLight t = new TrafficLight();
		for(int i=0;i<7;i++){
			System.out.println(t);
			t.change();
		}
	}

}

这里我们直接通过访问枚举的一个实例来获取枚举的引用。


5.values()方法的特别地方。

  我们前面说到过,enum类是继承Enum得到的。我们查看Enum的实现时,发现他并没有values()这个方法,而我们自己月没有实现,那么这个方法是怎么来的?Enum的实现



  其实,values()这个static方法是由编译器添加的static方法,同样的还有ValueOf()方法。Enum里面实现的valuesOf有两个参数,jvm给添加的只有一个参数。在这里很容易出现下面一个错误:

enum Signal {
	GREEN,YELLOW,RED;
}

public class demo111 {
	public static void main(String[] args) {
		Enum a = Signal.GREEN;
		//values方法有jvm添加,向上转型后此方法丢失
//		for(Signal s : a.values(){
//			
//		}	
	}
}

5. 枚举可以实现接口用来扩充自己。


6.EnumSet

    《effective java》中讲到:尽量用EnumSet代替位域。

    set是一种集合,只能向其中添加不重复的对象;对于enum,不能从一个给定enum中删除或者添加实例。 而EnumSset就是通过enum创建一种替代品,以替代传统的基于int的“位标志”,这些标记可以代表“开/关”信息表示添加、删除。例如

public enum AlarmPoints {
	STAIR1,STAIR2,LOBBY,OFFICE1,OFFICE2,OFFICE3,
	OFFICE4,BATHROOM,UTILITY,KICHEN
}

import static EnumSet.AlarmPoints.*;

import java.util.EnumSet;
public class EnumSets {
	/**
	 * Enum的缺点:无法添加或者删除enum中的元素;通过EnumSet可以做到
	 */
	public static void main(String[] args) {
		//noneof根据传入的的class新建一个新的enumset,此时他为空
		EnumSet<AlarmPoints> points = EnumSet.noneOf(AlarmPoints.class); 
		//想enumset中添加AlarmPoint中有的元素
		points.add(BATHROOM);
		//EnumSet.of根据传入的参数创建一个新的enum
		points.addAll(EnumSet.of(STAIR2,LOBBY,KICHEN));
		//不管放入的顺序怎么样,它内部都按照AlarmPoints的顺序打印
		System.out.println(points);
	}
}
EnumSet的基础是long,一个long有64位,而一个enum实例只需要一位表示开关,因此:在不超过一个long的表达能力下,EnumSet可以应用于最多64个元素的enum;如果超过64个,EnumSet会追加一个long.

7.EnumMap

  《Effective Java》中说:用EnumMap代替序数索引。

   EnumMap是一中特殊的map,他要求其中的key必须来自于一个enum。见下面例子。

public enum AlarmPoints {
	STAIR1,STAIR2,LOBBY,OFFICE1,OFFICE2,OFFICE3,OFFICE4,BATHROOM,UTILITY,KICHEN
}

import static EnumMap.AlarmPoints.*;

import java.util.EnumMap;

interface Command{void action();}

/*
 * EnumMap 用来代替序数索引0
 */
public class EnumMaps {
	
	public static void main(String[] args) {
		//EnumMap 创建需要一个enum作为key ; 再讲此enum的class作为形参传入
		EnumMap<AlarmPoints,Command> em  = new EnumMap<AlarmPoints,Command>(AlarmPoints.class);
		//为enum的每一个常量添加事件
		em.put(BATHROOM, new Command(){
			public void action(){
				System.out.println("BATHROOM BOOM");
			}
		});
		em.put(OFFICE1, new Command(){
			public void action(){
				System.out.println("OFFICE1 fires");
			}
		});
		//提取action的事件
		em.get(BATHROOM).action();
	}

}

8.Enum实现责任链

  <详见我的设计模式中的责任链部分>


9.常量相关方法

     enum是允许为每个enum的实例编写方法的。

import java.text.DateFormat;
import java.util.Date;

public enum ConstantSpecificMethod {
	DATE_TIME{
		public String getInfo(){
			return DateFormat.getDateInstance().format(new Date());
		}
	}
	,
	CLASSPATH{
		public String getInfo(){
			return System.getenv("CLASSPATH");
		}
	}
	,
	VERSION{
		public String getInfo(){
			return  System.getProperty("java.version");
		}
		String getS(){
			return "hhhh";
		}
	};
	
	/**
	 *这里的方法一定不能忘记。因为上面都是enum的实例,实例中的方法必须要在类里面先
	 *定义,实例里面才能 ;
	 *无论这里是抽象方法还是具体方法;抽象方法只是在后面实现了多态而已,具体方法说明
	 *在实例中被覆写了。 《Thinking in Java》里面在这里用的抽象方法;
         *在这里:尤其注意enum里面定义的是enum的实例,可以理解为一个对象在new之后的实例。
         */
	 public String getInfo(){
		 return "this is class.GetInfo()";
	 }
	 
	public static void main(String[] args){
		for(ConstantSpecificMethod s :ConstantSpecificMethod.values()){
			System.out.println(s.getInfo());
		}
	}
}

10.多路分发



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java关键字enum是用于定义枚举类型的关键字枚举类型是一种特殊的数据类型,它限制变量只能取几个固定值中的一个,而不是任意值。在Java中,使用enum关键字定义枚举类型可以简化代码并提高可读性。例如,可以使用enum关键字定义一个表示季节的枚举类型,其中包含春天、夏天、秋天和冬天四个常量。每个常量可以有自己的属性和方法。 枚举类型的常量可以通过枚举类的名称和常量名来访问。例如,在示例代码中,可以通过Season2.GIRL访问Gender2枚举类型中的GIRL常量。同时,可以使用for循环来迭代枚举类型的所有常量。在示例代码中,for循环遍历Color枚举类型的所有常量,并打印每个常量的值。 总结来说,Java关键字enum用于定义枚举类型,它可以简化代码并提高可读性。枚举类型的常量可以通过枚举类的名称和常量名来访问,同时可以使用for循环来迭代枚举类型的所有常量。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java enum关键字不识别的快速解决办法](https://download.csdn.net/download/weixin_38582909/12793660)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Java枚举enum关键字](https://blog.csdn.net/weixin_30627341/article/details/102437321)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [软件构造笔记:Java枚举](https://blog.csdn.net/weixin_42697247/article/details/107352466)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值