夯实基础 - java基础学习- 枚举类

在某些情况下一个类的对象是有限而且固定的,比如一个季节类的对象只能是春夏秋冬。这种实例有限而且固定的类,在java里被称为枚举类。

手动实现枚举类

在早期代码当中,可能会直接通过简单的静态常量来表示枚举。

public static final int SEASON_SPRING = 1;
public static final int SEASON_SUMMER = 2;
public static final int SEASON_FALL = 3;
public static final int SEASON_WINTER = 4;

这种定义方法简单明了,但存在如下几个问题。

  • 类型不安全,因为上面的每个季节实际上是一个int整数,因此完全可以把一个季节当成一个int整数使用,例如进行加法运算SEASON_SPRING+ SEASON_SUMMER,这样的代码完全正常。
  • 没有命名空间:当需要使用季节时,必须在SPRING前使用SEASON_前缀,否则程序与其他类的静态概念混淆。
  • 打印输出的意义不明确: 当输出某个季节的时候输出值很难猜测其具体含义。

但枚举又确实有存在的意义,因此早期也可而采用定义类的方式来实现,可以采用如下设计方式。

  • 通过private将构造器隐藏起来
  • 把这个类的所有可能实例通过public static final修饰的变量保存。
  • 如果有必要,可以提供一些静态方法,允许其他程序根据特定参数来获取与之匹配的实例。
  • 通过枚举类可以是程序更加健壮,避免创建对象的随意性。

但通过定义类来实现枚举的代码量比较大,实现起来也比较麻烦。

枚举类入门

java可以通过enum关键字(它与class interface关机词的地位相同),用以定义枚举类。正如之前所说,枚举类是一种特殊类,他一样可以拥有自己的成员变量、方法,可以实现一个或者多个的接口,可以定义自己的构造器。一个Java源文件中最多只能定义一个public访问权限的枚举类,且该java源文件也必须和该枚举类的类名相同。

但是枚举类并不是普通类,他和普通类有如下区别。

  • 枚举类可以实现一个或者多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,而不是默认继承Object类,因此枚举类不能显示的继承其他父类。其中java.lang.Enum类实现了java.lang.Serializable和java.lang.Comparable两个接口。
  • 使用enum定义、非抽的枚举类会默认使用final修饰
  • 枚举类的构造器只能使用private访问控制符,如果省略了构造器的访问控制符则默认使用private修饰;如果强制指定访问控制符,则只能指定private修饰符。由于枚举类的构造器都是private的,而子类构造器总要调用父类构造器一次,因此枚举类不能派生子类。
  • 枚举类的所有实例必须在枚举类的第一行显示列出,否则这个枚举类永远都不能产生实例。列出这些实例是,系统会自动添加public static final修饰,无需程序眼显示添加。

枚举类默认提供了一个values()方法,该方法可以很方便地变量所有的枚举值。

下面程序定义了一个SeasonEnum枚举类。

public enum SeasonEnum{
	SPRING,SUMMER,FALL,WINNER;
}

变比上述程序,将会生成一个SeasonEnum.class文件,这表明枚举类是一种特殊的Java类。由此可见,enum关键词与class,interface关键词的作用大致相似。

所有的枚举类都继承自java.lang.Enum类,所以枚举类可以直接使用java.lang.Enum类所包含的方法。Java.lang.enum提供了以下方法。

  • int compareTo(E e):该方法用于与指定枚举对象比较位置,若是位于e后面返回正数,否则返回负数。
  • String name():返回此枚举实例分名称,这个名称就是定义枚举类时列出的所有枚举值之一。
  • int ordinal():返回枚举值在枚举类当中的索引值。
  • public static <T extends Enum<T>> T valueOf(Class<T>enumType,String name): 这个是一个静态方法,用于返回指定枚举类中指定名称的枚举值。名称必须在该枚举类中声明枚举值时所使用的标识符完全匹配,不允许使用额外空白符。

枚举类的成员变量、方法和构造器

枚举类也是一种类,只是它是一种比较特殊的类,因此它一样可以定义成员变量、方法和构造器。

publci enum Gender
{
	MALE,FEMAL;
	public String name;
}

上面枚举类里定义了一个名为name的实例变量,并且将它定义为一个public访问权限。下面将会通过如下程序使用该枚举类

public class GenderTest{
	public static void main(String[] args){
		Gender g = Enum.valueOf(Gender.class, "FEMALE");
		g.name="女";
		System.out.println(g+"代表:" + g.name);
	}
}

上述程序说明使用枚举类与使用普通类并没有太大的区别。

枚举类实现接口

枚举类也可以实现一个或者多个接口。与普通类实现一个或者多个接口完全一样,枚举类实现一个或者多个接口时,也需要实现该接口所包含的方法。

如果枚举类来实现接口里的方法,则每个枚举值在调用该方法时都有相同的行为方式(因为方法体完全一样。)如果需要每个枚举值在调用该方法时呈现出不同的实现方式,从而让不同的枚举值调用该方法时具有不同的行为方式。

public enum Gender implement GenderDesc{
    MALE("男"){
        public void info(){
            System.out.println("这个枚举值代表男性");
        }
    }
    FEMALE("女"){
        public void info(){
            System.out.println("这个枚举值代表女性");
        }
    }
}

上述代码看起来有点奇怪: 当创建MALE和FEMALE两个枚举值时,后面又紧跟了一堆花括号,这对花括号里包含了一个info方法定义。花括号部分实际上就是一个类体部分,在这种情况下,当创建MALE和FEMALE枚举值时,并不是直接创建Gender枚举值的实例,而是创建了Gender类的匿名子类的实例。因为粗体字括号部分实际上时匿名内部类的类体部分,所以这个部分的代码实际上是匿名内部类的类体部分,所以这个部分的代码语法与前面介绍的匿名内部类语法大致相似,只是他依然是枚举类的匿名内部子类。

并不是所有的枚举类都是用final修饰!非抽象的枚举类才默认使用final修饰。对于一个抽象类的枚举类而言——只要它包含了抽象方法,他就是抽象枚举类,系统就会默认使用abstract修饰,而不是使用final修饰。

编译上面的程序可以看到生成了Gender.class、Gender$1.class和Gender$2.class三个文件,这样的三个class文件正好证明了上面的结论:MALE和FEMALE实际上是Gender匿名子类的实例,而不是Gender类的实例。当调用MALE和FEMALE两个枚举值的方法时,就会看到两个枚举值的方法实现不同的行为方式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值