一、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()方法创建对象,其中参数即为注解的属性值,这样就能完成对象的初始化了。
以上便是对注解的解析,当然框架肯定远远不止这么简单,但利用反射的核心思想应该是差不多的。
总结:
谢谢你的观看。
如果可以的话,麻烦帮忙点个赞,谢谢你。