深入枚举enum了解

枚举enum讲解



前言

枚举一般表示一组常量,比如春夏秋冬、东南西北等等。


一、实例:季节枚举

1. 声明枚举

枚举表示一个类的有限个实例化对象,比如谈到季节,你只能列举出春、夏、秋、冬四种情况;谈到星期几,你只能列举出星期一到星期天7种情况。

enum SeasonEnum {
    
    
    /*
     *枚举春、夏、秋、冬四种季节
     */
    SPRING,SUMMER,AUTUMN,WINTER;
}

枚举允许定义在类的外部、内部,同项目下的文件也是可以引用的,调用前import一下即可。

// 外部
enum MyEnum {
    
    }

public MyClass {
    
    }

// 内部
public MyClass {
    
    
enum MyEnum {
    
    }

}

// 引用
// 文件enums.MyEnum.java
package enums;
enum MyEnum {
    
    }

// 文件MyClass.java
import *.enums.SeasonEnum;
public MyClass {
    
    }

如果同时存在重名的enum,类内部的会覆盖外部的;引用的会覆盖以上两种,且如果项目别处已经存在该名enum,会报编译错误,直至正确导入该enum所在的.java文件。

2. 枚举的调用

public class Main {
    
    
    public static void main(String[] args) {
    
    
        System.out.println(SeasonEnum.SPRING);
    }
}

结果:SPRING

枚举enum是一种特殊的类class,且默认强制是具体的、动态的、不可继承的(不允许使用abstract、static、final修饰,会报编译错误);

枚举在.java文件中与类的规则相同:至多有一个class(enum)被public修饰,并且该class(enum)必须与.java文件名一致。

3. 枚举的本质

每个枚举都是通过 class 在内部实现的,且所有的枚举值都是 public static final 的。
以上的枚举类 SeansonEnum转化在内部类实现:

class SeasonEnum {
    
    
     public static final SeasonEnum SPRING = new SeasonEnum();
     public static final SeasonEnum SUMMER = new SeasonEnum();
     public static final SeasonEnum AUTUMN = new SeasonEnum();
     public static final SeasonEnum WINTER= new SeasonEnum();
}

这就能解释为什么SeasonEnum为什么默认强制是动态的(静态类无法实例化——不能new)。
至于为什么是final,final表示不可继承的,被修饰的类不能拥有子类。子类本身就表示对父类规范的扩展。而枚举本身就是对完整规范的具体实现,再让子类去继承枚举的话就本末倒置了。

4. values()、ordinal() 和 valueOf() 方法

枚举中默认存在的方法(不需要自定义也能调用)。
enum 定义的枚举类默认继承了 java.lang.Enum 类,并实现了 java.lang.Serializable 和 java.lang.Comparable 两个接口。

values(), ordinal() 和 valueOf() 方法位于 java.lang.Enum 类中:

  • values() 返回枚举类中所有的值。
  • ordinal()方法可以找到每个枚举常量的索引,就像数组索引一样。
  • valueOf()方法返回指定字符串值的枚举常量。

实例

enum SeasonEnum {
    
    
    // 此处的SPRING相当于SPRING()无参构造方法
    // 在{}代码块中要具体实现所有的抽象方法
    SPRING {
    
    
        @Override
        public void months() {
    
    
            System.out.println("This season includes March, April and May.");
        }

    },
    // 此处是调用SUMMER(String)构造方法
    SUMMER("hot") {
    
    
        @Override
        public void months() {
    
    
            System.out.println("This season includes June, July and August.");
        }

    }, AUTUMN {
    
    
        @Override
        public void months() {
    
    
            System.out.println("{This season includes September, October and November.");
        }

    }, WINTER {
    
    
        @Override
        public void months() {
    
    
            System.out.println("This season includes December, January and February.");
        }

    };

    // 变量的声明和普通类一样
    // 建议充分封装对象,使用private修饰,对外提供get()、set()方法。
    private String description;

    // 有参构造
    SeasonEnum(String adjective) {
    
    
        this.description = adjective;
        System.out.println("Constructor called for : " + this.toString());
    }

    // 构造方法,不写private也不会报错
    // 无参构造,如果没有声明任何一个构造方法则会默认生成一个无参构造
    SeasonEnum() {
    
    
        System.out.println("Constructor called for : " + this.toString());
    }

    public void descriptor() {
    
    
        System.out.println("This season is " + getDescription() + ".");
    }

    public String getDescription() {
    
    
        return description;
    }

    // 抽象方法,每个枚举对象中必须具体实现这个方法,否则会报编译错误
    // 抽象方法只能声明在抽象类里,但enum自己声明抽象方法,自己具体实现,这也是enum的特殊之处之一
    public abstract void months();
}

public class Main {
    
    
    public static void main(String[] args) {
    
    
        SeasonEnum season1 = SeasonEnum.SPRING;
        System.out.println(season1);
        season1.descriptor();
        season1.months();

        SeasonEnum season2 = SeasonEnum.SUMMER;
        season2.descriptor();
        season2.months();
    }

}


执行以上代码输出结果为:

Constructor called for : SPRING
Constructor called for : SUMMER
Constructor called for : AUTUMN
Constructor called for : WINTER
SPRING
This season is null.
This season includes March, April and May.
This season is hot.
This season includes June, July and August.

5. 迭代枚举元素

可以使用 for 语句来迭代枚举元素:

实例

enum SeasonEnum {
    
    
    SPRING, SUMMER, AUTUMN, WINTER;
}

public class MyClass {
    
    
    public static void main(String[] args) {
    
    
        for (SeasonEnum season : SeasonEnum.values()) {
    
    
            System.out.println(season);
        }
        
    }
    
}

执行以上代码输出结果为:

SPRING
SUMMER
AUTUMN
WINTER

6. 在 switch 中使用枚举类

枚举类常应用于 switch 语句中:

实例

enum SeasonEnum {
    
    
    SPRING, SUMMER, AUTUMN, WINTER;
}

public class MyClass {
    
    
    public static void main(String[] args) {
    
    
        SeasonEnum season= SeasonEnum.SPRING;

        switch (season) {
    
    
            case SPRING:
                System.out.println("春天");
                break;
            case SUMMER:
                System.out.println("夏天");
                break;
            case AUTUMN:
                System.out.println("秋天");
                break;
            case WINTER:
                System.out.println("冬天");
                break;
            default:
                break;
        }

    }

}

执行以上代码输出结果为:

春天


总结

枚举是一种特殊的类,区别在于:

  1. 会在内部创建有限个实例化对象,且不能再创建新的对象。

因为实例化对象的权限在自己手里(构造方法是私有的)。

  1. 调用时是直接调用实例化好的静态对象,enum本身在创建完所有的枚举对象后就完成了全部工作。
  2. 如果想让枚举中不同实例的同名方法实现不同内容,可以声明抽象方法,抽象方法最后在各个实例中的实现是互不相关的。

enum可以声明抽象方法,抽象方法只能在抽象类中声明;
enum可以实例化对象,只有非抽象的具体类才能实例化。
看似有些矛盾。
个人更倾向于enum是具体类而不是抽象类,抽象类无法实例化,而enum最重要的产物就是实例化出的对象。
而enum中的抽象方法被强制在各对象中具体实现,就是设计者对于矛盾的最终解决,也是enum区别于class的关键点之一。
编程语言中会存在很多矛盾点,设计者一定会给出一个最终规则,所以了解最终规则即可,不必纠结,类比法只是便于理解,不要反被其束缚。

猜你喜欢

转载自blog.csdn.net/War_wick/article/details/127793442