zl程序教程

您现在的位置是:首页 >  其它

当前栏目

枚举类

枚举
2023-09-14 09:04:05 时间

思维导图

点击标题可下载xmind文件

代码练习

import java.util.Arrays;

public class EnumTest {
    public static void main(String[] args) {
        System.out.println(Season.SPRING);
        // 枚举类默认继承java.lang.Enum,可以继承父类的实例方法toString(),name(),values(),valueOf(),compareTo(),ordinary()
        System.out.println(Season.SPRING.toString());
        System.out.println(Season.SPRING.name());
        System.out.println(Arrays.toString(Season.values()));
        System.out.println(Season.valueOf("SPRING"));
        System.out.println(Season.SPRING.compareTo(Season.FALL));
        System.out.println(Season.SPRING.ordinal());
        // 测试枚举类的get方法
        System.out.println(Season.SPRING.getId()+"-"+Season.SPRING.getDesc());
        // 测试枚举类,及实例实现的抽象方法
        Season.SPRING.info();
        Season.SUMMER.info();
        Season.SPRING.test();

        // switch判断的参数可以传入byte,short,char,int,String,枚举类类型数据
        switch(Season.SPRING){
            case WINTER:
                System.out.println("switch winter");
                break;
            case SUMMER:
                System.out.println("switch summer");
                break;
            case FALL:
                System.out.println("switch fall");
                break;
            case SPRING:
                System.out.println("switch spring");
                break;
            default:
                System.out.println("输入非合法季节");
        }
    }
}

// 使用enum关键字定义的枚举类,默认继承java.lang.Enum类
// 枚举类实现接口
// 枚举类包含抽象方法,系统会隐式加abstract修饰,但不能显式加abstract
enum Season implements Info{
    // 枚举类实例必须定义在枚举类定义中第一行,实例间以逗号隔开,以分号结束。
    // 枚举类实例其实是实例名, 类似于 Season SPRING = new Season();
    // 枚举类实例默认使用public static final修饰,即public static final SeaSon SPRING = new Season();
    // 枚举类实例后面是否跟参数,取决与构造器定义
    SPRING(1,"春"){
        @Override
        public void test() {
            System.out.println("测试春天");
        }
    },

    // 枚举类实现接口,也可以基于枚举类实例来重写接口抽象方法
    // 枚举类包含抽象方法,只能基于枚举类实例来重写抽象方法
    /**
     * 基于枚举类实例重写抽象方法,其实是定义枚举类的匿名内部类,即枚举类的子类实例
     * public static final SUMMER = new Season(){
     *     重写抽象方法
     * }
     */
    SUMMER(2,"夏"){
        @Override
        public void info() {
            System.out.println("这是夏天");
        }

        @Override
        public void test() {
            System.out.println("测试夏天");
        }
    },

    FALL(3,"秋"){
        @Override
        public void info() {
            System.out.println("这是秋天");
        }

        @Override
        public void test() {
            System.out.println("测试秋天");
        }
    },

    WINTER(4,"冬"){
        @Override
        public void info() {
            System.out.println("这是冬天");
        }

        @Override
        public void test() {
            System.out.println("测试冬天");
        }
    };

    // 枚举类的成员变量建议使用private final修饰
    private final int id;
    private final String desc;

    // 枚举类的构造器只能使用private修饰,private可以省略
    private Season(int id,String desc){
        this.id = id;
        this.desc = desc;
    }

    // 枚举类只提供get方法,不提供set方法
     public int getId(){
        return id;
     }

     public String getDesc(){
        return desc;
     }

     // 枚举类实现接口可以基于类来实现接口的抽象方法
     public void info(){
         System.out.println("这是季节枚举类");
     }

     // 枚举类包含抽象方法
     public abstract void test();
}

interface Info{
    void info();
}

思考题

1.枚举类是否可以派生子类?

需要分情况讨论
①抽象枚举类可以派生子类
②非抽象枚举类不可以派生子类
具体枚举类啥时候是抽象的,啥时候是非抽象的请看3

2.枚举类的构造器是私有的,那么枚举类如何派生子类? 我们知道子类的构造器最终(子类构造器重载时,总会有一个构造器第一行或隐式调用父类构造器)都会调用父类构造器,但是子类不能访问父类私有成员,而枚举类的构造器是私有。

注意只有抽象枚举类可以派生子类,非抽象枚举类不能派生子类。
我们还需要知道枚举类第一行必须定义该枚举类的实例。
对于抽象枚举类,如定义抽象方法的枚举类
enum Season{
	SPING{
		public void test(){
			System.out.println("spring");
		}
	},
	
	SUMMER{
		public void test(){
			System.out.println("summer");
		}
	},
	
	FALL{
		public void test(){
			System.out.println("fall");
		}
	},
	
	WINTER{
		public void test(){
			System.out.println("winter");
		}
	};
	
	public abstract void test();
}
其中实例SPRING实际上是:
public static final Season SPRING = new Season(){
	public void test(){
		System.out.println("spring");
	}
};
可以看出抽象枚举类的第一行定义的实例,其实是当前枚举类的子类实例(匿名内部类)

所以这个问题的最终答案是:只有抽象枚举类可以派生子类,且只能在本类中以匿名内部类的方式派生子类,并生成实例。
且可以从抽象枚举类编译后生成的字节码文件看出
Season.class,Season$1.class,Season$2.class,Season$3.class,Season$4.class
我们知道匿名内部类编译后就是【外部类名$N.class,其中N是数字】形式

3.如何定义抽象枚举类?直接在定义abstract enum 枚举类名 会怎么样?

定义抽象枚举类不能直接加abstract修饰。会编译报错。
抽象枚举类是指
①实现了接口,但是枚举类没有基于类重写该接口的所有抽象方法
②枚举类中定义了抽象方法
此时枚举类会自动隐式地被abstract修饰

非抽象枚举类是指
没有实现接口或者没有在枚举类中定义抽象方法,非抽象枚举类不能派生子类,自动隐式被final修饰

4.使用enum关键字定义的枚举类为什么不能继承父类?

因为使用enum关键字定义枚举类会自动继承java.lang.Enum类

5.枚举类定义中第一行是该枚举类的实例,那么这些显式定义的实例具体是什么?例如enum Season{SPRING,SUMMER,FALL,WINTER;}中SPING是Season的实例,那么SPRING具体是实例的什么?

SPING是实例名字,具体请看2