枚举类型(Enumerated Type)在编程语言中常用,程序员必备食粮,下面随着我的思路来认识一下枚举类型。

是什么

枚举类型在java中是一种基本数据类型。它用于声明一组命名的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型。

为什么用

至于为什么,可以简单这样理解,知道用一个东西的劣势后,出来一个新东西来弥补它。再加上点好处。

举个例子,如果希望定义三种颜色,你可以在Java程序中通过常量定义方式来实现。

Public static class Color
{public static final int RED = 0;      public static final int BlUE = 1;public static final int GREEN = 2;
}

使用的时候,可以直接在程序中直接引用这些常量。但是,这种方式也存在着一些问题。

1、类型不安全

由于颜色常量的对应值是整数形,所以程序执行过程中很有可能给颜色变量传入一个任意的整数值,导致出现错误。

2、没有命名空间

由于颜色常量只是类的属性,当你使用的时候不得不通过类来访问

3、一致性差

因为整形常量属于编译器常量,所以编译过程完成后,所有客户端和服务器端引用的地方,会直接将整数值写入。这样,当你修改旧的枚举整数值后或者增加新的枚举值后,所有引用地方代码都需要重新编译,否则运行时刻就会出现错误。

4、类型无指意性

由于颜色变量值仅仅是一些无任何含义的整数值,如果在运行期调试时候,你会发现日志中有很多魔术数字,但除了程序员本身,其他人很难明白其奥秘。

所以,为了改进Java语言在这方面的不足,5.0版本SDK发布时候,在语言层面上增加了枚举类型。

怎么用(定义)

枚举类型的定义

用enum关键字加上名称和大括号包含起来的枚举值体即可,例如将上面的例子用enum方式来重新定义

enum Color{RED,BLUE,GREEN}

从上面的的定义形式来看,似乎Java中的枚举类型很简单,但实际上Java语言规范赋予枚举类型的功能非常的强大,它不仅简单地将整形数值转换成对象,还将枚举类型定义转变成一个完整功能的类定义。这种类定义的扩展允许开发者给枚举类型增加任何方法和属性,也可以实现任意的接口。另外,Java平台也为Enum类型提供了高质量的实现,比如默认实现Comparable和Serializable接口,让开发者一般情况下不用关心这些细节。

引入枚举类型一个最直接的益处就是扩大switch语句使用范围。5.0之前,Java中switch的值只能是简单类型,比如int、byte、short、char有了枚举类型之后,就可以使用对象了。(从jdk1.7开始,switch支持String类型。)

用的时候应该需要注意的几个地方

1、Enum类型不支持public和protected修饰符的构造方法。因此构造函数一定要是private或friendly。继而可以得知,枚举对象是无法在程序中通过直接调用其构造方法来初始化的。

2、定义Enum类型的时候,如果是简单类型,那么最后一个枚举值后不用跟任何一个符号;但如果有定制方法,那么最后一个枚举值与后面代码用;隔开。

3、由于enum类型的值实际上是通过运行期构造出对象来表示的,所以在cluster环境下,每个虚拟机都会构造出一个同义的枚举对象。因而在做比较操作的时候需要注意,如果直接通过使用等号('==')操作符,这样看似一样的枚举值一定不相等,因为这不是同一个对象实例。

对此进行更正:enum类型是基本类型,枚举是常量,编译后成为静态变量,Java中静态变量都是存储在方法区,枚举在整个内存中只有唯一的一个实例,所以用等号('==')判断,枚举值一定相同。

举几个例子

1、最常见的枚举定义

public class Enum1 {// 定义一周七天的枚举类型enum WeekDayEnum {Mon, Tue, Wed, Thu, Fri, Sat, Sun;public static void main(String[] args) {// 读取当天的信息WeekDayEnum today = WeekDayEnum.Sun;// 根据日期来选择进行活动switch (today) {case Mon:System.out.println(today);break;case Tue:System.out.println(today);break;case Wed:System.out.println(today);break;case Thu:System.out.println(today);break;case Fri:System.out.println(today);break;case Sat:System.out.println(today);break;default:System.out.println(today);break;}}}
}

打印结果:

Sun

2、定制Enum类型:通过类似class的定义来给枚举进行定制,比如要给enum类型增加属性。

