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注解。