专栏首页测试技术圈Junit单元测试遇见的一个枚举类型的坑(枚举类型详解)

Junit单元测试遇见的一个枚举类型的坑(枚举类型详解)

Enum的简介

枚举类型很早就在计算机语言中存在了,主要被用来将一组相似的值包含进一种类型中,这种类型的名称被定义成独一无二的类型描述符,这就是枚举类型。

在java语言中,枚举类型是一个完整功能的类,允许开发者给枚举类型添加方法和属性,同时也可以提供接口。同时Java也为Enum提供了高质量的实现,比如comparable和Serializable接口.

* 其中:Comparable 是排序接口,如果一个Java类有这个接口,那么只能说明这个类支持排序。即然实现Comparable接口的类支持排序,假设现在存在“实现Comparable接口的类的对象的List列表(或数组),则该List列表(或数组)可以通过 Collections.sort(或 Arrays.sort)进行排序。“实现Comparable接口的类的对象”可以用作“有序映射(如TreeMap)”中的键或“有序集合(TreeSet)”中的元素,而不需要指定比较器。Serializable接口的对象转换成一个字符序列,并能够在以后将这个字节序列完全恢复为原来的对象。而且这个过程是可以通过网络完成的,也就是说序列化机制能够自动弥补不同操作系统之间差异。*

Enum的定制

通过类的定义,可以给Enum一些复杂的功能,例如下面代码给Enum增加属性:

public enum DrinkEnum{

// 酒
Wine("a cup of wine ");
//橙汁
Oragen_Juice("a cup of oragen juice")
//Enum对象的drink_class属性
private String drink_class;
//枚举对象构造函数
private DrinkEnum(String drink){
    this.drink_class=drink;
}
//枚举对象的drink_class属性
public String getDrink(){
    return this.drink_class;
}

Enum的一些坑

1 Enum 不支持public和protected修饰符的构造方法,因此构造函数一定要是private或者friendly的,这也就约束了枚举对象是无法在程序中通过直接调用构造函数进行初始化的。
2 Enum的值是通过运行期构造出来的对象表示的,因此在集群环境下,每个jvm构造出同义对象,但是在做布尔运算的时候有可能有问题,因此要格外注意。在对Enum进行比较的时候,使用值比对。

Enum的原理

在使用enum创建枚举类型后,编译器会为其生成一个对应的枚举类,这个类继承与java.lang.Enum。举例如下:

enum Day {
    MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

编译后会变成Day.class,那么测者反编译后看到如下:

final class Day extends Enum
{
    //编译器为我们添加的静态的values()方法
    public static Day[] values()
    {
        return (Day[])$VALUES.clone();
    }
    //编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
    public static Day valueOf(String s)
    {
        return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);
    }
    //私有构造函数
    private Day(String s, int i)
    {
        super(s, i);
    }
     //前面定义的7种枚举实例
    public static final Day MONDAY;
    public static final Day TUESDAY;
    public static final Day WEDNESDAY;
    public static final Day THURSDAY;
    public static final Day FRIDAY;
    public static final Day SATURDAY;
    public static final Day SUNDAY;
    private static final Day $VALUES[];
    static 
    {    
        //实例化枚举实例
        MONDAY = new Day("MONDAY", 0);
        TUESDAY = new Day("TUESDAY", 1);
        WEDNESDAY = new Day("WEDNESDAY", 2);
        THURSDAY = new Day("THURSDAY", 3);
        FRIDAY = new Day("FRIDAY", 4);
        SATURDAY = new Day("SATURDAY", 5);
        SUNDAY = new Day("SUNDAY", 6);
        $VALUES = (new Day[] {
            MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
        });
    }
}

可以看到,编译后生成一个final类,同时前面的七个日期定义成七个类型。同时还有两个静态方法,分别是values()和 valueOf(),MONDAY枚举类型对应public static final Day MONDAY;,values()方法的作用就是获取枚举类中的所有变量,并作为数组返回,而valueOf(String name)方法与Enum类中的valueOf方法的作用类似根据名称获取枚举变量,只不过编译器生成的valueOf方法更简洁些只需传递一个参数。由于values()方法是由编译器插入到枚举类中的static方法,所以如果我们将枚举实例向上转型为Enum,那么values()方法将无法被调用,因为Enum类中并没有values()方法,valueOf()方法也是同样的道理。

final变量经常和static关键字一起使用,作为常量。final类通常功能是完整的,不允许被继承。

因此枚举类型,在调用中如果对内部变量使用了set函数,那么就是对一个常量进行了上set操作,也就会导致所有调用的地方的值都发生了变化。

EnumSet和EnumMap

EnumSet

EnumSet是一个针对枚举类型的高性能Set接口实现,但是在其中装入的枚举类型必须是同类型的,在EnumSet中通过bit-vector实现,也就是一个long型。EnumSet支持在遍历。

for (WeekDayEnum day:EnumSet.range(WeekDayEnum.Mon,WeekDayEnum.Sun)){
    System.out.println(day)
}

同时EnumSet还提供了一个获取子集的方法:

EnumSet <WeekDayEnum> JobDays =  EnumSet.of(WeekDayEnum.Mon,WeekDayEnum.Fri);

EnumMap

EnumMap是一个高性能的Map接口实现,主要管理用枚举做Key-Value的关系,内部是通过数组方式实现的。

private static Map<WeekDayEnum,RainbowClolor> schema = new EnumMap<WeekDayEnum.values()[i],RainbowClolor.values()[i]>(WeekDatEnum.class);

转自:https://blog.csdn.net/crisschan

本文分享自微信公众号 - V社 北京社(SoftwareTesters),作者:Black spider 525

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 窥视WebSocket传输的内容(Fiddler抓取)

