83、项目开发中,推荐使用枚举定义常量,来代替接口常量或类常量
Eg:enum{Spring,Summer,Autumn,Winter;}
枚举定义常量相对于经常使用的常量类和静态常量相比的优势:
1)枚举常量更简单:枚举常量不需要定义枚举值,int spring=1;枚举表示的 是一个枚举项,字面含义不同,其他常量必须是一个类型;
2)枚举常量属于稳态型
3)枚举具有内置的方法,例如values:获得所有值的集合,可用于遍历,ordinal: 获得排序值,compareTo比较方法等;
4)枚举可以自定义方法:枚举常量不仅可以定义静态方法,还可以定义非静 态方法,还能够从根本上杜绝常量类被实例化
缺点:枚举类型是不能有继承的,枚举常量定义完毕后,除非修改重构,否则无法做扩展。
枚举类型的遍历:
for(Season s:Season.values()){
System.out.println(s);
}
84、使用构造函数协助描述枚举项
enum Season{
//通过构造方法可以为枚举项添加描述和其他定义
Spring("春","春暖花开"),Summer("夏","艳阳高照"),Autumn("秋","秋高气爽"),Winter("冬","雪花飘飘");
private String desc;//描述
private String other;//其他
//添加上述描述和定义必须添加下面所示的构造方法
Season(String desc,String other){
this.desc=desc;
this.other=other;
}
//获得描述
public String getDesc(){
return desc;
}
//获得其他
public String getOther(){
return other;
}
}
推荐在枚举定义中为每个枚举项定义描述,比在接口常量或类常量中增加注释的方式友好、简洁
85、小心switch带来的空值异常
public static void testSwitch(Season s){
switch(s){
case Spring:System.out.println("春");break;
case Summer:System.out.println("夏");break;
default:throw new AssertionError();
}
}
上面代码,如果做测试:testSwitch(null);会发现在switch(s)处抛出空指针异常,这是因为java能判断的switch类型为short、byte、int、char类型,那么为什么枚举类型能编译通过呢,这是因为编译器是根据枚举类型的排序值进行判断的:Switch(s.ordinal()){case Season.Spring.ordinal()},如果为null值,那么没有ordinal方法,肯定会抛空指针异常,所以解决方法是在该方法中加入是否为null判断
86、在switch的default代码块中增加AssertionError错误
Default:throw new AssertionError();
87、使用valueOf前必须进行校验
枚举类中提供valueOf方法,用于查找字符串值与该参数相等的枚举项,返回一个枚举类型的数据
//测试valueOf方法,因为Season不存在SpringTime会抛出
//IllegalArgumentException异常信息
public static void testValueOf(){
List<String> list=Arrays.asList("Spring","SpringTime");
for(String s:list){
Season season=Season.valueOf(s);
if(season!=null){
System.out.println(s);
}else{
System.out.println("该枚举类型不存在");
}
}
}
解决方案:
1、在Season.valueOf方法中添加try....catch方法进行捕获
2、在枚举类中添加一个判断是否存在的方法,例如:contains方法,如果存在 该字符串信 息,则进行valueOf 转换为相应的枚举类型,不存在则不转换
88、用枚举实现工厂方法模式更简单
89、枚举项的数量限制在64个以内
Java提供的枚举集合,由于枚举类型的实例数量固定并且有限,相对来说其效率会比其他Set和Map要高:
EnumSet:其元素必须是某一枚举的枚举项
EnumMap:key值必须是某一枚举的枚举项
EnumSet存储枚举类型数据时候,当枚举数量小于等于64时,创建一个RegularEnumSet实例对象,大于64时则创建一个JunmboEnumSet实例对象
public static void testEnumSet(){
EnumSet<Season> set1=EnumSet.allOf(Season.class);
EnumSet<Season> set2=EnumSet.allOf(Season.class);
//枚举类型Season中小于或等于64个元素,则得到的结果为:class java.util.RegularEnumSet
System.out.println(set1.getClass());
//枚举类型Season中超过64个元素,则得到的结果为:class java.util.JumboEnumSet
System.out.println(set2.getClass());
}
因为EnumSet提供的实现类底层都是基本的数字类型操作,其性能肯定比其他的Set类型要好很多,特别是数量少于64的时候,速度飞快.
90、小心注解继承
元注解:@Inherited,表示一个注解是否可以自动被继承
91、枚举和注解结合使用威力更大
//定义角色级别,用户,管理员,超级管理员
enum RoleIdentify{
User,Admin,SuperAdmin;
}
//定义访问权限注解类
@Retention(RetentionPolicy.RUNTIME)//元注解,表示该注解的保留级别
@Target(ElementType.TYPE)//元注解,表示该注解可以标注在什么地方
@Inherited//元注解,表示该注解会被自动继承
@interface Access{
//定义访问级别,默认为管理员
RoleIdentify level() default RoleIdentify.Admin;
}
//使用自己定义的注解
@Access(level=RoleIdentify.User)
class TestAnnatation{
}
public class AnnatationTest {
public static void main(String[] args) {
//测试
TestAnnatation test=new TestAnnatation();
Access access=test.getClass().getAnnotation(Access.class);
System.out.println(access.level());//打印输出User
}
}
92、主要@Override不同版本的区别
如下代码:
interface MyInterface{
public void doSomething();
}
class MyImpl implements MyInterface{
@Override
public void doSomething() {
}
public void doTest(List<String> strList){
}
}
上面代码在jdk1.6版本上编译没有任何问题,但是在jdk1.5版本上编译上面代码会出错误:The method doSomething of type MyImpl override a superclass...
原因是jdk1.5中的@Override是严格遵守覆写的定义:子类方法与父类方法必须具有相同的方法名称、输入参数、输出参数(允许子类缩小)、访问权限(允许子类扩大),父类必须是一个类,不能是一个接口,否则不能算是覆写。
所以,如果是jdk1.6版本的项目移植到jdk1.5版本上面,就需要删除实现接口方法上的@Override注解。