// 定义 RSS(Really Simple Syndication) 种子的枚举类型
public enum NewsRSSFeedEnum{// 雅虎头条新闻 RSS 种子YAHOO_TOP_STORIES("<a href=\"http://rss.news.yahoo.com/rss/topstories\"><code>http://rss.news.yahoo.com/rss/topstories</code></a>"),// CBS 头条新闻 RSS 种子CBS_TOP_STORIES("<a href=\"http://feeds.cbsnews.com/CBSNewsMain?format=xml\"><code>http://feeds.cbsnews.com/CBSNewsMain?format=xml</code></a>"),// 洛杉矶时报头条新闻 RSS 种子LATIMES_TOP_STORIES("<a href=\"http://feeds.latimes.com/latimes/news?format=xml\"><code>http://feeds.latimes.com/latimes/news?format=xml</code></a>");// 枚举对象的 RSS 地址的属性private String rss_url;// 枚举对象构造函数NewsRSSFeedEnum(String rss) {this.rss_url = rss;}// 枚举对象获取 RSS 地址的方法public String getRssURL() {return this.rss_url;}public static void main(String[] args) {NewsRSSFeedEnum newsRSSFeedEnum = NewsRSSFeedEnum.YAHOO_TOP_STORIES;switch (newsRSSFeedEnum) {case YAHOO_TOP_STORIES:System.out.println(newsRSSFeedEnum);System.out.println(newsRSSFeedEnum.getRssURL());break;case CBS_TOP_STORIES:System.out.println(newsRSSFeedEnum.getRssURL());break;default:System.out.println(newsRSSFeedEnum.getRssURL());break;}}
}

打印结果:

YAHOO_TOP_STORIES
<a href="http://rss.news.yahoo.com/rss/topstories"><code>http://rss.news.yahoo.com/rss/topstories</code></a>

3、一个特别有意思的现象,关于toString()

public enum Color
{Red("红色"),Green("绿色"),Blue("蓝色");private String color;Color(String color){this.color = color;}public String toString(){return this.color;}public static void main(String[] args){Color color = Color.Blue;switch(color){case Green:System.out.println(color);break;case Red:System.out.println(color);default:System.out.println(color);System.out.println(color.toString());}}
}

打印结果:

蓝色

蓝色

有意思的东西来了,为什么第一行输出的是蓝色而不是Blue。让我从源码的级别来告诉你。

我们可以在IDE工具中跳println()方法,看其实现。

 public void println(Object x) {String s = String.valueOf(x);synchronized (this) {print(s);newLine();}}

然后我们再跳valuesOf()方法,看其实现。

 public static String valueOf(Object obj) {return (obj == null) ? "null" : obj.toString();}

到这里可以看出,用println打印,会自动调用toString()方法。一切类都继承自Object,对其toString()方法进行了重写,所以会调子类的方法。
如果将toString改名,那么第一行就会正常输出Blue。

4、不同虚拟机上枚举对象的比较

WeekDayEnum.java

public enum WeekDayEnum {Mon(1), Tue(2), Wed(3), Thu(4), Fri(5), Sat(6), Sun(7);private int index;WeekDayEnum(int idx) {this.index = idx;}public int getIndex() {return index;}
}

EnumerationClient.java

// 客户端程序,将一个枚举值通过网络传递给服务器端import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;public class EnumerationClient {public static void main(String... args) throws UnknownHostException,IOException {Socket socket = new Socket();// 建立到服务器端的连接socket.connect(new InetSocketAddress("127.0.0.1", 8999));// 从连接中得到输出流OutputStream os = socket.getOutputStream();ObjectOutputStream oos = new ObjectOutputStream(os);// 将星期五这个枚举值传递给服务器端oos.writeObject(WeekDayEnum.Fri);oos.close();os.close();socket.close();if ("".equals("")) {}}}

EnumerationServer.java

// 服务器端程序,将从客户端收到的枚举值应用到逻辑处理中import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class EnumerationServer {public static void main(String... args) throws IOException,ClassNotFoundException {ServerSocket server = new ServerSocket(8999);// 建立服务器端的网络连接侦听Socket socket = server.accept();// 从连接中获取输入流InputStream is = socket.getInputStream();ObjectInputStream ois = new ObjectInputStream(is);// 读出客户端传递来的枚举值WeekDayEnum day = (WeekDayEnum) ois.readObject();// 用值比较方式来对比枚举对象if (day == WeekDayEnum.Fri) {System.out.println("client Friday enum value is same as server's");} else if (day.equals(WeekDayEnum.Fri)) {System.out.println("client Friday enum value is equal to server's");} else {System.out.println("client Friday enum value is not same as server's");}// 用 switch 方式来比较枚举对象switch (day) {case Mon:System.out.println("Do Monday work");break;case Tue:System.out.println("Do Tuesday work");break;case Wed:System.out.println("Do Wednesday work");break;case Thu:System.out.println("Do Thursday work");break;case Fri:System.out.println("Do Friday work");break;case Sat:System.out.println("Do Saturday work");break;case Sun:System.out.println("Do Sunday work");break;default:System.out.println("I don't know which is day");break;}ois.close();is.close();socket.close();}
}