    Fiddler(中文名称:小提琴)是一个HTTP的调试代理,以代理服务器的方式,监听系统的Http网络数据流动,Fiddler可以也可以让你检查所有的HTTP通...

    Criss@陈磊
  • 一次性搞清楚线上CPU100%,频繁FullGC排查套路

    处理过线上问题的同学基本上都会遇到系统突然运行缓慢,CPU 100%,以及 Full GC 次数过多的问题。

    Criss@陈磊
  • 基于Fiddler的APP抓包及服务端模拟

    如果我们可以拿到项目组的接口文档,并且HTTP后台服务是可以工作的,那我们的接口测试会非常顺利,可以不使用Fiddler工具。

    Criss@陈磊
  • PHP使用类“单例”静态变量提高效率

    蛋未明
  • 使用PHP生成ICO图标

    今天教大家如何使用PHP生成ico图标,ico图标在每个网站中都需要用到的,使用方法也是很简单的,基本上以下面的方式为主,还有其他的方式。

    申霖
  • 【小工匠聊密码学】--对称加密--3DES

      3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于...

    Java小工匠
  • 物联网资产暴露情况—IPv6拿起接力棒

    《2018物联网安全年报》中,我们对物联网资产的网络地址变化情况进行了分析,得到了物联网资产的实际暴露情况,年报第二章首先对去年的数据进行了更新。国内来看,暴露...

    绿盟科技研究通讯
  • Python/PyMC3/ArviZ贝叶斯统计实战(下)

    在上半部分中,我们了解了贝叶斯方法步骤和高斯推论,也将贝叶斯方法应用到一个实际问题中,今天我主要介绍贝叶斯在Python中实现最终的后验分布。

    AiTechYun
  • 还在使用 SimpleDateFormat?你的项目崩没?

    日常开发中,我们经常需要使用时间相关类,说到时间相关类,想必大家对SimpleDateFormat并不陌生。主要是用它进行时间的格式化输出和解析,挺方便快捷的,...

    芋道源码
  • 还在使用SimpleDateFormat?你的项目崩没?

    日常开发中,我们经常需要使用时间相关类,说到时间相关类,想必大家对SimpleDateFormat并不陌生。主要是用它进行时间的格式化输出和解析,挺方便快捷的,...

    格姗知识圈

扫码关注云+社区

领取腾讯云代金券