【Java】基础52:注解,没有想象中那么简单

2020-07-30 16:07:43 浏览数 (1)

一、Annotation概述

Annotation,翻译过来就是注释、注解的意思。

第47天的时候就接触过注解,当时我还把注解和注释弄混了,其实它们之间是大同小异的:都是一种说明。

它们的区别在于:

  • 注释主要是给程序员看的备注信息。
  • 注解主要是给JVM看的备注信息。
1JDK提供的注解

①重写注解:@Override

被@override注解修饰的方法必须是父类中的重写方法或者是接口中的抽象方法。

其中用//修饰的句子就是注释。

②函数式接口:@FunctionalInterface

被FunctionalInterface修饰的接口必须是函数式接口。

其中用/**/修饰的句子也是注释。

③过时注解:@Deprecated

表示该方法已经过时了,有更好的方法可以使用。

当然过时并不代表着不能用了,依旧可以使用。

④抑制警告注解:@SuppressWarnings

让编译器不要报出警告信息。

这个是什么意思呢?

就是有的时候程序员写的代码不是很规范,开发工具会提示警告(只是警告并不是报错,并不影响程序的运行)。

对于刚开始学Java的人来说,可能都没有注意这个警告,而该注解可以使编译器不要报出警告信息。

2自定义注解

Java里非常重要的四大类型:

  • Class:类
  • Interface:接口
  • Enum:枚举
  • Annotation:注解

它们的创建方式是很相似的:

①定义注解名

使用@interface关键字定义注解类,注意不要和接口的关键字Interface弄混。

注解名称以大写开头(大驼峰命名规则)

②定义注解属性

属性的格式为:属性数据类型 属性名();

其格式和接口中的抽象方法很类似。

但是注解只有属性,没有任何方法。

如果要给注解属性定义默认值,,可以使用 default 关键字

但是一般不会直接赋值,都是由外部使用时才赋值的。

其中注解中并不是所有数据类型都可以使用,只能定义12种类型数据:

  • 基本数据类型(8种)
  • 类型(是Class这个类,不是所有的类
  • 字符串(String类型)
  • 枚举(Enum)
  • 注解(Annotation)
  • 以及它们对应的一维数组(也就是最常用的那种)

二、Annotation使用

注解的使用是千变万化的:

①在类上可以直接使用注解。

②在属性上也可以使用注解。

③在方法上也可以使用注解。

以上便是注解的常用使用方式,甚至注解在参数列表中也可以直接使用。

语法:@注解(属性名1 = XXX,属性名2 = XXX...)

如果注解中只有一个属性,可以将属性名定义为 value,这样使用该注解时可以省略 value=

也就是说注解中若是只有一个value属性,使用它时直接就可以赋值,比如:@MyAnnotation(“刘小爱”)

元注解

元,元始天尊的元,元老的元。在计算机中,可以将其理解成最初始的意思。

元注解便是最初始的注解,注解的注解,主要作用就是用来修饰自定义注解。

其中有两种元注解,代码如下:

①注解@Target

它的作用在于指明自定义注解可以使用的位置

  • ElementType.TYPE:可以注释在类上
  • ElementType.METHOD:可以注释在方法上
  • ElementType.FIELD:可以注释在属性上
  • ElementType.CONSTRUCTOR:可以注释在构造方法上

都是很常见的英语单词,根据其意思就能知道它的作用。

②注解@Retention

Retention,翻译过来就是保留的意思。它的作用就是指定该注解的保留策略。

什么叫保留策略?就可以理解成生命周期。

  • RetentionPolicy.SOURCE:保留到源码时期
  • RetentionPolicy.CLASS:保留到编译时期
  • RetentionPolicy.RUNTIME:保留到运行时期

这两个元注解都只有一个属性并且叫value,所以可以直接给属性赋值,并且源码也很相似。

以注解@Target为例,我们看下它的源码:

它们的属性类型都是枚举。

什么叫枚举呢?

枚举里面有各种各样的属性,全都是大写字母。

使用枚举名可以直接调用这些属性,就有点类似于使用类名直接调用静态变量。

因为时间受限就不详细说明了。

三、Annotation解析

注解有什么方便之处呢?看下面的例子:

①创建自定义注解

使用@Target让自定义注解可以放在方法上、构造上;

使用@Retention让自定义注解保留到运行时期。

自定义注解中只有一个属性,并且属性名为value,所以可以简写。

②创建Student对象

分别在构造方法上和成员方法上放上自定义的注解,同时给注解的属性赋值。

这样做有什么用?

如果有对应框架的话,我们直接在构造方法上放一个注解,就能够给类的属性赋值了。

不用我们创建对象初始化什么的,是不是超级简单?

当然需要有对应的框架,那底层是怎么做到的呢?底层代码一般不用我们去写,但是最好了解下它大致上是怎么实现的。

使用的方法就是我们昨天学的反射,反射一般应用于框架中,这也是反射的厉害之处之一:

①获取Student类对应的Class对象

每个类都有一个对应的Class对象,三种获取Class对象的方式,选择一种即可。

同时利用Class对象获取对应的构造器,也就是getConstructor()方法:

  • 如果是无参构造,方法参数就没有。
  • 如果是有参构造,方法参数为构造方法参数类型对应的Class对象。

②判断构造方法上是否有注解

isAnnotationPresent()方法可以判断是否存在注解。

因为构造方法上是可以放多个注解的。

所以参数为我们需要的注解对应的Class对象。

③获取注解的属性值

getAnnotation() 方法可以获取注解,参数为对应注解的Class对象。

如果存在指定类型的注解,则返回该注解,否则返回null。

除了上述的方法,还有两个具有类似功能的方法:

Annotation[] getAnnotations() ,返回此元素上存在的所有注释(包括继承的)

Annotation[] getDeclaredAnnotations() ,返回直接存在于此元素上的所有注释(不包括继承的)

④将注解属性赋值给对应的对象

构造器调用newInstance()方法创建对象,其中参数即为注解的属性值,这样就能完成对象的初始化了。

以上便是对注解的解析,当然框架肯定远远不止这么简单,但利用反射的核心思想应该是差不多的。

总结:

谢谢你的观看。

如果可以的话,麻烦帮忙点个赞,谢谢你。

0 人点赞