Enum

Enum类是java.lang包中一个类,他是Java语言中所有枚举类型的公共基类。

一、定义

public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable

1.抽象类

首先,抽象类不能被实例化,所以我们在java程序中不能使用new关键字来声明一个Enum,如果想要定义可以使用这样的语法:

enum enumName{
value1,value2
method1(){}
method2(){}
}

其次,看到抽象类,第一印象是肯定有类继承他。至少我们应该是可以继承他的,所以:

public class testEnum extends Enum{
}
public class testEnum extends Enum<Enum<E>>{
}
public class testEnum<E> extends Enum<Enum<E>>{
}

尝试了以上三种方式之后,得出以下结论:Enum类无法被继承。

为什么一个抽象类不让继承?enum定义的枚举是怎么来的?难道不是对Enum的一种继承吗?带着这些疑问我们来反编译以下代码:

enum Color {RED, BLUE, GREEN}

编译器将会把他转成如下内容:

public final class Color extends Enum<Color> {
public static final Color[] values() { return (Color[])$VALUES.clone(); }
public static Color valueOf(String name) { ... } private Color(String s, int i) { super(s, i); } public static final Color RED;
public static final Color BLUE;
public static final Color GREEN; private static final Color $VALUES[]; static {
RED = new Color("RED", 0);
BLUE = new Color("BLUE", 1);
GREEN = new Color("GREEN", 2);
$VALUES = (new Color[] { RED, BLUE, GREEN });
}
}

短短的一行代码,被编译器处理过之后竟然变得这么多,看来,enmu关键字是java提供给我们的一个语法糖啊。。。从反编译之后的代码中,我们发现,编译器不让我们继承Enum,但是当我们使用enum关键字定义一个枚举的时候,他会帮我们在编译后默认继承java.lang.Enum类,而不像其他的类一样默认继承Object类。且采用enum声明后,该类会被编译器加上final声明,故该类是无法继承的。 PS:由于JVM类初始化是线程安全的,所以可以采用枚举类实现一个线程安全的单例模式。

2.实现ComparableSerializable接口

Enum实现了Serializable接口,可以序列化。 Enum实现了Comparable接口,可以进行比较,默认情况下,只有同类型的enum才进行比较(原因见后文),要实现不同类型的enum之间的比较,只能复写compareTo方法。

3.泛型:<E extends Enum<E>>

怎么理解<E extends Enum<E>>?

首先,这样写只是为了让Java的API更有弹性,他主要是限定形态参数实例化的对象,故要求只能是Enum,这样才能对 compareTo 之类的方法所传入的参数进行形态检查。所以,我们完全可以不必去关心他为什么这么设计。

这里倒是可以关注一下泛型中extends的用法,以及K V O T E ? object这几个符号之间的区别。

好啦,我们回到这个令人实在是无法理解的<E extends Enum>

首先我们先来“翻译”一下这个Enum<E extends Enum>到底什么意思,然后再来解释为什么Java要这么用。 我们先看一个比较常见的泛型:List。这个泛型的意思是,List中存的都是String类型,告诉编译器要接受String类型,并且从List中取出内容的时候也自动帮我们转成String类型。 所以Enum<E extends Enum>可以暂时理解为Enum里面的内容都是E extends Enum类型。 这里的E我们就理解为枚举,extends表示上界,比如: List<? extends Object>,List中的内容可以是Object或者扩展自Object的类。这就是extends的含义。 所以,E extends Enum表示为一个继承了Enum类型的枚举类型。 那么,Enum<E extends Enum>就不难理解了,就是一个Enum只接受一个Enum或者他的子类作为参数。相当于把一个子类或者自己当成参数,传入到自身,引起一些特别的语法效果。

二、属性

在Enum中,有两个成员变量,一个是名字(name),一个是序号(ordinal)。 序号是一个枚举常量,表示在枚举中的位置,从0开始,依次递增。

private final String name;
public final String name() {
return name;
}
private final int ordinal;
public final int ordinal() {
return ordinal;
}

三、方法

1. 构造方法

前面我们说过,Enum是一个抽象类,不能被实例化,但是他也有构造函数,从前面我们反编译出来的代码中,我们也发现了Enum的构造函数,在Enum中只有一个保护类型的构造函数:

protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}

文章开头反编译的代码中private Color(String s, int i) { super(s, i); }中的super(s, i);就是调用Enum中的这个保护类型的构造函数来初始化name和ordinal。

2. 其它方法

	public String toString() {
return name;
} public final boolean equals(Object other) {
return this==other;
} public final int hashCode() {
return super.hashCode();
} public final int compareTo(E o) {
Enum other = (Enum)o;
Enum self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
} public final Class<E> getDeclaringClass() {
Class clazz = getClass();
Class zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? clazz : zuper;
} public static <T extends Enum<T>> T valueOf(Class<T> enumType,
String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum constant " + enumType.getCanonicalName() + "." + name);
}

四、参考资料

http://www.hollischuang.com/archives/92

