1、引入
【1】数学:枚举法:
1<x<4
2<y<5
求x+y=6
枚举法:一枚一枚的列举出来。前提:有限,确定
【2】在java中,类的对象是有限个,确定的。这个类我们可以定义为枚举类。
举例:
星期:一二三四五六日
性别:男女
季节:春夏秋冬
【3】自定义枚举类:(JDK1.5之前自定义枚举类)
代码示例:
Season类:
package test5_Enum;
/**
* @Auther: zhoulz
* @Description: 定义枚举类:季节
* @version: 1.0
*/
public class Season {
//属性
//private final String seasonName = "春天";//季节名字
//private final String seasonDesc = "出暖花开";//季节描述
//季节都是确定的,可以说是常量,因此要赋值
//但是赋值后,就无法更改了,即不能向上面那么写,
// 怎么办:利用构造器
private final String seasonName;//季节名字
private final String seasonDesc;//季节描述
//利用构造器对属性进行赋值操作:
//构造器私有化,外界不能调用这个构造器,只能Season内部自己调用
Season(String seasonName,String seasonDesc){
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//提供枚举类的有限的、确定的对象:
//Season spring = new Season("春天","春暖花开");
//改为:
//public static - 为了外界能调用,且Season. 直接调用;final - 外界不能该;SPRING - 常量的话,就大写。
public static final Season SPRING = new Season("春天","春暖花开");
public static final Season SUMMER = new Season("夏天","烈日炎炎");
public static final Season AUTUMN = new Season("秋天","硕果累累");
public static final Season WINTER = new Season("冬天","冰天雪地");
//上面基本创建好了枚举类
//额外因素:
//因为都是常量,且值都设置好了,所以不用set()方法了
//但可以有get()方法
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
//还可以有toString()方法
@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
}
测试类:Test1
package test5_Enum;
/**
* @Auther: zhoulz
* @Description: test5_Enum
* @version: 1.0
*/
public class Test1 {
public static void main(String[] args) {
Season summer = Season.SUMMER;
System.out.println(summer/*.toString()*/);
//相当于:
System.out.println(summer.toString());
System.out.println(summer.getSeasonName());
}
}
2、JDK1.5之后使用enum关键字来创建枚举类
较之前自定义的枚举类:
变为下面的枚举类:
代码示例:
package test6_Enum_2;
/**
* @Auther: zhoulz
* @Description: 定义枚举类:季节
* @version: 1.0
*/
public enum Season {
//提供枚举类的有限的、确定的对象:—— enum枚举类要求对象(常量)必须放在最开始位置
//然后,改成:
//多个对象之间用,进行连接,最后一个对象后面用;结束
SPRING ("春天","春暖花开"),
SUMMER ("夏天","烈日炎炎"),
AUTUMN ("秋天","硕果累累"),
WINTER ("冬天","冰天雪地");
//属性
private final String seasonName;//季节名字
private final String seasonDesc;//季节描述
//利用构造器对属性进行赋值操作:
//构造器私有化,外界不能调用这个构造器,只能Season内部自己调用
Season(String seasonName, String seasonDesc){
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//上面基本创建好了枚举类
//额外因素:
//因为都是常量,且值都设置好了,所以不用set()方法了
//但可以有get()方法
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
//还可以有toString()方法
@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
}
同样,定义好了枚举类,我们就可以使用了。
使用枚举类:
代码示例:
package test6_Enum_2;
/**
* @Auther: zhoulz
* @Description: test6_Enum_2
* @version: 1.0
*/
public class TestSeason {
public static void main(String[] args) {
Season winter = Season.WINTER;
System.out.println(winter);
//将重写后的toString()方法注释后,得到输出后的 winter为 WINTER
//而在之前自定义的枚举中,如果将重写后的toString()方法注释,
//得到的结果为:test5_Enum.Season@14ae5a5
//而结果WINTER 说明打印的不是一个地址,从而说明enum定义的Season不是继承自Object
//获取其父类:
System.out.println(Season.class.getSuperclass().getName());//结果:java.lang.Enum
//enum关键字对应的枚举类的上层父类是 :java.lang.Enum
//但是我们自定义的枚举类的上层父类:Object
}
}
在源码中经常看到别人定义的枚举类形态:
public enum Season {
SPRING,
SUMMER,
AUTUMN,
WINTER;
}
为什么这么简单:因为这个枚举类底层没有属性,属性,构造器,toString,get方法都删掉不写了,然后案例来说应该写为:SPRING() , 现在连()都可以省略了, 就变成 SPRING。
看到的形态就剩:常量名(对象名)
举例:
Thread中的枚举类:State
代码示例:
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
3、Enum类的常用方法
代码示例:
Season枚举:
public enum Season {
SPRING,
SUMMER,
AUTUMN,
WINTER;
}
测试类:
package test7_Enum_3;
/**
* @Auther: zhoulz
* @Description: test7_Enum_3
* @version: 1.0
*/
public class TestSeason {
public static void main(String[] args) {
//用enum关键字创建的Season枚举类上面的父类是:java.lang.Enum,
//其下的常用方法,子类Season可以直接拿过来使用:
//1、toString() —— 获取对象的名字
Season autumn = Season.AUTUMN;
System.out.println(autumn/*.toString()*/); //AUTUMN
System.out.println("----------");
//2、values() —— 返回枚举类对象的数组
//values()是静态的,所以直接Season. 去调
Season[] values = Season.values();
//使用增强for循环,对values进行遍历
//对values进行遍历,然后用Season s 去接收
for (Season s:values){
System.out.println(s.toString());
}
System.out.println("----------");
//3、valueOf() —— 通过对象名字获取这个枚举对象
//注意:对象的名字必须传正确,否则抛出异常
//注意:valueOf()方法 要求传入的是一个String name (字符串对象) ,
// 然后返回的是一个Season对象
Season autumn1 = Season.valueOf("AUTUMN");
System.out.println(autumn1);
}
}
4、枚举类实现接口
(1)首先,定义一个接口:
代码示例:
package test8_Enum_4_implement_interface;
/**
* @Auther: zhoulz
* @Description: test8_Enum_4_implement_interface
* @version: 1.0
*/
public interface TestInterface {
void show();
// 接口体中只进行方法的声明,不允许提供方法的实现,
// 方法的定义没有方法体,且用分号结尾
}
(2)然后,创建一个枚举类实现接口,并且重写show方法:
代码示例:
package test8_Enum_4_implement_interface;
/**
* @Auther: zhoulz
* @Description: test8_Enum_4_implement_interface
* @version: 1.0
*/
public enum Season implements TestInterface{
SPRING,
SUMMER,
AUTUMN,
WINTER;
//实现接口,必须要对里面的抽象方法进行重写:
@Override
public void show(){
System.out.println("这是Season!!!");
}
}
(3)最后,创建测试类:
代码示例:
package test8_Enum_4_implement_interface;
/**
* @Auther: zhoulz
* @Description: test8_Enum_4_implement_interface
* @version: 1.0
*/
public class Test1 {
public static void main(String[] args) {
Season autumn = Season.AUTUMN;
autumn.show();
//同理
Season summer = Season.SUMMER;
summer.show();
}
}
结果发现:
所有创建的枚举对象,调用这个show方法的时候,走的都是同一个方法,结果都一样:
但是现在要求:
不同的对象 调用的show方法也不同。
代码示例:
测试类:同上
枚举类:
package test8_Enum_4_implement_interface;
/**
* @Auther: zhoulz
* @Description: test8_Enum_4_implement_interface
* @version: 1.0
*/
public enum Season implements TestInterface{
SPRING{
@Override
public void show() {
System.out.println("这是春天!!!!");
}
},
SUMMER{
@Override
public void show() {
System.out.println("这是夏天!!!");
}
},
AUTUMN{
@Override
public void show() {
System.out.println("这是秋天!!");
}
},
WINTER{
@Override
public void show() {
System.out.println("这是冬天!");
}
};
//实现接口,必须要对里面的抽象方法进行重写:
/*@Override
public void show(){
System.out.println("这是Season!!!");
}*/
}
结果:
5、实际应用
代码示例:
Person类:
package test9_Enum_5_practical_application;
/**
* @Auther: zhoulz
* @Description: test9_Enum_5_practical_application
* @version: 1.0
*/
public class Person {
//属性
private int age;
private String name;
//private String sex;
//不用属性sex:
private Gender sex;
//set、get方法:
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/*public String getSex() {
return sex;
}
public void setSex(String sex) {
if (sex == "男" || sex == "女"){ //更好?:if (sex.equals("男") || sex.equals("女"))
this.sex = sex;
}
else{
this.sex = "性别设置无效!";
System.out.println("请您重新设置性别!!!");
}
}*/
//
//提供对应的枚举类的对象的set、get方法
public Gender getSex() {
return sex;
}
public void setSex(Gender sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
'}'; //记住把sex注释掉,创建了Gender sex后就会报错了
}
}
枚举类:
package test9_Enum_5_practical_application;
/**
* @Auther: zhoulz
* @Description: test9_Enum_5_practical_application
* @version: 1.0
*/
public enum Gender {
男,
女;
}
测试类:
package test9_Enum_5_practical_application;
/**
* @Auther: zhoulz
* @Description: test9_Enum_5_practical_application
* @version: 1.0
*/
public class Test {
public static void main(String[] args) {
Person p = new Person();
p.setAge(20);
p.setName("小丽");
//p.setSex("女");
//p.setSex("qwewdwdfasf"); //不是自己想要的,但也不会报错
//以前的做法是在setSex()方法中进行判断,
//现在通过枚举来解决 : 创建一个枚举类,把属性sex及其方法去掉,
//当创建了枚举类对象Gender sex后,设置的不是“男、女”就会报错了。
//而且,不能直接传入“男、女”
//应该是:
p.setSex(Gender.男);//会提示传入:Gender sex 对象
//输入Gender. 后,自动获取
//即:传入枚举类Gender的对象:-->在入口处对参数进行了限制
System.out.println(p);
}
}
还可以通过枚举结合switch处理:
代码示例:
package test9_Enum_5_practical_application;
/**
* @Auther: zhoulz
* @Description: test9_Enum_5_practical_application
* @version: 1.0
*/
public class Test2 {
public static void main(String[] args) {
Gender sex = Gender.男;
//switch后面的()中可以传入枚举类型
//switch后面的():int,short,byte,char,String ,枚举
// long、float、double不行
switch (sex){
case 女:
System.out.println("一个女孩。");
break;
case 男:
System.out.println("一个男孩。");
break;
}
}