天天看点

Java注解实现以及部分参数说明

Java注解详细说明

今天面试过程中遇到了一个问题:谈谈注解的底层实现。由于本人只写过几个自定义注解,在复习过程中也忽略了这一部分,所以只回答了使用过一些自定义注解。然后面试官又问了一些反射的问题。面试结束经过百度后才知道,注解的底层实现就是用到了反射。所以今天来补上这一部分内容。

首先,注解是没有行为的,只能有数据。让其实现某些行为必须有实例(也就是代理对象),再用反射技术实现某些行为。

通过对一个注解进行反编译,我们可以在反编译代发中发现 ​

​public interface extends java.lang.annotation.Annotation​

​​ ,我们可以得知,注解就是一个继承自​

​java.lang.annotation.Annotation​

​的接口。也就是说,注解就是一个接口。

那么接口又是怎么样设置的属性呢?简单来说就是Java通过动态代理的方式来生成了一个接口的实例。这样对该代理的实例的属性赋值后,我们就可以通过反射,在程序运行时获取到注解的配置信息了。

下面再来看一块代码

@Override
public String toString() {
     return "xxxxx";
}      

上面的代码重写了toString方法并使用了@Override注解。但是即使它不使用此注解,程序也会正常执行。

所以注解也称为源代码的元数据。也就是说他只是一个附带品而已,它本身没有任何作用,只有外部程序(编译器或VM)解析它,才会引起它的作用。比如@Override的作用是告诉编译器这个方法是一个重写方法(描述方法的元数据),如果父类中不存在该方法,编译器便会报错,提示该方法没有重写父类中的方法。如果不小心拼写错误,例如将toString()写成了toStrring(){double r},而且没有使用@Override注解,那程序依然能编译运行。但实际的执行结果肯定与预期不符。这也是注解的一大功能,就是有助于程序的阅读,

一个注解基本由​

​Annotation​

​​、​

​ElementType​

​​、​

​RetentionPolicy​

​​三个类组成,​

​Annotation​

​是接口,其余两个是枚举。 所有的注解都基于这三个类,所谓的元注解也是用这三个类生成的,只不过可修饰的元素(ElementType)为ANNOTATION_TYPE。

下面简要的介绍一下元注解

元注解就是用来描述注解的注解,比如“@Target”元注解,它的作用是用来说明MethodInfo这个注解只能用于对方法进行注解:

@Target(ElementType.METHOD)
public @interface MethodInfo { 
    ...
}      

1. Retention

这个元注解表示一个注解会被保留到什么时候,比如以下代码表示Developer注解会被保留到运行时(也就是说在运行时依然能发挥作用):

@Retention(RetentionPolicy.RUNTIME)
public @interface Developer {
    String value();
}      

我们在使用@Retention时,后面括号里的内容即表示它的取值,从以上定义我们可以看到,取值的类型为RetentionPolicy,这是一个枚举类型,它可以取以下值:

  • SOURCE:表示在编译时这个注解会被移除,不会包含在编译后产生的class文件中;
  • CLASS:表示这个注解会被包含在class文件中,但在运行时会被移除;
  • RUNTIME:表示这个注解会被保留到运行时,在运行时可以JVM访问到,我们可以在运行时通过反射解析这个注解。

2. Documented

当一个注解被@Documented元注解所修饰时,那么无论在哪里使用这个注解,都会被Javadoc工具文档化。

3. Inherited

4. Target

  • TYPE:表示可以用来修饰类、接口、注解类型或枚举类型;
  • PACKAGE:可以用来修饰包;
  • PARAMETER:可以用来修饰参数;
  • ANNOTATION_TYPE:可以用来修饰注解类型;
  • METHOD:可以用来修饰方法;
  • FIELD:可以用来修饰属性(包括枚举常量);
  • CONSTRUCTOR:可以用来修饰构造器;
  • LOCAL_VARIABLE:可用来修饰局部变量。