Java 枚举(enum) 详解7种常见的用法

Java 枚举(enum) 详解7种常见的用法JDK1.5引入了新的类型——枚举。在Java中它虽然算个“小”功能,却给我的开发带来了“大”方便。大师兄我【大师兄】又加上自己的理解,来帮助各位理解一下。用法一:常量在JDK1.5之前,我们定义常量都是:publicstaticfinal….。现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。Java代码publ…

大家好,又见面了,我是你们的朋友全栈君。

JDK1.5引入了新的类型——枚举。在 Java 中它虽然算个“小”功能,却给我的开发带来了“大”方便。

大师兄我【大师兄】又加上自己的理解,来帮助各位理解一下。

用法一:常量

在JDK1.5 之前,我们定义常量都是: public static final…. 。现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。 

Java代码 

public enum Color {  
  RED, GREEN, BLANK, YELLOW  
} 

用法二:switch

JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。 

Java代码 

enum Signal {  
    GREEN, YELLOW, RED  
}  
public class TrafficLight {  
    Signal color = Signal.RED;  
    public void change() {  
        switch (color) {  
        case RED:  
            color = Signal.GREEN;  
            break;  
        case YELLOW:  
            color = Signal.RED;  
            break;  
        case GREEN:  
            color = Signal.YELLOW;  
            break;  
        }  
    }  
}  

用法三:向枚举中添加新方法

如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。

https://blog.csdn.net/qq_27093465/article/details/52180865

而且 Java 要求必须先定义 enum 实例。 

Java代码 

public enum Color {  
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
    // 成员变量  
    private String name;  
    private int index;  
    // 构造方法  
    private Color(String name, int index) {  
        this.name = name;  
        this.index = index;  
    }  
    // 普通方法  
    public static String getName(int index) {  
        for (Color c : Color.values()) {  
            if (c.getIndex() == index) {  
                return c.name;  
            }  
        }  
        return null;  
    }  
    // get set 方法  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public int getIndex() {  
        return index;  
    }  
    public void setIndex(int index) {  
        this.index = index;  
    }  
}  

用法四:覆盖枚举的方法

下面给出一个toString()方法覆盖的例子。 

Java代码 

public enum Color {  
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
    // 成员变量  
    private String name;  
    private int index;  
    // 构造方法  
    private Color(String name, int index) {  
        this.name = name;  
        this.index = index;  
    }  
    //覆盖方法  
    @Override  
    public String toString() {  
        return this.index+"_"+this.name;  
    }  
}  

用法五:实现接口

所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。 

Java代码 

public interface Behaviour {  
    void print();  
    String getInfo();  
}  
public enum Color implements Behaviour{  
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
    // 成员变量  
    private String name;  
    private int index;  
    // 构造方法  
    private Color(String name, int index) {  
        this.name = name;  
        this.index = index;  
    }  
//接口方法  
    @Override  
    public String getInfo() {  
        return this.name;  
    }  
    //接口方法  
    @Override  
    public void print() {  
        System.out.println(this.index+":"+this.name);  
    }  
}  

用法六:使用接口组织枚举

 Java代码 

public interface Food {  
    enum Coffee implements Food{  
        BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO  
    }  
    enum Dessert implements Food{  
        FRUIT, CAKE, GELATO  
    }  
}  
    /**
     * 测试继承接口的枚举的使用(by 大师兄 or 大湿胸。)
     */
    private static void testImplementsInterface() {
        for (Food.DessertEnum dessertEnum : Food.DessertEnum.values()) {
            System.out.print(dessertEnum + "  ");
        }
        System.out.println();
        //我这地方这么写,是因为我在自己测试的时候,把这个coffee单独到一个文件去实现那个food接口,而不是在那个接口的内部。
        for (CoffeeEnum coffee : CoffeeEnum.values()) {
            System.out.print(coffee + "  ");
        }
        System.out.println();
        //搞个实现接口,来组织枚举,简单讲,就是分类吧。如果大量使用枚举的话,这么干,在写代码的时候,就很方便调用啦。
        //还有就是个“多态”的功能吧,
        Food food = Food.DessertEnum.CAKE;
        System.out.println(food);
        food = CoffeeEnum.BLACK_COFFEE;
        System.out.println(food);
    }

