再谈java枚举enum

一、认识枚举

枚举是一种特殊类

枚举的定义:

修饰符 enum 枚举名 {
       枚举项1,枚举项2,枚举项3;
       其他成员;
}

注意:

  • 枚举的第一行只能写枚举项,多个枚举项用逗号(,),隔开
  • 每一个枚举项都是一个常量(不可改变值),且都指向一个该枚举的对象

二、为什么要使用枚举

例如,有这么一方法,需要获取男孩和女孩的一些特征。传入男孩,就返回男孩的信息,传入女孩,就返回女孩的信息。

我们来看以下几种方法实现。

方法一

我们用1表示男孩,2表示女孩,代码如下:

package org.example.enumX;

public class Example2 {
    public static void main(String[] args) {
        choseStudent(1);
    }
    public static void choseStudent(int sex){
        switch (sex){
            case 1:
                System.out.println("男孩的特征");
                break;
            case 2:
                System.out.println("女孩的特征");
                break;
            default:
                System.out.println("参数错误");
        }
    }
}
// 程序输出:男孩的特征

以上代码虽然实现了业务逻辑,但是方法传1和传2并不能让人很快理解该值的意思,甚至我们可以传3,4,5,6,7 没有任何限制。

为了让代码更容易理解, 我们吧男孩和女孩封装到一个类里面,如下,方法二

方法二

同样,用1表示男孩,2表示女孩,只是我们把信息封装到一个类里面了。

package org.example.enumX;
class StudentA{
    public static final int boy = 1;
    public static final int girl = 2;
}

public class Example1 {
    public static void main(String[] args) {
        choseStudent(StudentA.boy);
    }
    public static void choseStudent(int sex){
        switch (sex){
            case 1:
                System.out.println("男孩的特征");
                break;
            case 2:
                System.out.println("女孩的特征");
                break;
            default:
                System.out.println("参数错误");
        }
    }
}

以上代码,我们就很清楚参数传入的是一个男孩,代码可读性变好了。但是我们仍然能够传其他的int类型值。

为了限制该方法传值的问题,于是我们引入了枚举,如下方法三:

方法三

使用枚举来实现该功能

package org.example;

enum StudentB{
    BOY,GIRL
}

public class Example3 {
    public static void main(String[] args) {
        choseStudent(StudentB.BOY);
    }
    public static void choseStudent(StudentB sex){
        switch (sex){
            case BOY:
                System.out.println("男孩的特征");
                break;
            case GIRL:
                System.out.println("女孩的特征");
                break;
            default:
                System.out.println("参数错误");
        }
    }
}

这样不仅提高了代码的可读性,也限制了调用者对该方法的传值。

枚举的底层原理

我们将方法二中的类声明为final 防止继承,同事将构造方法声明为private以防止外部实例化。这样我们就可以保证,再程序内Student就只能有我们定义好的常量。如下:

package org.example.enumX;

final class StudentD{
    public static final StudentD BOY = new StudentD();
    public static final StudentD GIRL =  new StudentD();
    private StudentD(){}
}

通过上面的代码,我们也能限制调用者传递的内容。以上代码就类似为枚举的原理。

我们将方法三中的StudentB 枚举类的class文件进行反编译,可以看到如下代码:

PS D:\project\IDEAjava\testPro\demos\target\classes\org\example> javap .\StudentB.class
Compiled from "Example3.java"
final class org.example.StudentB extends java.lang.Enum<org.example.StudentB> {
  public static final org.example.StudentB BOY;
  public static final org.example.StudentB GIRL;
  public static org.example.StudentB[] values();
  public static org.example.StudentB valueOf(java.lang.String);
  static {};
}

 带参数的枚举项

由于每一个枚举项都是该枚举的一个实例,因此我们给枚举定义了构造方法之后,枚举项在实例化的时候就可以带上参数了

package org.example.test;

enum StudentD{
    BOY("男","短头发"),  
    GIRL("女","长头发");

    private final String sex;
    private final String hair;

    private StudentD(String sex,String hair){
        this.sex = sex;
        this.hair = hair;
    }

    public String getInfo(){
        String info = "性别:" + this.sex + "头发:" + this.hair;
        return info;
    }
}
public class Example4 {
    public static void main(String[] args) {
        choseStudent(StudentB.GIRL);
    }
    public static void choseStudent(StudentB stu){
        switch (stu){
            case BOY:
                System.out.println("男孩的特征:" + StudentD.BOY.getInfo());
                break;
            case GIRL:
                System.out.println("女孩的特征:" + StudentD.GIRL.getInfo());
                break;
            default:
                System.out.println("参数错误");
        }
    }
}

运行结果:

女孩的特征:性别:女头发:长头发

posted @ 2024-10-13 23:00  远洪  阅读(7)  评论(0编辑  收藏  举报