Java基础(十)——枚举与注解 Craftsman

一、枚举

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

本博客所有文章仅用于学习、研究和交流目的,版权归作者所有,欢迎非商业性质转载。

如果本篇博客给您带来帮助,请作者喝杯咖啡吧!点击下面打赏,您的支持是我最大的动力!

原文地址:https://www.cnblogs.com/originator/p/15737062.html