枚举:jdk1.5引入的新特性,允许用常量表示特定的数据片段,且全一类型安全的形式来表示。
常用的定义常量方式
public static final xxx ...例如:
public static final int SEASON_SPRING = 1;
public static final int SEASON_SUMMER = 2;
public static final int SEASON_FALL = 3;
public static final int SEASON_WINTER = 4;
使用常量的缺点
1.类型不安全,若一个方法要求传入季节参数。
public Object getSeasonXXX(int seasonType) {
...
return xxx;
}
//如果这个时候要调用getSeasonXXX根据传入的天气获取天气的一些相关属性,用常量的话,形参就是int类型,这个时候getSeasonXXX(SEASON_WINTER)和getSeasonXXX(4)都能获取冬天的天气属性,那么getSeasonXXX(5)也能编译过去而不会警告,但这样就不安全了。
2.没有命名空间。开发者要在命名的时候以SEASON_开头,另外一个开发者再看这段代码的时候,才知道这四个常量分别代表季节。
3.如果定义int值相同的变量,容易造成混淆。
使用枚举类
这个时候尝试利用枚举来定义常量,写个最简单的例子,例如
public enum SeasonEnum {
SPRING,SUMMER,FALL,WINTER;
}
将该类的编译后的class文件 javap(对编译的文件进行反编译)一下,可以看到类型默认继承java.lang.Enum
简单用法
public class testEnum1 {
enum EnumW {
SPRING,SUMMER,FALL,WINTER;
}
public static void main(String[] args) {
EnumW enumW = EnumW.SPRING;
System.out.println(enumW); //输出SPRING
System.out.println(enumW); //输出SPRING
if (enumW.equals(enumW.toString())) { //这边不会输出相同 因为enumW不是String类型 但是有equals、toString()方法
System.out.println("相同");
}
}
}
枚举类也可以定义属性和方法,例如
public class testEnum2 {
enum EnumW {
SPRING("春天"),SUMMER("夏天"),FALL("秋天"),WINTER("冬天");//枚举类的实例必须放在第一行,如果放在下面编译会报错
private final String name;
private EnumW(String name) {//枚举类的构造器只能是私有的 这边改为public编译会有警告(可以自定义多个参数然后再get获取多个属性)
this.name = name;
}
public String getName() {
return name;
}
}
public static void main(String[] args) {
EnumW enumW = EnumW.SPRING;
System.out.println(enumW.getName());//春天
}
}
从上述例子可以看出枚举类的几个特点
- enum和class、interface的地位一样
- 使用enum定义的枚举类默认继承了java.lang.Enum,而不是继承Object类。枚举类可以实现一个或多个接口。
- 枚举类的所有实例都必须放在第一行展示,不需使用new 关键字,不需显式调用构造器。自动添加public static final修饰。
- 使用enum定义、非抽象的枚举类默认使用final修饰,不可以被继承,又因为继承了Enum类不能再继承其它类。
- 枚举类的构造器只能是私有的。
枚举类的常用用法
1.可以在switch case语句中直接使用枚举值,不需加入枚举类作为限定,使代码更加优雅
public class testEnum3 {
enum EnumW {
SPRING,SUMMER,FALL,WINTER;
}
public void judge(EnumW s)
{
switch(s)
{
case SPRING: //直接使用枚举值做限定
System.out.println("春天适合踏青。");
break;
case SUMMER:
System.out.println("夏天要去游泳啦。");
break;
case FALL:
System.out.println("秋天一定要去旅游哦。");
break;
case WINTER:
System.out.println("冬天要是下雪就好啦。");
break;
}
}
public static void main(String[] args) {
EnumW enumw = EnumW.SPRING;
testEnum testEnum = new testEnum();
testEnum.judge(enumw);//春天适合踏青。
}
}
思考
1.枚举类是否可以定义抽象方法
首先有抽象方法的类必然是抽象类,但是根据上面的反编译的类由final修饰而不是抽象类,但是枚举类又可以定义抽象方法,这是为什么呢。
首先编写这么一段代码
public enum AbstractTest {
Spring {
@Override
public AbstractTest getSeason() {
return Spring;
}
},
Summer {
@Override
public AbstractTest getSeason() {
return Summer;
}
},
FALL {
@Override
public AbstractTest getSeason() {
return FALL;
}
},
WINTER {
@Override
public AbstractTest getSeason() {
return WINTER;
}
};
public abstract AbstractTest getSeason();
public static void main(String[] args) {
System.out.println(AbstractTest.Spring.toString());//Spring
}
}
查看编译后的文件
javac AbstractTest.java
将java文件编译为class文件,会生成4个从1开始包含$+数字的class文件(匿名内部类)和一个主类(枚举类),这四个类继承了主类从而通过子类来实现抽象方法
所以枚举类是可以带有抽象方法的,含有抽象方法的枚举类将自动修饰abstract并通过内部类来实现。