望远山,知近路,而后自得其乐!

Java注解简介

1.什么是注解

从JDK5开始,Java增加了注解,注解是代理里特殊的标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。通过使用注解,开发人员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。代码分析工具,开发工具和部署工具都可以通过这些补充信息进行验证,处理或者进行部署。

JavaSE5内置了三种注解,定义在java.lang包中:

  1. @Override : 表示当前方法覆盖超类中的方法。如果你所写的方法和超类中的方法不同的话,编译器会报错。主要用于检查。
  2. @Deprecated : 表明当前的元素已经不适用。当使用了注解为@Deprecated的元素时,编译器会报出警告。
  3. @SuppressWarnings : 关闭不当的编译器警告。

2.注解的分类

按照注解的运行机制,可以将注解分为三类。

  • 源码注解 只在源码存在,编译成class文件就不存在了
  • 编译时注解 源码和编译后的class文件都存在,如JDK自带的三种注解@Override,@Deprecated,@SuppressWarnings
  • 运行时注解 在程序运行时可以起作用

3.元注解

元注解是用来标注其它注解来创建新注解的,时注解的注解。元注解的类型有以下几种:

  • @Target:注解所修饰的对象范围
  • @Inherited:表示注解可以被继承
  • @Documented:表示这个注解应该被JavaDoc工具记录
  • @Rentation:用来声明注解的保留策略
  • @Repeable:JDK8新增,允许一个注解在同一声明类型(类,属性或方法)上多次使用。

@Target注解的取值是一个ElementType类型的枚举,其中有以下几种取值,对应不同的对象范围。

  • ElementType.TYPE:能修饰类,接口或者枚举类型。
  • ElementType.FIELD:能修饰成员变量
  • ElementType. METHOD:能修饰方法
  • ElementType. PARAMETER:能修饰参数
  • ElementType. CONSTRUCTOR:能修饰构造方法
  • ElementType.LOCAL_VARIABLE:能修饰局部变量
  • ElementType. ANNOTATION_TYPE:能修饰注解
  • ElementType. PACKAGE:能修饰包
  • ElementType.TYPE_PARAMETER:能修饰参数声明
  • ElementType.TYPE_USE:使用类型

@Retention注解有3种类型,分别表示不同级别的保留策略。

  • RetentionPolicy.SOURCE:源码级注解,注解信息只会保留在Java源码中,源码在编译后,注解信息将会被丢弃,不会保留在.class文件中。
  • RetentionPolicy.CLASS:编译时注解。注解信息会保留在.java源码以及.class中。当运行java程序时,JVM会丢弃该注解信息,不会保留在JVM中,许多注解类框架,如EventBus,ButterKnife他们都是使用编译时注解信息开发的,针对编译时注解我们采用AbstractProcessor来处理注解信息。
  • RetentionPolicy.RUNTIME:运行注解。当运行Java程序时,JVM也会保留该注解信息,可以通过反射获取该注解信息。

@Documented 被修饰的注解会生成到javadoc中

@Inherited 可以让注解类似被继承一样,但是这并不是真的继承。通过使@Inherited,只可以让子类类对象使用getAnnotations()反射获取父类被@Inherited修饰的注解。

4.自定义注解实例

创建一个注解类JInfo,注解目标类型为METHOD,保留机制设置为运行时注解。该注解有一个注解成员info,为String类型,默认值为空字符串。

@Target(METHOD) //注解目标类型为方法(METHOD)
@Retention(RetentionPolicy.RUNTIME)  //留机制设:运行时注解
public @interface JInfo {
    public String info() default ""; ///注解成员 类型为String,默认为空字符串
}

就这么简单,一个注解就建好了。注解本身不会起到任何作用,需要配合注解处理器才能发挥一定的作用。下面展示一下在代码中是如何去添加注解并访问这些注解的,此处需要说明的是,如果需要在代码中去访问注解内容,注解保留机制需设置为运行时(RetentionPolicy.RUNTIME),否则无法访问。

public class Test {
    public static void main(String[] args) {
        Method[] methods = Test.class.getMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(JInfo.class)) {
                JInfo jInfo = method.getAnnotation(JInfo.class);
                System.out.println(jInfo.info());
            }
        }
    }
    
    @JInfo (info = "this is info string")
    public void test() {
        System.out.println("test");
    }
}

输出结果即注解内容:

this is info string

我们在进行注解时,如果注解是有成员的,那么就必须在注解后的括号里为每个成员指定数据,或者在注解类中为成员指定默认值,注解中不允许null值。

5.编译时注解

运行时注解一般在代码中需要通过反射去获取和使用,因此效率较低。为了解决效率问题,我们可以使用编译时注解,在编译期将注解转换为代码,从而提高执行效率。Annotation Processor是javac的一个工具,它用来在编译时扫描和处理注解。通过Annotation Processor可以获取到注解和被注解对象的相关信息,然后根据注解自动生成Java代码,省去了手动编写,提高了编码效率。

文章评论已关闭!