Java 枚举(enum) 详解7种常见的用法运行结果

用法七:关于枚举集合的使用

java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的 key是enum类型,而value则可以是任意类型。关于这个两个集合的使用就不在这里赘述,可以参考JDK文档。

关于枚举的实现细节和原理请参考:

参考资料:《ThinkingInJava》第四版

http://softbeta.iteye.com/blog/1185573

 

我的这篇文章,因为是转载的,可能基本就没有变动,导致被某人踩了一脚。觉得不符合我大师兄的性格。下面我把自己的使用理解给整理一下。

 

也是因为因为当时刚刚开始学习吧。把平时自以为了解的东西都只是大概了解了一下,说到底,还是自以为了解了,其实转眼就不知道什么是什么了。
出来学习,不习惯看代码怎么能行呢?
下面是我自己的测试代码。

package com.lxk.enumTest;

/**
 * Java枚举用法测试
 * <p>
 * Created by lxk on 2016/12/15
 */
public class EnumTest {
    public static void main(String[] args) {
        forEnum();
        useEnumInJava();
    }

    /**
     * 循环枚举,输出ordinal属性;若枚举有内部属性,则也输出。(说的就是我定义的TYPE类型的枚举的typeName属性)
     */
    private static void forEnum() {
        for (SimpleEnum simpleEnum : SimpleEnum.values()) {
            System.out.println(simpleEnum + "  ordinal  " + simpleEnum.ordinal());
        }
        System.out.println("------------------");
        for (TYPE type : TYPE.values()) {
            System.out.println("type = " + type + "    type.name = " + type.name() + "   typeName = " + type.getTypeName() + "   ordinal = " + type.ordinal());
        }
    }

    /**
     * 在Java代码使用枚举
     */
    private static void useEnumInJava() {
        String typeName = "f5";
        TYPE type = TYPE.fromTypeName(typeName);
        if (TYPE.BALANCE.equals(type)) {
            System.out.println("根据字符串获得的枚举类型实例跟枚举常量一致");
        } else {
            System.out.println("大师兄代码错误");
        }

    }

    /**
     * 季节枚举(不带参数的枚举常量)这个是最简单的枚举使用实例
     * Ordinal 属性,对应的就是排列顺序,从0开始。
     */
    private enum SimpleEnum {
        SPRING,
        SUMMER,
        AUTUMN,
        WINTER
    }


    /**
     * 常用类型(带参数的枚举常量,这个只是在书上不常见,实际使用还是很多的,看懂这个,使用就不是问题啦。)
     */
    private enum TYPE {
        FIREWALL("firewall"),
        SECRET("secretMac"),
        BALANCE("f5");

        private String typeName;

        TYPE(String typeName) {
            this.typeName = typeName;
        }

        /**
         * 根据类型的名称,返回类型的枚举实例。
         *
         * @param typeName 类型名称
         */
        public static TYPE fromTypeName(String typeName) {
            for (TYPE type : TYPE.values()) {
                if (type.getTypeName().equals(typeName)) {
                    return type;
                }
            }
            return null;
        }

        public String getTypeName() {
            return this.typeName;
        }
    }
}

然后是测试的结果图:

Java 枚举(enum) 详解7种常见的用法

简单的例子,大家基本都用过,看不懂的基本都是第二个例子。可以看到,在第二个例子里面,后面带有参数,其实可以这么理解。

enum这个关键字,可以理解为跟class差不多,这也个单独的类。可以看到,上面的例子里面有属性,有构造方法,有getter,也可以有setter,但是一般都是构造传参数。还有其他自定义方法。那么在这些东西前面的,以逗号隔开的,最后以分号结尾的,这部分叫做,这个枚举的实例。也可以理解为,class  new 出来的实例对象。这下就好理解了。只是,class,new对象,可以自己随便new,想几个就几个,而这个enum关键字,他就不行,他的实例对象,只能在这个enum里面体现。也就是说,他对应的实例是有限的。这也就是枚举的好处了,限制了某些东西的范围,举个栗子:一年四季,只能有春夏秋冬,你要是字符串表示的话,那就海了去了,但是,要用枚举类型的话,你在enum的大括号里面把所有的选项,全列出来,那么这个季节的属性,对应的值,只能在里面挑。不能有其他的。

