Java基础(十)——枚举与注解
一、枚举
1、介绍
枚举类:类的对象只有有限个,确定的。当需要定义一组常量时,强烈建议使用枚举类。如果枚举类中只有一个对象,则可以作为单例模式的实现。
使用 enum 定义的枚举类默认继承了 java.lang.Enum类,因此不能再继承其他类。
2、枚举的实现
代码示例:方式一,JDK 5.0 之前,自定义枚举类
1 public class SeasonEnum { 2 3 // 枚举当前类的多个对象 4 public static final SeasonEnum SPRING = new SeasonEnum("01", "春天"); 5 public static final SeasonEnum SUMMER = new SeasonEnum("02", "夏天"); 6 public static final SeasonEnum AUTUMN = new SeasonEnum("03", "秋天"); 7 public static final SeasonEnum WINTER = new SeasonEnum("04", "冬天"); 8 9 private SeasonEnum(String code, String desc) { 10 this.code = code; 11 this.desc = desc; 12 } 13 14 private final String code; 15 private final String desc; 16 17 public String getCode() { 18 return code; 19 } 20 21 public String getDesc() { 22 return desc; 23 } 24 }
代码示例:方式二,JDK 5.0,可以使用 enum 关键字定义枚举
1 public enum SeasonEnum { 2 3 // 枚举当前类的多个对象 4 SPRING("01", "春天"), 5 SUMMER("02", "夏天"), 6 AUTUMN("03", "秋天"), 7 WINTER("04", "冬天"); 8 9 public static final Map<String, SeasonEnum> map = new HashMap<>(); 10 11 static { 12 for (SeasonEnum e : values()) { 13 map.put(e.code, e); 14 } 15 } 16 17 SeasonEnum(String code, String desc) { 18 this.code = code; 19 this.desc = desc; 20 } 21 22 private final String code; 23 private final String desc; 24 25 public String getCode() { 26 return code; 27 } 28 29 public String getDesc() { 30 return desc; 31 } 32 33 }
3、枚举实现接口
1 public enum SeasonEnum implements Info { 2 3 // 枚举当前类的多个对象 4 SPRING("01", "春天") { 5 @Override 6 public void show() { 7 System.out.println("春暖花开"); 8 } 9 }, 10 SUMMER("02", "夏天") { 11 @Override 12 public void show() { 13 System.out.println("夏日炎炎"); 14 } 15 }, 16 AUTUMN("03", "秋天"), 17 WINTER("04", "冬天"); 18 19 SeasonEnum(String code, String desc) { 20 this.code = code; 21 this.desc = desc; 22 } 23 24 private final String code; 25 private final String desc; 26 27 public String getCode() { 28 return code; 29 } 30 31 public String getDesc() { 32 return desc; 33 } 34 35 public void show() { 36 System.out.println("我的天气"); 37 } 38 39 } 40 41 interface Info { 42 void show(); 43 }
4、API
values()方法:返回所有的枚举类型的对象。
valueOf(String str):检查该字符串是不是枚举类对象的"名字"。如不是,会有运行时异常:IllegalArgumentException。
toString():返回当前枚举类对象常量的名称。
二、注解
1、介绍
从 JDK 5.0 开始,Java 增加了对元数据(MetaData)的支持,也就是Annotation(注解)。
Annotation 其实就是代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过使用 Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署。
一定程度上,可以说:框架 = 注解 + 反射 + 设计模式。
2、示例
示例一、生成文档相关
@author:标明开发该类模块的作者,多个作者之间使用,分割。
@version:标明该类模块的版本。
@see:参考转向,也就是相关主题。
@since:从哪个版本开始增加的。
@param:对方法中某参数的说明,如果没有参数就不能写。
@return:对方法返回值的说明,如果方法的返回值类型是void就不能写。
@exception:对方法可能抛出的异常进行说明,如果方法没有用throws显式抛出的异常就不能写。
示例二、在编译时进行格式检查(JDK内置的三个基本注解)
@Override:限定重写父类方法,该注解只能用于方法。
@Deprecated:用于表示所修饰的元素(类,方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择。
@SuppressWarnings:抑制编译器警告。
3、自定义注解
代码示例:
1 @Retention(RetentionPolicy.RUNTIME) 2 @Target({ElementType.TYPE, ElementType.FIELD}) 3 public @interface MyAnnotation { 4 String value() default "baidu"; 5 } 6 7 @MyAnnotation() 8 public class Person { 9 } 10 11 public class Main { 12 public static void main(String[] args) { 13 // 通过反射获取Person类的注解 14 Class<Person> clazz = Person.class; 15 MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class); 16 17 // 获取注解的值 18 String value = annotation.value(); 19 System.out.println(value); // baidu(输出了默认值) 20 } 21 }
4、元注解
JDK 的元注解用于修饰其他注解定义。除了上面自定义注解用到的两个,JDK5.0提供了4个标准的元注解,分别是:@Documented、@Inherited、@Retention、@Target。
@Retention:用于指定注解的生命周期,它包含一个RetentionPolicy枚举类型的成员变量。
源码示例:
1 @Documented 2 @Retention(RetentionPolicy.RUNTIME) 3 @Target(ElementType.ANNOTATION_TYPE) 4 public @interface Retention { 5 /** 6 * Returns the retention policy. 7 * @return the retention policy 8 */ 9 RetentionPolicy value(); 10 } 11 12 public enum RetentionPolicy { 13 /** 14 * Annotations are to be discarded by the compiler. 15 */ 16 SOURCE, 17 18 /** 19 * Annotations are to be recorded in the class file by the compiler 20 * but need not be retained by the VM at run time. This is the default 21 * behavior. 22 */ 23 CLASS, 24 25 /** 26 * Annotations are to be recorded in the class file by the compiler and 27 * retained by the VM at run time, so they may be read reflectively. 28 * 29 * @see java.lang.reflect.AnnotatedElement 30 */ 31 RUNTIME 32 }
源码中的英文注释写的很清楚,下面翻译一下:
RetentionPolicy.SOURCE:在源文件中有效(即源文件保留),编译器直接丢弃这种策略的注释。
RetentionPolicy.CLASS:在class文件中有效(即class保留),当运行 Java 程序时,JVM不会保留注解。这是默认值。
RetentionPolicy.RUNTIME:在运行时有效(即运行时保留),当运行 Java 程序时,JVM 会保留注释。只有声明为RUNTIME生命周期的注解,才可以通过反射获取该注释。
@Target:用于指定注解能用于修饰哪些程序元素,它包含一个ElementType枚举类型的成员变量。
源码示例:
1 @Documented 2 @Retention(RetentionPolicy.RUNTIME) 3 @Target(ElementType.ANNOTATION_TYPE) 4 public @interface Target { 5 ElementType[] value(); 6 } 7 8 public enum ElementType { 9 // 用于修饰类、接口,或者enum声明 10 /** Class, interface (including annotation type), or enum declaration */ 11 TYPE, 12 13 // 用于修饰域 14 /** Field declaration (includes enum constants) */ 15 FIELD, 16 17 // 用于修饰方法 18 /** Method declaration */ 19 METHOD, 20 21 // 用于修饰参数 22 /** Formal parameter declaration */ 23 PARAMETER, 24 25 // 用于修饰构造器 26 /** Constructor declaration */ 27 CONSTRUCTOR, 28 29 // 用于修饰局部变量 30 /** Local variable declaration */ 31 LOCAL_VARIABLE, 32 33 // 用于修饰注解 34 /** Annotation type declaration */ 35 ANNOTATION_TYPE, 36 37 // 用于修饰包 38 /** Package declaration */ 39 PACKAGE, 40 41 /** 42 * Type parameter declaration 43 * 44 * @since 1.8 45 */ 46 TYPE_PARAMETER, 47 48 /** 49 * Use of a type 50 * 51 * @since 1.8 52 */ 53 TYPE_USE 54 }
@Documented:用于指定被该注解修饰的类将被 javadoc 工具提取成文档。默认情况下,javadoc是不包括注解的。定义为Documented的注解必须设置Retention值为RUNTIME。
@Inherited:被它修饰的注解将具有继承性。如果某个类使用了被@Inherited 修饰的注解,则其子类将自动具有该注解。
三、JDK8的新特性
1、介绍
Java 8对注解处理提供了两点改进:可重复的注解及可用于类型的注解。此外,反射也得到了加强,在Java8中能够得到方法参数的名称。这会简化标注在方法参数上的注解。
2、可重复注解
代码示例:方式一,JDK8之前
1 @Retention(RetentionPolicy.RUNTIME) 2 @Target({ElementType.TYPE}) 3 public @interface MyAnnotation { 4 String value() default "baidu"; 5 } 6 7 @Retention(RetentionPolicy.RUNTIME) 8 @Target({ElementType.TYPE}) 9 public @interface MyAnnotations { 10 MyAnnotation[] value(); 11 } 12 13 //@MyAnnotation("xiaoming") 14 //@MyAnnotation("xiaohong") 15 @MyAnnotations({@MyAnnotation("xiaoming"), @MyAnnotation("xiaohong")}) 16 public class Person { 17 private int age; 18 19 public void say() { 20 } 21 }
代码示例:方式二,JDK8之后
1 // 注:MyAnnotation的Target和Retention等元注解须与MyAnnotations相同 2 @Repeatable(MyAnnotations.class) 3 @Retention(RetentionPolicy.RUNTIME) 4 @Target({ElementType.TYPE}) 5 public @interface MyAnnotation { 6 String value() default "baidu"; 7 } 8 9 @Retention(RetentionPolicy.RUNTIME) 10 @Target({ElementType.TYPE}) 11 public @interface MyAnnotations { 12 MyAnnotation[] value(); 13 } 14 15 @MyAnnotation("xiaoming") 16 @MyAnnotation("xiaohong") 17 public class Person { 18 private int age; 19 20 public void say() { 21 } 22 }
3、类型注解
在Java 8之前,注解只能在声明的地方使用。Java8开始,注解可以应用在任何地方。
ElementType.TYPE_PARAMETER:表示该注解能写在类型变量的声明语句中(如:泛型声明)。
ElementType.TYPE_USE:表示该注解能写在使用类型的任何语句中。
代码示例:TYPE_PARAMETER
1 @Retention(RetentionPolicy.RUNTIME) 2 @Target({ElementType.TYPE, ElementType.TYPE_PARAMETER}) 3 public @interface MyAnnotation { 4 String value() default "baidu"; 5 } 6 7 @MyAnnotation 8 public class Person<@MyAnnotation T> { 9 private T age; 10 11 public void say() throws RuntimeException { 12 List<String> list = new ArrayList<>(); 13 14 int num = (int) 10L; 15 } 16 }
代码示例:TYPE_USE
1 @Retention(RetentionPolicy.RUNTIME) 2 @Target({ElementType.TYPE, ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) 3 public @interface MyAnnotation { 4 String value() default "baidu"; 5 } 6 7 @MyAnnotation 8 public class Person<@MyAnnotation T> { 9 private T age; 10 11 public void say() throws @MyAnnotation RuntimeException { 12 List<@MyAnnotation String> list = new ArrayList<>(); 13 14 int num = (@MyAnnotation int) 10L; 15 } 16 }
作者:Craftsman-L
本博客所有文章仅用于学习、研究和交流目的,版权归作者所有,欢迎非商业性质转载。
如果本篇博客给您带来帮助,请作者喝杯咖啡吧!点击下面打赏,您的支持是我最大的动力!