JAVA-注解

注解定义

Java 注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。注解包含在 java.lang.annotation 包中。
注意:注解本身不是代码的一部分,注解作用在类或者方法、属性上不会自己起作用,需要其他工具(代码)主动去获取注解的信息。

作用

  • 替代配置文件:例如spring中的中@Autowired,@Service
  • 编译时进行格式检查:例如Override

jdk注解

  • @Override,表示当前的方法定义将覆盖超类中的方法。
  • @Deprecated,使用了注解为它的元素编译器将发出警告,因为注解
  • @Deprecated是不赞成使用的代码,被弃用的代码。
  • @SuppressWarnings,关闭不当编辑器警告信息。
  • @Functionallnterface:java8 函数式接口注解,一般有这个注解的方法可以直接使用 lambda 表达式

元注解(定义注解的注解)

元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。基本的元标签有:

  • @Retention:定义了该注解的生命周期
  • @Documented:简单的标记注解,表示是否将注解信息添加在 Java 文档
  • @Target:表示该注解用于什么地方
  • @Inherited:定义了一个注释与子类的关系。如果一个超类带有 @Inherited 注解,那么对于该超类,它的子类如果没有被任何注解应用的话,那么这个子类就继承了超类的注解。
    @Repeatable:@Repeatable 是 Java 8 中加入的,是指可重复的意思。通常使用 @Repeatable 的时候指注解的值可以同时取多个。

如何定义一个注解

注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以无形参的方法形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型
注意:注解可以有默认值,需要用 default 关键字指定。如果注解内只有一个名为 value 的属性时,应用该属性时可以将值直接写到括号内,不用写 value = “…”

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Person {
    int id() default 100;
    String name();
    String language();
    String company();
}

上面假设定义了一个名为 @Person 的注解,该注解有 id, name, language, company 三个属性。使用的时候,我们应该对其赋值。赋值的方式类似于 key=“value” 的方式进行,属性之间用 “,” 隔开:

@Coder(id = 10086, name = "GRQ", language = "JAVA", company = "cetc")
public class personTest() {
}

自定义注解步骤

自定义注解类编写的规则:

  • 注解类型定义为 @interface,所有的注解会自动继承 java.lang.Annotation
  • 这一接口,而且不能再去继承其他的类或接口;
  • 参数成员只能用 public 或 default 两个关键字修饰;
  • 参数成员只能用基本类型:byte, short, char, int, long, float, double, boolean,以及String, Enum, Class, Annotations 等数据类型,以及这些类型的数组;
  • 要获取类方法和字段的注解信息,必须通过Java 的反射技术;
  • 注解也可以不定义成员变量,这种注解具有标记作用;
  • 自定义注解需要使用元注解进行编写;
    大家可以参考这篇文章

注解底层原理

从java源码到class字节码是由编译器完成的,编译器会对java源码进行解析并生成class文件,而注解也是在编译时由编译器进行处理,编译器会对注解符号处理并附加到class结构中,根据jvm规范,class文件结构是严格有序的格式,唯一可以附加信息到class结构中的方式就是保存到class结构的attributes属性中。 我们知道对于类、字段、方法,在class结构中都有自己特定的表结构,而且各自都有自己的属性,而对于注解,作用的范围也可以不同,可以作用在类上,也可以作用在字段或方法上,这时编译器会对应将注解信息存放到类、字段、方法自己的属性上。

在我们的AnnotationTest.java类被编译后,在对应的AnnotationTest.class文件中会包含一个RuntimeVisibleAnnotations属性,由于这个注解是作用在类上,所以此属性被添加到类的属性集上。即Test注解的键值对value=test会被记录起来。而当JVM加载AnnotationTest.class文件字节码时,就会将RuntimeVisibleAnnotations属性值保存到AnnotationTest的Class对象中,于是就可以通过AnnotationTest.class.getAnnotation(Test.class)获取到Test注解对象,进而再通过Test注解对象获取到Test里面的属性值。

这里可能会有疑问,Test注解对象是什么?其实注解被编译后的本质就是一个继承Annotation接口的接口,所以@Test其实就是“public interface Test extends Annotation”,当我们通过AnnotationTest.class.getAnnotation(Test.class)调用时,JDK会通过动态代理生成一个实现了Test接口的对象,并把将RuntimeVisibleAnnotations属性值设置进此对象中,此对象即为Test注解对象,通过它的value()方法就可以获取到注解值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值