我上面的例子,就是根据typeName,你可以从那些例子里面挑选到唯一的一个TYPE类型的枚举实例–TYPE.BALANCE。注意方法

TYPE type = TYPE.fromTypeName(typeName);
这个方法的返回类型就是这个TYPE枚举类型的。
这下就好理解,这个枚举是怎么在工作了吧

再补充一下:

上面那个带参数的枚举类型的实例里面实际上是三个属性,除了我自定义的typeName以外,还有2个是系统自带的。看下面源码的图:

Java 枚举(enum) 详解7种常见的用法

看到这里之后,不知道你能不能理解下面图片内说明的话:下面图片主要说明在使用枚举时,的规范和标准。希望可以在实际开发时候用到

Java 枚举(enum) 详解7种常见的用法

Java 枚举(enum) 详解7种常见的用法

最后补充一点:

也许你知道呢,但是也许你不知道呢?我是真的不知道,测了之后才知道!!!

枚举类型对象之间的值比较,是可以使用==,直接来比较值,是否相等的,不是必须使用equals方法的哟。

具体,请参考下面的链接:

java 枚举类比较是用==还是equals?

2017.11.07 更新

有的老铁,说这个switch case怎么写,我就在下面再啰嗦一下。

    private static void testSwitchCase() {
        String typeName = "f5";
        //这几行注释呢,你可以试着三选一,测试一下效果。
        //String typeName = "firewall";
        //String typeName = "secretMac";
        TypeEnum typeEnum = TypeEnum.fromTypeName(typeName);
        if (typeEnum == null) {
            return;
        }
        switch (typeEnum) {
            case FIREWALL:
                System.out.println("枚举名称(即默认自带的属性 name 的值)是:" + typeEnum.name());
                System.out.println("排序值(默认自带的属性 ordinal 的值)是:" + typeEnum.ordinal());
                System.out.println("枚举的自定义属性 typeName 的值是:" + typeEnum.getTypeName());
                break;
            case SECRET:
                System.out.println("枚举名称(即默认自带的属性 name 的值)是:" + typeEnum.name());
                System.out.println("排序值(默认自带的属性 ordinal 的值)是:" + typeEnum.ordinal());
                System.out.println("枚举的自定义属性 typeName 的值是:" + typeEnum.getTypeName());
                break;
            case BALANCE:
                System.out.println("枚举名称(即默认自带的属性 name 的值)是:" + typeEnum.name());
                System.out.println("排序值(默认自带的属性 ordinal 的值)是:" + typeEnum.ordinal());
                System.out.println("枚举的自定义属性 typeName 的值是:" + typeEnum.getTypeName());
                break;
            default:
                System.out.println("default");
        }
    }

然后,就是运行结果的截图。

Java 枚举(enum) 详解7种常见的用法

老铁们,看完这个枚举,你要懂个概念,那就是,这个枚举,他是个对象,就像你定义的Student类,Person类,等等一些个类一样。

要有这么个概念。只要是个类,他就可以有构造函数,可以有属性,可以有方法。

对的,老铁,你对这个属性,构造函数啥的,有概念吧,没有的话,我可就郁闷啦。

然后,你就看到,这个地方有2个默认的属性,一个是name,一个是ordinal,这2个属性就像你定义Student类和Person类的name和age一样,

只不过,这2个是系统自带的属性,不用你自己去定义啦。

你也可以给这个枚举类,也就是你自己声明的枚举,随便加属性。

我上面代码例子里面的那个TypeEnum那个枚举,就是这么干的,就简单的添加了个自定义属性typeName,

虽然他有自己的name了,那姑且叫我这个自定义的属性叫别名吧。

可以看到,我例子里面就是通过自己写的那个构造方法给我这个自定义的属性初始化值的。

