[重学Java基础][类与接口][枚举类]

本文介绍了Java中的枚举类,包括枚举类的优势,如防止非法实例创建,提供类型安全。枚举类的定义和使用,枚举实例的成员变量和方法,以及Enum类的内置方法如valueOf()、values()等。还探讨了枚举类的原理,它是Java的语法糖,编译后实际上是特殊的类。此外,文章提到了枚举类的持久化在JPA中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[重学Java基础][类与接口][枚举类]

前言

枚举类 Java 5 引入 用来代替常量域

什么是常量域

比如你有一组天气信息 需要维护
为了兼顾操作和可读性
编写一个天气常量类
每种天气对应一个final的常量

public class WeatherConst {

    public final int sunny=0;
    public final int cloudy=1;
    public final int overcast=2;
    public final int mist=3;
    public final int dizzle=4;
    public final int snowy=5;
}

这种方法被称为 常量枚举模式
很显然 这种模式存在很大的弊端
它在安全性和使用方便性上没有任何帮助

如果你将一个域之外的值传入到接受的方法中
编译器也不会给出任何警告

为了解决这一问题 Java 5 引入了枚举类
同样 应该也能想到 枚举也有使用集合的需求
所以Java 同时也引入了枚举集合
EnumMap EnumSet

枚举类的优点

相比常量枚举

枚举类有以下优势
- 枚举类是不可继承的 避免出现未知的子类
- 枚举类不可以新建 避免出现未定义的实例

- 常量作为参数时,是String,int等弱类型,开发人员可以传入没有在常量接口里定义的值,编译器无警告。枚举类显然可以克服这一问题

Enum类

定义一个天气枚举类来代替常量枚举

public enum Weather {
    sunny,
    cloudy,
    overcast,
    mist,
    foggy,
    hazy,
    dizzle,
    downpour,
    sleet,
    hailstone,
    shower,
    storm,
    lightsnow,
    snowy
    ;
}

定义枚举类的过程很简单
注意 类关键字是enum而不是class
这样就定义了一个枚举类

然后定义 枚举实例

    sunny,
    cloudy,
    overcast,
    mist,
    ……
    snowy
    ;

枚举实例 就是这些单独的变量 每个以逗号隔开 最后以分号结尾
我们在调用的时候 实际上调用的就是这些枚举实例

和通常的成员变量不同 枚举实例没有修饰符

调用

    Weather weather=Weather.cloudy;

    System.out.println(weather);//cloudy

但这种简单的枚举类并不足够
如果你想要在枚举实例中包含自定义信息呢

比如天气的中文内容 那么你需要这样定义

public enum Weather {
    sunny("晴天"),
    cloudy("多云"),
    overcast("阴天"),
    mist("雾"),
    foggy("霾"),
    hazy("沙尘"),
    dizzle("小雨"),
    downpour("大雨"),
    sleet("雨夹雪"),
    hailstone("冰雹"),
    shower("阵雨"),
    storm("暴风雨"),
    lightsnow("小雪"),
    snowy("雪"),
    snows("雪"),
    ;

    String cnValue;

    Weather(String cnValue) {
      this.cnValue = cnValue;
    }   
}

每个枚举变量后使用括号可以 传入成员变量

这里每个类都传入了 字符串型变量的 中文天气名
那这个字符串变量 在哪里定义的呢
就在枚举类中定义
String cnValue

当然必须同时定义构造方法


    Weather(String cnValue) {
      this.cnValue = cnValue;
    }   

枚举类个构造方法 默认就是私有的
所以 此处也不必添加域修饰符
添加也只能用private修饰 其他会报错

枚举实例 可以添加多个成员变量
比如要在这个天气枚举类中 除了有中文天气名外
还可以使用整形量来指代天气类型

public enum Weather {

    sunny("晴天",0),
    cloudy("多云",1),
    overcast("阴天",2),
    mist("雾",3),
    foggy("霾",4),
    hazy("沙尘",5),
    dizzle("小雨",6),
    downpour("大雨",7),
    sleet("雨夹雪",8),
    hailstone("冰雹",9),
    shower("阵雨",10),
    storm("暴风雨",11),
    lightsnow("小雪",12),
    snowy("雪",13)
    ;

    private String cnValue;
    private Integer weatherId;

    Weather(String cnValue,Integer weatherId) {
        this.cnValue = cnValue;
        this.weatherId=weatherId;
    }
}

在枚举实例中 添加了整型值 同时在枚举类中定义private Integer weatherId
构造函数也同时添加了整型入参

同时可以添加get方法以获取这些属性

    public String getCnValue() {
        return cnValue;
    }

    public Integer getWeatherId() {
        return weatherId;
    }

调用的时候

      System.out.println(Weather.snowy.getWeatherId());//13
      System.out.println(Weather.snowy.getCnValue());//雪

Enum的原理

枚举类为什么会有如此特殊的形式 和Java 普通类差别这么大
其实 枚举类是个Java的语法糖 是特殊包装的普通Java类
反编译枚举类的class文件就会发现真相

