Java一注解全面分析

2021-04-25  本文已影响0人  mumuxi_

目录

一、为什么要学习注解呢?

二、什么是注解(Annotation)

三、注解有什么作用

四、注解的分类

五、注解基本概念和知识(元注解、Java内置注解、Annotation接口、注解的属性、注解处理器、注解处理类)

六、自定义注解


一、为什么要学习注解呢?

在实际的项目中我们会使用大量的框架,很多框架就会使用大量的注解。学习注解能够使我们读懂别人的代码。我们也可以使用注解,自定义注解使我们的代码更清晰更整洁。从目前行业使用注解的情况,主要是用来简化代码,提高开发效率。

二、什么是注解(Annotation)

从JDK5开始,Java增加了Annotation的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。

其实单纯说注解,注解本身没有任何的作用。简单说和注释没啥区别,而它有作用的原因是:注解解释类,也就是相关对代码进行解释的特定类。一般这些类使用反射是可以拿到的。因此,通过注解和反射这两者的结合使用,是可以做到很多功能的。

三、注解有什么作用

理解了注解之后,大概也可以知道注解有什么用处了,这是我个人理解的和结合目前大家对注解的使用的总结出来的:

四、注解的分类

1.按运行机制分

2.按来源分

五、一些基本概念知识(元注解、Java内置注解、Annotation接口、注解的属性、注解处理器、注解处理类)

1.元注解

元注解就是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。目前我知道的元注解有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。

如果注解类型声明上没有@Retention声明,则保留策略默认为RetentionPolicy.CLASS。

定义 Annotation 时,@Target 可有可无。若有 @Target,则该 Annotation 只能用于它所指定的地方;若没有 @Target,则该 Annotation 可以用于任何地方。

2.内置的普通注解

Java有内置一些注解,最早内置了三种注解,后面也添加有一些新的注解,请读者自行了解:

3.Annotation接口(注解的本质)

「java.lang.annotation.Annotation」接口中有这么一句话,用来描述『注解』。

The common interface extended by all annotation types
所有的注解类型都继承自这个普通的接口(Annotation)

这句话有点抽象,但却说出了注解的本质。我们看一个 JDK 内置注解的定义:

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

这是注解 @Override 的定义,其实它本质上就是:

public interface Override extends Annotation{
}

没错,注解的本质就是一个继承了 Annotation 接口的接口。有关这一点,你可以去反编译任意一个注解类,你会得到结果的。

4.注解的属性

注解的属性也叫做成员变量,注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。

Java中注解成员的类型必须是如下几类:

  1. 基本数据类型(boolean, byte, char, short, int, long, float, double等);
  2. String;
  3. Class;
  4. 枚举;
  5. 其他的注解;
  6. 以上类型的数组;

注解属性的语法形式如下:

[访问级别修饰符] [数据类型] 名称() default 默认值;

例如,我们要定义在注解中定义一个名为 value 的字符串属性,其默认值为空字符串,访问级别为默认级别,那么应该定义如下:

String value() default "";

注意:在注解中,我们定义属性时,属性名后面需要加 ()

5.注解处理器(Annotation Processing Tool,简称APT)

根据元注解@Retention指定值的不同,注解可分为SOURCE、CLASS和RUNTIME三种类型。当被声明为SOURCE时,注解仅仅在源码级别被保留,编译时被丢弃;声明为CLASS时,注解会由编译器记录在class文件内,但在运行时会被忽略,默认的Retention级别即为CLASS;声明为RUNTIME时,注解将被保留到运行时,可通过反射在运行时获取到。针对CLASS类型的注解,就需要用到注解处理器。注解处理器(Annotation Processing Tool)是javac内置的工具,用于在编译时期扫描和处理注解信息。从JDK 6开始,apt暴露了可用的API。一个特定的处理器接收一个Java源代码或已编译的字节码作为输入,然后输出一些文件(通常是.java文件)。这就意味着你可以使用apt动态生成代码逻辑,需要注意的是apt仅可以生成新的Java类而不能对已存在的Java类进行修改。所有生成的Java类将和其他源代码一起被javac编译。

6.注解处理类

注解处理类就是帮助程序员快速的构造自定义注解处理器的一些类和接口。Java使用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口。除此之外,Java在java.lang.reflect 包下新增了AnnotatedElement接口,该接口代表程序中可以接受注解的程序元素。

AnnotatedElement接口实现类

AnnotatedElement接口方法

1.default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果指定类型的注解出现在当前元素上,则返回true,否则将返回false。这种方法主要是为了方便地访问一些已知的注解。

2.<T extends Annotation> T getAnnotation(Class<T> annotationClass)
如果在当前元素上存在参数所指定类型(annotationClass)的注解,则返回对应的注解,否则将返回null。

3.Annotation[] getAnnotations()
返回在这个元素上的所有注解。如果该元素没有注释,则返回值是长度为0的数组。该方法的调用者可以自由地修改返回的数组;它不会对返回给其他调用者的数组产生影响。

4.default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
如果参数中所指定类型的注解是直接存在于当前元素上的,则返回对应的注解,否则将返回null。这个方法忽略了继承的注解。(如果没有直接在此元素上显示注释,则返回null。)

5.default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)
返回与该元素相关联的注解。如果没有与此元素相关联的注解,则返回值是长度为0的数组。这个方法与getAnnotation(Class)的区别在于,该方法检测其参数是否为可重复的注解类型(JLS 9.6),如果是,则尝试通过“looking through”容器注解来查找该类型的一个或多个注解。该方法的调用者可以自由地修改返回的数组;它不会对返回给其他调用者的数组产生影响。参考@Repeatable。

六、自定义注解

1.注解的定义

使用 @interface 来声明一个注解,注解的语法格式如下:

public @interface 注解名 {定义体}

我们来定义一个注解

@Retention(RetentionPolicy.RUNTIME)
public @interface Test{}

2.自定义Java注解处理器

实现一个自定义注解处理器需要有两个步骤,第一是实现Processor接口处理注解,第二是注册注解处理器

实现Processor接口

通过实现Processor接口可以自定义注解处理器,这里我们采用更简单的方法通过继承AbstractProcessor类实现自定义注解处理器。实现抽象方法process处理我们想要的功能。

public class CustomProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
        return false;
    }
}

一些具体实现可以参考自定义Java注解处理器,这里不多叙述

注册注解处理器

使用Google提供的@AutoSerivce注解: 引入依赖:

dependencies { compile 'com.google.auto.service:auto-service:1.0-rc2' }

使用@AutoService生成META-INF/services/javax.annotation.processing.Processor文件:

AutoService(Processor.class) public class AutoBuilderProcessor extends AbstractProcessor { ...
}

3.自定义注解实战(这里找的都是一些Android实战案例,对于纯Java的小伙伴只能表示抱歉了)

对于自定义注解,大家可以去学习使用 ButterKnife和Dagger2 框架,并理解他们的原理,这样可以帮助大家加深对自定义注解的使用。下面是一些实战案例:
仿ButterKnife,实现自己的BindView
Android 注解(Annotation)的入门与使用(一)
手写ButterKnife来搞明白Android注解处理器

参考:
1.深入理解 Java 注解
2.Java注解处理器
3.AnnotatedElement
4.自定义Java注解处理器

上一篇 下一篇

猜你喜欢

热点阅读