打印结果:

client Friday enum value is same as server's
Do Friday work

工具类

JDK5.0中在增加Enum类的同时,也增加了两个工具类EnumSet和EnumMap,这两个类都放在java.until包里。

EnumSet

EnumSet是一个针对枚举类型的高性能的Set接口实现。EnumSet中转入的所有枚举对象都必须是同一种类型,在其内部,是通过bit-vector来实现,也就是通过一个long型数。EnumSet支持在枚举类型的所有值的某个范围中进行迭代。

Demo:

import java.util.EnumSet;public class Enum2{public static void main(String[] args) {for(WeekDayEnum day : EnumSet.range(WeekDayEnum.Mon, WeekDayEnum.Fri)) {System.out.println(day);}}
}

注:WeekDayEnum.java在上面内容已提到。

打印结果:

Mon
Tue
Wed
Thu
Fri

EnumMap

与EnumSet类似,EnumMap也是一个高性能的Map接口实现,用来管理使用枚举类型作为keys的映射表,内部是通过数组方式来实现。EnumMap将丰富的和安全的Map接口与数组快速访问结合到一起。如果希望将一个枚举类型映射到一个值,就应该使用EnumMap.

Demo:

import java.util.EnumMap;
import java.util.Map;enum RainbowColor {Red, Orange, Yellow, Green, Blue, Indigo, purple
}public class Enum3 {// 定义一个 EnumMap 对象,映射表主键是日期枚举类型,值是颜色枚举类型// 定义一个 EnumMap 对象,映射表主键是日期枚举类型,值是颜色枚举类型private static Map<WeekDayEnum, RainbowColor> schema = new EnumMap<WeekDayEnum, RainbowColor>(WeekDayEnum.class);static {// 将一周的每一天与彩虹的某一种色彩映射起来for (int i = 0; i < WeekDayEnum.values().length; i++) {schema.put(WeekDayEnum.values()[i], RainbowColor.values()[i]);}}public static void main(String[] args) {System.out.println("What is the lucky color today?");System.out.println("It's " + schema.get(WeekDayEnum.Sat));}
}

打印结果:

What is the lucky color today?
It's Indigo

其它资料参考:

http://lib.csdn.net/article/javase/2436

https://www.ibm.com/developerworks/cn/java/j-lo-enum/

http://baike.baidu.com/link?url=6bB1lb-w3mM-C6_oKRzxHsjD8LupjurSX8TevdFdKSFmfPC9BZV5HUoo4W976Dv1j26fSszFA2VLe8zU7VAA7KPBYTZJqQC6k6UdPLgd4rDSrH-ZCEt7bNt7DVGfXYcW

拓展:

堆区
存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令);
jvm只有一个heap区,被所有线程共享,不存放基本类型和对象引用,只存放对象本身。

堆的优劣势:堆的优势是可以动态的分配内存大小,生存期也不必事先告诉编译器,java的垃圾收集器会自动收取这些不在使用的数据,但缺点是,由于要在运行时动态分配内存,存取速度慢。

栈区
每一个线程包含一个stack区,只保存基本数据类型的对象和自定义对象的引用(不是对象),对象都存放在共享heap中;
每个栈中的数据(基本数据类型和对象引用)都是私有的,其他栈不能访问;
栈分为3部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)
栈的优势劣势:存取速度比堆要快,仅次于直接位于CPU的寄存器,但必须确定的是存在stack中的数据大小与生存期必须是确定的,缺乏灵活性。单个stack的数据可以共享。
stack:是一个先进后出的数据结构,通常保存方法中的参数,局部变量。在java中,所有基本类型和引用类型都在stack中储存,栈中数据的生存空间一般在当前scopes内

方法区

又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量;方法区中包含的都是在程序中永远的唯一的元素。

摘自《java栈、堆、方法区详解》,地址:http://www.cnblogs.com/hqji/p/6582365.html