java源码学习(三)Enum的更多相关文章

  1. 在IDEA中搭建Java源码学习环境并上传到GitHub上

    打开IDEA新建一个项目 创建一个最简单的Java项目即可 在项目命名填写该项目的名称,我这里写的项目名为Java_Source_Study 点击Finished,然后在项目的src目录下新建源码文件 ...

  2. Java 源码学习系列(三)——Integer

    Integer 类在对象中包装了一个基本类型 int 的值.Integer 类型的对象包含一个 int 类型的字段. 此外,该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,还 ...

  3. JDK源码学习笔记——Enum枚举使用及原理

    一.为什么使用枚举 什么时候应该使用枚举呢?每当需要一组固定的常量的时候,如一周的天数.一年四季等.或者是在我们编译前就知道其包含的所有值的集合. 利用 public final static 完全可 ...

  4. mybatis源码学习(三)-一级缓存二级缓存

    本文主要是个人学习mybatis缓存的学习笔记,主要有以下几个知识点 1.一级缓存配置信息 2.一级缓存源码学习笔记 3.二级缓存配置信息 4.二级缓存源码 5.一级缓存.二级缓存总结 1.一级缓存配 ...

  5. Java 源码学习线路————_先JDK工具包集合_再core包,也就是String、StringBuffer等_Java IO类库

    http://www.iteye.com/topic/1113732 原则网址 Java源码初接触 如果你进行过一年左右的开发,喜欢用eclipse的debug功能.好了,你现在就有阅读源码的技术基础 ...

  6. Vue源码学习三 ———— Vue构造函数包装

    Vue源码学习二 是对Vue的原型对象的包装,最后从Vue的出生文件导出了 Vue这个构造函数 来到 src/core/index.js 代码是: import Vue from './instanc ...

  7. Java源码学习 -- java.lang.StringBuilder,java.lang.StringBuffer,java.lang.AbstractStringBuilder

    一直以来,都是看到网上说“ StringBuilder是线程不安全的,但运行效率高:StringBuffer 是线程安全的,但运行效率低”,然后默默记住:一个是线程安全.一个线程不安全,但对内在原因并 ...

  8. spring源码学习(三)--spring循环引用源码学习

    在spring中,是支持单实例bean的循环引用(循环依赖)的,循环依赖,简单而言,就是A类中注入了B类,B类中注入了A类,首先贴出我的代码示例 @Component public class Add ...

  9. java源码学习(四)ArrayList

    ArrayList ​ ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ​ ArrayList不是线程安全的,只能用在单线程环境下, ...

  10. java源码学习(二)Integer

    Integer类包含了一个原始基本类型int.Integer属性中就一个属性,它的类型就是int. 此外,这个类还提供了几个把int转成String和把String转成int的方法,同样也提供了其它跟 ...

随机推荐

  1. 自动化运维:使用psutil和paramiko读取远程主机信息

    1.前言  今天大致看了下自动化运维的东西,里面介绍到了psutil模块,其封装了linux 下的大部分shell命令,用起来比较方便.但是基本都是介绍在本地如何使用,而实际情况大家很少这样使用,一般 ...

  2. LeetCode5. Longest Palindromic Substring 最长回文子串 4种方法

    题目链接:https://leetcode.com/problems/longest-palindromic-substring/ 题意很简单,就是求一个字符串得最长子串,这里的子串指连续的. 本文给 ...

  3. Jquery ajaxSubmit()的浏览器兼容问题

    form.ajaxSubmit({ 2 beforeSubmit: function() { 3 if (FinanceUtil.validate(form)) { 4 FinanceUtil.loa ...

  4. 1-LPC1778建立工程

    先来建立一个工程模板,,,要比32简单的多,假设32是用库开发的话,,,,因为还要把那些和库相关的文件加到工程里.... LPC呢就只需要把设置系统和总线的时钟文件(system_LPC177x_8x ...

  5. 15、TCP/IP协议

    15.TCP/IP协议       几台孤立计算机系统组在一起形成网络,几个孤立网络连在一起形成一个网络的网络,即互连网.一个互连网就是一组通过相同协议族互连在一起的网络. 互联网的目的之一是在应用程 ...

  6. YYLabel 自动布局 富文本文字点击事件

    YYLabel显示多行除了需要设置numberOfLines = 0以外,还需要设置preferredMaxLayoutWidth最大的宽度值才可以生效多行效果 YYLabel中的NSMutableA ...

  7. 018 关联映射文件中<class>标签中的lazy(懒加载)属性

    Lazy(懒加载): 只有在正真使用该对象时,才会创建这个对象 Hibernate中的lazy(懒加载): 只有我们在正真使用时,它才会发出SQL语句,给我们去查询,如果不使用对象则不会发SQL语句进 ...

  8. Java IO流学习总结(1)

    Java IO流学习总结 Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本 ...

  9. 开涛spring3(6.9) - AOP 之 6.9 代理机制

    Spring AOP通过代理模式实现,目前支持两种代理:JDK动态代理.CGLIB代理来创建AOP代理,Spring建议优先使用JDK动态代理. JDK动态代理:使用java.lang.reflect ...

  10. mac系统下给文件夹加密方法

    电脑里我们往往会有许多隐私的文件,不希望被别人看到,在过去的Windows电脑里,我们习惯性的会在文件夹中将该文件隐藏,但是这个隐藏是不安全的,遇到稍微会点电脑技术的人就可以给你解开,安全性不高,ma ...