还有,这个构造方法是不可以,也不被运行public的,不信,你可以试试。

还有,你不能对系统自带的name属性,在构造函数里面赋值,没有为什么。

https://blog.csdn.net/qq_27093465/article/details/52180865

(2019-07-29更新)

再补充一点,这个也比较重要

就是这个枚举类型,一旦创建,且被使用(比如,存数据库啥的)之后,持久化后的对象信息里面就保存了这个枚举信息。这个时候你的需求或者要求啥的,需要变更这个枚举名称。应当禁止这个变更的操作,只能重新创建,用新的代替旧的,不能直接把旧的给改了,因为,就数据在逆转成对象的时候,如果,旧的枚举不在了,那么就会400还是500的报错或者是空指针的bug。这也是需要关注的一个问题。希望注意下,不然等到出bug了再想到这个问题,就不好了。

 

我写完文章,给自己点个赞,不过分吧,
不过分,那我可就点啦啊。
我先点为敬,你们随意。大家随意。不要客气。。。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/136232.html原文链接:https://javaforall.net

(0)
上一篇 2022年6月3日 下午10:36
下一篇 2022年6月3日 下午10:36


相关推荐

  • linux查看端口是否被占用的命令是,Linux如何查看端口是否被占用

    linux查看端口是否被占用的命令是,Linux如何查看端口是否被占用Linux如何查看端口是否被占用Linux如何查看端口是否被占用?下面为大家推荐两种检测方法,对Linux系统不熟悉的小伙伴可以看看。1、使用lsof命令lsof是一个非常强大的linux工具,她被用来查找哪些程序使用了那些文件。在linux系统下,基本上所有的东西都可以被当作文件来用。socket当然也是一种文件了。所以lsof可以用来查找谁用了某一个端口。具体方法:lsof-i:port_…

    2025年7月15日
    4
  • OpenClaw本地部署vs云服务器:2026全场景选型与落地实操指南

    OpenClaw本地部署vs云服务器:2026全场景选型与落地实操指南

    2026年3月16日
    3
  • Android – match_parent 和 fill_parent差异

    Android – match_parent 和 fill_parent差异

    2022年1月2日
    59
  • javah 找不到类文件的解决办法

    javah 找不到类文件的解决办法学习 jni 的时候 javacHellowo java 生成 Helloworld class 文件以后 调用 javahHellowo 提示找不到类文件由于 javah 以后生成的 h 文件需要包名 类名 所以必须在包括全包名的目录下执行 javah 命令 也就是项目 src 在或者项目 bin classe 下执行 javah 包名 类名的命令 比如 在 src 下或者 classe 文件夹下执

    2026年3月17日
    1
  • VM虚拟机桥接模式无法联网解决办法

    VM虚拟机桥接模式无法联网解决办法1.背景介绍:桥接模式—-使虚拟机客户机可以和主机在同一网段,这样,和主机同局域网内的其他主机就也可以ping到虚拟机了;因此,虚拟机设置为桥接模式,且设为静态IP,这样以后就可以方便的使用虚拟机了;2.问题描述:桥接模式之前是好用的,但是主机有一天突然宕机了,重启之后,打开虚拟机,发现主机和虚拟机客户机相互之间ping不通;测试:a.将虚拟机IP获取方式改为自

    2022年5月6日
    70
  • osgb转3dtiles之数据篇

    osgb转3dtiles之数据篇前不久 终于对 osgb 以及 3dtiles 的数据结构有了足够的了解 成功地利用 FME 将 osgb 数据转换成了 3dtiles 数据 于是 我开心地决定先来写一下如何将 osgb 转换成 3dtiles 数据 为了让大家能够比较详细的了解这两个数据格式 该系列文章一共分为上下两篇 我将会从 osgb 与 3dtiles 的数据结构以及层级构建两个方面对其进行介绍 下篇仍在酝酿中 所以我们可以先将此篇作为单篇来看 本篇文章 仅讲解 osgb 与 3dtiles 的数据结构 不会涉及到层级等等的介绍 但为了能够成功的看到我们最终转换出来

    2026年2月18日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号