Java:枚举类也就这么回事
MySQL8.0 InnoDB并行执行
目次
一、媒介
本篇博客是对JDK1.5的新特征罗列的一波小小的总结,主假如昨天在看一部分面试题的时刻,碰到了罗列范例的题目,发明本身有很多细节还须要加强,做起来都含糊其词,是时刻总结一波了。
二、源自一道面试题
不多bb,直接直言不讳,我碰到如许一道或许很简单的题目:
enum AccountType
{
SAVING, FIXED, CURRENT;
private AccountType()
{
System.out.println(“It is a account type”);
}
}
class EnumOne
{
public static void main(String[]args)
{
System.out.println(AccountType.FIXED);
}
}
问打印的结果是啥?准确答案以下:
It is a account type
It is a account type
It is a account type
FIXED
至于结果为啥是这个,且看我逐步总结。
三、罗列的由来
存期近合理。
我贼喜好这句圣经,每次我一诠释不了它为何涌现的时刻,就不自发地用上这句话。
罗列肯定有他存在的代价,在一些时刻,我们须要定义一个类,这个类中的对象是有限且牢固的,比方我们一年有四个时节,春夏秋冬。
在罗列被支撑之前,我们该怎样定义这个Season类呢?可能会像下面如许:
public class Season {
//private润饰组织器,没法随意建立对象
private Season(){}
//final润饰供应的对象在类外不能转变
public static final Season SPRING = new Season();
public static final Season SUMMER = new Season();
public static final Season AUTUMN = new Season();
public static final Season WINTER = new Season();
}
在定义上,这个Season类能够完成我们的预期,它们各自代表一个实例,且不能被转变,外部也不能随意建立实例。
但,经由历程自定义类完成罗列的结果有个明显的问题:代码量异常大。
因而,JDK1.5,罗列类应运而生。
四、罗列的定义情势
enum
关键字用以定义罗列类,这是一个和class
,interface
关键字职位相称的关键字。也就是说,罗列类和我们之前运用的类差不太多,且enum和class润饰的类假如同名,会失足。
有一部分划定规矩,类须要遵照的,罗列类也遵照:
- 罗列类也能够定义成员变量、组织器、平常和笼统要领等。
- 一个Java源文件最多只能定义一个public的罗列类,且类名与文件名雷同。
- 罗列类能够完成一个或多个接口。
也有一部分划定规矩,罗列类显得异乎寻常:
- 罗列类的实例必须在罗列类的第一行显式列出,以逗号分开,列出的实例体系默许增加
public static final
润饰。 - 罗列类的组织器默许私有,且只能是私有,能够重载。
- 罗列类默许final润饰,没法被继续。
- 罗列类都继续了java.lang.Enum类,所以没法继续其他的类。
- 平常状况下,罗列常量须要用
罗列类.罗列常量
的体式格局挪用。
晓得这些今后,我们能够用enum关键字从新定义罗列类:
public enum Season{
//定义四个实例
SPRING,SUMMER,AUTUMN,WINTER;
}
须要注重的是,在JDK1.5罗列类到场今后,switch-case语句举行了扩大,其掌握表达式能够是恣意罗列范例,且能够直接运用罗列值的称号,无需增加罗列类作为限制。
五、Enum类里有啥?
Enum类是一切enum关键字润饰的罗列类的顶级父类,里头定义的要领默许状况下,是通用的,我们来瞅它一瞅:
public abstract class Enum<E extends Enum<E>> extends Object implements Comparable<E>, Serializable
我们能够发明,Enum实际上是一个继续自Object类的笼统类(Object类果然是顶级父类,不可撼动),并完成了两个接口:
- Comparable:支撑罗列对象的比较。
- Serializable:支撑罗列对象的序列化。
1、唯一的组织器
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
官方文档如许说的:程序员不能去挪用这个组织器,它用于编译器相应enum范例声明发出的代码,关于这一点,我们背面体会会越发深入一些。
2、重要的要领们
关于Object类中的要领,这边就不赘述了,重要提一提特别的要领。
public final String name()
返回这个罗列常量的称号。官方发起:大多数状况,最好运用toString()要领,因为能够返回一个友爱的名字。而name()要领以final润饰,没法被重写。
public String toString()
源码上看,toString()要领和name()要领是雷同的,然则发起:假若有更友爱的常量称号显现,能够重写toString()要领。
public final int ordinal()
返回此罗列常量的序号(其在enum声明中的位置,个中初始常量的序号为零)。
大多数程序员将不须要这类要领。它被用于庞杂的基于罗列的数据构造中,如EnumSet和EnumMap。
public final int compareTo(E o)
这个要领用于指定罗列对象比较次序,同一个罗列实例只能与雷同范例的罗列实例举行比较。
public final int compareTo(E o) {
Enum<?> other = (Enum<?>)o;
Enum<E> self = this;
if (self.getClass() != other.getClass() && // optimization
//getDeclaringClass()要领返回该罗列常量对应Enum类的类对象
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
//该罗列常量次序在o常量之前,返回负整数
return self.ordinal - other.ordinal;
}
public static <T extends Enum > T valueOf(Class enumType,
String name)
该静态要领返回指定罗列类中指定称号的罗列常量。
3、凭空涌现的values()要领
为何会想到总结这个要领呢?实在也是有肯定心路历程的,官方文档特别强调了一句话:
Note that when using an enumeration type as the type of a set or as the type of the keys in a map, specialized and efficient set and map implementations are available.
平常Note开头的玩艺儿,照样比较重要的。大抵意义以下:
当运用罗列范例作为鸠合的范例或映照中的键的范例时,能够运用专门化且有用的鸠合和映照完成。
看完异常不明白,因而开始查找材料,发明有一种用法:
Arrays.asList(AccountType.values())
很明显挪用了这个罗列类的values()要领,然则适才对罗列类的要领一通剖析,也没看到有values()要领啊。然则编译器确切提醒,有,确切有!
这是怎么回事呢?JDK文档是这么说的:
The compiler automatically adds some special methods when it creates an enum. For example, they have a static values method that returns an array containing all of the values of the enum in the order they are declared.
编译器会在建立一个罗列类的时刻,自动在里面到场一些特别的要领,比方静态的values()要领,它将返回一个数组,依据罗列常量声明的次序寄存它们。
如许一来,罗列类就能够和鸠合等玩艺儿很好地合营在一起了,细致咋合营,今后碰到了就晓得了。
关于这一点,待会反编译今后会越发印象深入。
六、反编译罗列类
注:因为学问尚浅,这部分内容总结起来虚虚的,然则总归查找了很多的材料,若有说的不对的处所,还望批评区批评指正。
那末,回到我们文章开头提到的那到面试题,我们依据结果来推想程序运转今后发作的状况:
- 个中的组织器被挪用了三次,申明定义的罗列常量确切是三个活生生的实例,也就是说,每次建立实例就会挪用一次组织器。
- 然后,
System.out.println(AccountType.FIXED);
将会挪用toString()要领,因为子类没有重写,那末将会返回name值,也就是"FIXED"
。
至此,我们的猜想完毕,实在确切也大差不差了,大抵就是这个历程。在一番查阅材料今后,我又尝试着去反编译这个罗列类文件:
我们先用javap -p AccountType.class
敕令试着反编译今后检察一切类和成员。
为了看看static中发作的状况,我试着用越发细致的指令,javap -c -l AccountType.class
,试图猎取当地变量信息表和行号,虽然我大几率照样看不太懂的。
我们以个中一个为例,参看虚拟机字节码指令表,大抵历程以下:
static {};
Code:
0: new #4 //建立一个对象,将其援用值压入栈
3: dup //复制栈顶数值并将复制值压入栈顶
4: ldc #10 //将String常量值SAVING从常量池推送至栈顶
6: iconst_0 //将int型0推送至栈顶
7: invokespecial #11 //挪用超类组织器
10: putstatic #12 //为指定的静态域赋值
以下为由个人明白简化的编译构造:
public final class AccountType extends java.lang.Enum<AccountType> {
//静态罗列常量
public static final AccountType SAVING;
public static final AccountType FIXED;
public static final AccountType CURRENT;
//存储静态罗列常量的私有静态域
private static final AccountType[] $VALUES;
//编译器新到场的静态要领
public static AccountType[] values();
//挪用实例要领猎取指定称号的罗列常量
public static AccountType valueOf(java.lang.String);
static {
//建立对象,传入罗列常量名和次序
SAVING = new AccountType("SAVING",0);
FIXED = new AccountType("FIXED",1);
CURRENT = new AccountType("CURRENT",2);
//给静态域赋值
$VALUES = new AccountType[]{
SAVING,FIXED,CURRENT
}
};
}
Enum类的组织器,在感应到enum关键字润饰的类今后,将会被挪用,传入罗列常量的字符串字面量值(name)和索引(ordinal),建立的实例存在私有静态域&VALUES
中。
而且编译器确切会增加静态的values()要领,用以返回寄存罗列常量的数组。
七、罗列类完成单例
public enum EnumSingleton {
INSTANCE;
public EnumSingleton getInstance(){
return INSTANCE;
}
}
这部分比及今后总结单例形式再侃,先在文末贴个地点。
objectarx 多段线自交检查