Libx

JAVA 枚举类型的一些理解

Word count: 1,375Reading time: 5 min
2018/04/14 Share

说点废话

在开始学习JAVA之后,写习惯了Javascript的我,首先意识到的是好繁琐,比如在接触JAVA中的枚举类型之后,这在JS中想要实现重写一些方法,以及其他一些类似的效果其实从语法上来讲要简单的不少,虽然Javascript最初是JS之父用了10多天写出了的,甚至有一一部分直接抄的JAVA比如Date类,(虽然抄来的Date一直被吐槽不好用,好像打算要重写?)

甚至连起名字都是为了蹭一波JAVA的名气。并且面向对象的实现方式也截然不同,一个是纯正的基于对象的继承,另一个是基于原型链的继承。甚至有人调侃真的OOP和假的OOP。。

不过虽然实现方式不一样,但是一些设计思想感觉还是类似的,之前总有人说JAVA和Javascript的区别就是斑马和斑马线的区别,现在来想一想其实这两种语言还是类似的地方的,尤其是在ES6中的Class出现之后,Class ,extends 等等语法糖的出现,给人感觉更像了///可能JS作为一个一开始并不被看好的语言随着应用范围越来越广,使用JS、构建的项目也越来越大,想要变得更牛逼似乎有一种更适合于工程化的东西出现了吧。

JAVA的枚举类型

先来举个最常用的栗子🎂 :

public enum Colors {
RED,BLUE,BLACK,YELLOW,GREEN;
}
// 简单调用:Colors.RED

这是最基本的使用方法。但是其实并没有展现出JAVA的枚举类型的用途,有点人才埋没。

再举一个目前用的比较多的一种使用方式:

public enum Tips {
WIN("you win"),LOSE("you lose");
private String tip;
private Tips(String tip){
this.tip = tip;
}
public String toString(){
return this.tip;
}
}
System.out.println(Tips.WIN)
// you win

在这段代码中,我们简单的保存了一些基本的提示信息,重写tostring方法,这在JS里面其实可以说是很常见了,不同的是修改的原型链上的方法,不禁感到非常亲切。

在看到这种用法之后,很疑惑,WIN和LOSE,看起来很像是一个函数,但是很不理解在初始化的时候到底是怎么操作的,以至于认为在调用的时候是调用的一个名为WIN的方法,于是就反编译了编译生成的class文件:

➜ src javap Tips.class
Compiled from "Tips.java"
public final class Tips extends java.lang.Enum<Tips> {
public static final Tips WIN;
public static final Tips LOSE;
public static Tips[] values();
public static Tips valueOf(java.lang.String);
public java.lang.String toString();
static {};
}

在看到了反编译的文件之后才算明白,所创建的枚举类型实例(且为final类型)继承自Java的Enum类,
而在内部的编译中,其实是遍历生成以所写内容命名的Tips类的实例,且生成的实例就能为final类型,不可继承,因为是static类型由Tips类所属,所以可以直接调用,比如:Tips.WIN.
因为重写了构造方法Tips(),并声明了私有变量tip,所以在生成实例的时候,初始化各个实例的tip为所传入的内容。然后重写toString方法,在调用的时候,返回tip。效果就是实现了,当然重写类的toString方法可能一般并不提倡,以为在JS里面也同样是要避免污染原型链的,这里应该是类似的。

由于WIN(以WIN为例)实质上是Tips类的一个static的对象,为全局共有,当然可以给其创建封装新的接口,比如,
比如:

public String getTip (){
return this.tip;
}

需要注意的一点是,这个getTip方法是属于实例的还是属于class的?也就是说他是类方法还是实例方法?
再来反编译一下:

➜ src javap Tips.class
Compiled from "Tips.java"
public final class Tips extends java.lang.Enum<Tips> {
public static final Tips WIN;
public static final Tips LOSE;
public static Tips[] values();
public static Tips valueOf(java.lang.String);
public java.lang.String toString();
public java.lang.String getTip();
public static void main(java.lang.String[]);
static {};
}

因为在JS里构造函数中所写的方法,是属于实例的,即每初始化一个实例对象就会重新声明一个属于该对象的重名方法。浪费了内存。想要使其共享,就要将函数写到prototype上,所以在这里想了一下,不过在查了一些东西之后发现,这里的方法,即使并未写在构造函数里面,只要是非静态方法其就是实例方法。。似乎在JS和JAVA中,构造函数的概念及作用并不完全相同。与JS中使用工厂模式初始化的对象相比,JAVA中的类与JS的构造函数来对比更为合适一些。

Enum抽象类常见方法

方法 返回类型 说明
compareTo(E o) int 比较此枚举与指定对象的顺序
equals(Object other) boolean 当指定对象等于此枚举常量时,返回 true。
name() String 返回此枚举常量的名称,在其枚举声明中对其进行声明
ordinal() int 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)
toString() String 返回枚举常量的名称,它包含在声明中
getDeclaringClass() Class<?> 返回与此枚举常量的枚举类型相对应的 Class 对象

大概就是这样叭🚀

CATALOG
  1. 1. 说点废话
  2. 2. JAVA的枚举类型
  3. 3. Enum抽象类常见方法