注解学习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xfhy_/article/details/82590983

注解是java1.5引入的,比如@Override,@Deprecated等都是比较常见的注解,Java程序员在日常开发中注解使用广泛.

一.什么是注解

下面简单看下Java官方定义的注解,其中有些东西可能没见过,不过没关系,下面会讲.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

注解是一种描述数据的数据.官方称为元数据. 上面的Override表示的是重写父类的方法,这个注解让代码更具可读性,开发人员一看就知道这是拿来干什么的.其实这个注解在编译阶段就会被丢弃,因为这个注解只是拿来给编译器和开发人员看的.在运行时无实际意义.

二.为什么要引入注解

我暂时想到的是以下2点:

1. 规范

在Android中经常看到@StringRes,@NonNull等等注解,是为了让参数传递更规范,避免出错.

2. 注入

有时候在一个属性上,加一个注解,然后第三方框架就可以给这个属性赋值.这就是简单的注入.使用非常方便,代码解耦.比如出名的ButterKnife.还有Spring,Spring和注入相关的常见注解有Autowired、Resource、Qualifier、Service、Controller、Repository、Component。

三.Annotation是如何工作的?怎么编写自定义的Annotation?

对于上面的Override注解代码定义,大家可能还有点迷惑.就这样简单的定义一下,就可以了么??? 当然不是. Annotations是给大家在代码中使用的,并且不包含业务逻辑,那么就必须有人来实现业务逻辑. 那么谁来做这个事情->元数据的用户,需要从注解上面读取信息并实现必要的逻辑.Annotations仅仅提供它定义的属性(类/方法/包/域)的信息。

@MyTodo(author = "feiyang")
public static void main(String[] args) {
}

比如上面这段代码,我使用了注解,那么肯定需要去读取这个注解上面的值,然后做些什么操作,注解才有意义.That’s it.

编写注解

如果你仔细观察,你可能发现了,上面的Override定义中,Override本身是一个注解,但是注解上面居然还有注解……(/懵)

在Java1.5中java.lang.annotation提供了四种元注解,专门注解其他的注解:

@Documented –注解是否将包含在JavaDoc@Retention –什么时候使用该注解
@Target –注解用于什么地方
@Inherited – 是否允许子类继承该注解

Retention

定义该注解的生命周期

  • RetentionPolicy.SOURCE 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
  • RetentionPolicy.CLASS 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式
  • RetentionPolicy.RUNTIME 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。

@Target

表示该注解用于什么地方。如果不明确指出,该注解可以放在任何地方

ElementType.TYPE:用于描述类、接口或enum声明
ElementType.FIELD:用于描述实例变量
ElementType.METHOD 方法
ElementType.PARAMETER
ElementType.CONSTRUCTOR
ElementType.LOCAL_VARIABLE
ElementType.ANNOTATION_TYPE 另一个注释
ElementType.PACKAGE 用于记录java文件的package信息

下面来实操一下如何来定义注解,Annotations只支持基本类型、String及枚举类型。注释中所有的属性被定义成方法,并允许提供默认值。

@Target(ElementType.METHOD)   //只能用在方法上
@Retention(RetentionPolicy.RUNTIME)  //运行时也不会被丢弃的
public @interface MyTodo {
    //枚举
    enum Priority {
        LOW, MEDIUM, HIGH
    }

    enum Status {STARTED, NOT_STARTED}

    //普通的属性  带一个默认值
    String author() default "xfhy";

    Priority priority() default Priority.LOW;

    Status status() default Status.STARTED;
}

使用方式:

@MyTodo(author = "feiyang", status = MyTodo.Status.STARTED, priority = MyTodo.Priority.HIGH)
public static void main(String[] args) {
}

目前为止,我们定义了自己的自定义注解,然后可以用于一个业务的方法之上,但是我们目前并不知道属性上面的值是多少.所以我们还需要去读取这些属性的值.

private void getMethodsAnnotation() {
    Class<AnnotationTest> annotationTest = AnnotationTest.class;
    //获取所有方法
    for (Method method : annotationTest.getMethods()) {
        //获取该方法上面的注解
        MyTodo annotation = method.getAnnotation(MyTodo.class);
        if (annotation != null) {
            //获取方法名
            System.out.println("Method name : " + method.getName());
            //获取注解的值
            System.out.println("Author : " + annotation.author());
            System.out.println("Priority  : " + annotation.priority());
            System.out.println("Status  : " + annotation.status());
        }
    }
}

这样我们就读取到了注解上的值了.

猜你喜欢

转载自blog.csdn.net/xfhy_/article/details/82590983