public final class Weather extends Enum{
    private Weather(String cnValue,Integer weatherId){
        this.cnValue= cnValue;
        this.weatherId= weatherId;
    }

    public String getCnValue() {
        return cnValue;
    }

    public Integer getWeatherId() {
        return weatherId;
    }

    private int weatherId;
    private String cnValue;

    static {
        sunny= new Weather("晴天", 0);
        cloudy= new Weather("多云", 1);
        overcast= new Weather("阴天",2);
        mist= new Weather("雾",3);
        foggy= new Weather("霾",4);
        hazy= new Weather("沙尘",5);
        dizzle= new Weather("小雨",6);
        downpour= new Weather("大雨",7);
        sleet= new Weather("雨夹雪",8);
        hailstone= new Weather("冰雹",9);
        shower= new Weather("阵雨",10);
        storm= new Weather("暴风雨",11);
        lightsnow= new Weather("小雪",12);
        snowy = new Weather("雪",13)
    }
}

看了反编译的源码后 什么都明白了

为什么枚举类不能被继承 因为枚举类已经是final的了
为什么枚举类不能继承其他类 因为枚举类已经继承了枚举基类enum

每个枚举常量 为什么可以用括号内容的形式 定义自定义变量
并且 此时要在枚举类中添加 成员属性和构造方法

因为 每个枚举实例就是编译器在枚举类的静态块中
实例化的枚举类实例 同时通过构造方法传入你自定义的参数

所以枚举类必须要有构造方法 成员变强且和枚举实例的变量列表相同

既然知道 枚举实例是枚举类的实例化

那么枚举类定义的方法 枚举实例自然也可以重写

public enum Weather {

    sunny("晴天",0){
        @Override
        public void printWeather() {
            System.out.println("今天天气是"+this.getCnValue());
        }
    },
    cloudy("多云",1),
    ……
    ;
    ……

    public void printWeather(){
     System.out.println(this.getCnValue());
    }
}

此处定义一个打印天气方法
sunny这个枚举实例 重写方法内容

那么能不能定义抽象方法呢
可以的

public enum Weather {

    sunny("晴天",0){
        @Override
        public void printWeather() {
            System.out.println("晴天好");
        }
    },
    cloudy("多云",1){
        @Override
        public void printWeather() {
            System.out.println("多云天气不炎热");
        }
    },
    ……
    ;
    ……

    public abstract void printWeather(){
     System.out.println(this.getCnValue());
    }
}

如果定义了 抽象方法 则所有枚举实例的都必须重写此方法

反编译 可知
此时的 枚举类是

public abstract class Weather extends Enum{
  ……
}

此时的枚举类 是一个抽象类

Enum类的方法

valueOf() 方法:

接收一个字符串,然后将它转变为对应的枚举变量,区分大小写。
如果传入的字符串变量在枚举实例中找不到对应的 将会抛出异常

 Weather weather=Weather.valueOf("overcast");
        System.out.println(weather);//overcast

values()方法。

返回所有的枚举实例 多用于遍历枚举类

        for (Weather weather : Weather.values()) {
            System.out.println(weather);
        }

toString()方法。

直接返回枚举定义枚举变量的字符串

        System.out.println(Weather.hailstone.toString());
        //hailstone

当然你也可以自己重写toString()方法

name()方法。

和toString()方法作用完全一致 区别就是可以重写toString()方法

ordinal()方法。

枚举类会给所有的枚举变量一个默认的次序,该次序从0开始,类似于数组的下标。而ordinal()方法就是获取这个次序(或者说下标)
重点事 此方法只会返回默认的次序 不能重新定义次序
所以《Effective Java》就建议不要使用此方法
自己定义整型变量代替

compareTo()方法。

该方法用来比较两个枚举变量的”大小”,实际上比较的是两个枚举变量的次序(ordinal),返回两个次序相减后的结果,如果为负数,就证明变量1”小于”变量2

所以 一般也不要使用此方法

使用接口组织枚举

public interface Weathers {

    String forecast();

    public enum snows implements Weathers{
        storm, lightsnow,snow;

        @Override
        public String forecast() {
            return this.name();
        }
    }

    public enum rains implements Weathers{
        dizzle, downpour,sleet,shower;

        @Override
        public String forecast() {
            return this.name();
        }
    }

    public enum overcast implements Weathers{
        cloudy, overcast, mist, foggy, hazy;

        @Override
        public String forecast() {
            return this.name();
        }
    }
}

将枚举类放入接口 统一组织和管理

Enum类的持久化

在JPA中 可以使用枚举注解 @Enumerated来持久化枚举类

@Entity
@Data
@Table(name = "t_weather")
@DynamicInsert
@DynamicUpdate
@Builder
public class WeatherPO {


    @Id
    private Integer Id;

    private String cnValue;

    private Timestamp intime;

    @Enumerated(EnumType.STRING)
    private Weather weather;

}

@Enumerated 注解有两个选项
EnumType.STRING
EnumType.ORDINAL
显然STRING是返回枚举的name值
而ORDINAL是默认的序列编号

所以一般使用EnumType.STRING

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值