Java语言中的枚举类型相关推荐

  1. Java快速入门学习笔记2 | Java语言中的基本类型

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  2. 谈Java语言规范之枚举类型

    文章目录 枚举类型 一. 枚举常量 二.枚举主体声明 对枚举常数自我引用的限制: 三.枚举成员 这不是一顿快餐,希望你沉淀下来,细细品尝 写在前面 枚举类型可以考虑用来替换接口中的常量声明.并且 &l ...

  3. java 枚举_Java中的枚举类型(Enum)详解

    文章前记 程序员工作久了便可能整日忙碌于"增删改查"中,迷失方向,毫无进步. 该公众号致力于分享软件开发相关的原创干货,助你完成从程序员到架构师的进阶之路! 努力!做一个NB的Co ...

  4. 在java中关于枚举类型的特性_java枚举类型小结

    JDK5.0之前,我们一般选择使用 interface 来保存常量组,以此来弥补 JDK 中没有枚举类型的缺陷,从JDK5.0开始,Sun引进了一个全新的关键字 enum 来定义一个枚举类.同inte ...

  5. java中检查性异常类_Java异常处理、java语言推崇使用检查类型异常

    异常处理是java语言的重要特性之一,<Three Rules for effective Exception Handling>一文中是这么解释的:它主要帮助我们在debug的过程中解决 ...

  6. java 三种错误类型 区别_请列举至少三种在java语言中发生“严重错误”的情况...

    [简答题]自已编写一个自定义非整数异常类,来处理一个异常 [填空题]捕获异常时,可以把catch捕获的异常对象( ),使上层try-catch结构继续处理该异常事件;也可以把异常对象转换为其它异常对象 ...

  7. Java基础教程(15)--枚举类型

      枚举类型定义了一个枚举值的列表,每个值是一个标识符.例如,下面的语句声明了一个枚举类型,用来表示星期的可能情况: public enum Day {SUNDAY, MONDAY, TUESDAY, ...

  8. Java语言中的生僻知识

    最近有一首名叫<生僻字>的流行歌曲火遍大江南北,创作者给佶屈聱牙的生僻字,配上了优美明快的旋律,竟然让歌曲变得琅琅上口.悦耳动听起来,平时不太常见的拒人于千里之外的这些汉字也不再那么陌生, ...

  9. java语言中声明布尔型_【Java初探02】——Java语言基础

    本篇博文就Java语言的一些基本元素进行一些记录和阐述,主要讲解一下Java语言的一些基本构成元素和Java的主类结构. Java语言基础的大致组成 java主类结构 基本的数据类型 变量与常量 运算 ...

最新文章

  1. 智能车竞赛技术报告 | 双车接力组 - 黑龙江工程学院 - 睿龙二队
  2. Codeforces round 396(Div. 2) 题解
  3. P1476 休息中的小呆
  4. CAS的ABA问题描述 AtomicStampReference
  5. 领域驱动DDD原理简介与实践
  6. nginx redis mysql_Nginx + Lua + Kafka + Redis + Mysql
  7. 赣州师范高等专科学校计算机网络技术,赣州师范高等专科学校2021年招生简章...
  8. matlab红字怎么删除,matlab-系统爱好者
  9. Selective Search for Object Recoginition(转)
  10. Android中矢量图形的相关知识
  11. 面试题33:输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。 * 例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
  12. 概率Probability的本质是什么?[附概率基础知识,文末可下载28页PDF]
  13. 电信网通竞合协议事件升级 内部文件泄露曝裂痕
  14. 能切换双显卡的android,安卓模拟器如何把双显卡切换成高性能显卡
  15. 第二十章 幻读是什么,幻读有什么问题?
  16. Viusal 各个版本离线镜像
  17. 2021邵阳市地区高考成绩排名查询,2021邵阳最新高中排名前十
  18. 关于手机系统。。。。
  19. Golang 等比例调整图片分辨率且用黑色补齐多余部分
  20. 说一说递归里的return返回!!!

热门文章

  1. Linux的目录结构
  2. 联想 小新 Pro 14/16、Air 14/ 14 Plus 2022 款评测 联想小新 Pro 14、联想小新 Pro16、联想Air 14、联想14 Plus 2022款怎么样
  3. dofilter在java中_java 过滤器Filter中chain.doFilter()之前和之后代码的执行顺序
  4. 荣耀品牌全面升级背后:以战代守,深蹲起跳 1
  5. 17084 罗密欧与朱丽叶的迷宫问题
  6. 进阶题66 字符串统计
  7. 某大厂程序员爆料:和一个俄罗斯大美女相亲,不要彩礼,自带嫁妆,只是担心俄罗斯女人老得太快!...
  8. Microsoft SQL Server Management Studio更语言改为中文语言
  9. slot game 开发
  10. Windows命令--schtasks