java 注解 基本知识
1.注解
注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记。标记可以加在包、类,属性、方法,方法的参数以及局部变量上。
第一阶段最早在继承父类然后方法重载的时候就接触过注解。
@override就是一个标识,说明这是一个重写的方法。实际编译为字节码文件时就没有用了,只是在源码进行标识和判断方法重载的格式是否正确。
有一些注解则具备功能性
比如@getting 和@webServlet(将servlet配置到web.xml中,即映射到tomcat根目录)
1.1 创建注解
注解就是接口,在创建的时候设置为接口即可,注解要单独放在一个包里,包名annotation 中文翻译即注解
此时的接口还只是一个普通接口,需要在interface前加上@符号 才能转为注解类
此时这个注解就可以被使用了,但是此时的注解仅仅具备标识作用,可以被写在类上或者构造方法上,一个对象上可以被施加多个注解
1.2 注解的属性
注解可以设置属性,注意以下几点:
数据类型 属性名() default 值
- 设置数据类型与设置类时一致,但要注意设置基本数据类型时要给原始类型,不能给包裹类型
- 属性名后要加小括号
- default用于设置默认值
- 设置多个值,比如设置为数组时,要用大括号表示数组{},数组内各个元素用逗号隔开
实例:
设置注解属性
使用注解并给注解传值,传多个值时要用逗号隔开,并且写成k-v的格式
1.3 元注解
所谓元注解就是声明在注解上的注解,元注解是注解的一种声明,用于设置注解。
JDK1.5开始提供注解,给了4个注解,常用的是其中两个注解
@Retention | 保留期,声明注解的存活时间 |
---|---|
@Documented | 保留本类中的注解并能够被javadoc识别 |
@Target | 指定注解的运行地方(类/方法/变量等) |
@Inherited | 注解是否可以被子类继承 |
1.3.1 @Retention
Retention的意思是保留期(或者叫存活期)的意思,是指定该注解在JVM中的存活期的注解
存活期:源码阶段(.java文件) 编译阶段(.class) 运行阶段
不设置存活期时,默认存活期到编译阶段
RetentionPolicy.SOURCE | 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视 |
---|---|
RetentionPolicy.CLASS | 注解只被保留到编译进行的时候,它并不会被加载到JVM 中,默认时@Retention就设置为这个值 |
RetentionPolicy.RUNTIME | 注解可以保留到程序运行的时候,它会被加载进入到JVM 中,如果希望能在代码运行时取到注解的值,必须设置为这个值 |
源码说明:
这个注解只有一个属性,用于设置注解的保留期,该注解用枚举保存了三个值,根据传入的值确定设置的保留期
实际执行时,JAVA文件会被编译为字节码文件,此时代码从上至下执行,遇到注解时就会进入,然后读取@Retention以确定当前注解的保存期,再决定是否将这个注解保存在字节码中
代码:
使用:
1.3.2 @Target
指定当前声明的注解可运行的范围的标记,通过该注解可以指定声明的注解具体运行在类/方法/变量上等
ElementType.ANNOTATION_TYPE | 可以给一个注解进行注解 |
---|---|
ElementType.CONSTRUCTOR | 可以给构造方法进行注解 |
ElementType.FIELD | 可以给属性进行注解 |
ElementType.LOCAL_VARIABLE | 可以给局部变量进行注解 |
ElementType.METHOD | 可以给方法进行注解 |
ElementType.PACKAGE | 可以给一个包进行注解 |
ElementType.PARAMETER | 可以给一个方法内的参数进行注解 |
ElementType.TYPE | 可以给一个类型进行注解,比如类、接口、枚举 |
源码说明:
这个注解只有一个属性,用于设置的注解的可运行地点,该注解用枚举保存了十个值,根据传入的值确定注解能作用的地方
代码:
使用:
设置注解允许放的位置,可以只设置一个,也可以设置多个,设置多个时用大括号括起来,值之间用逗号隔开
此时如果注解放的地方不对,就会报错,如图放在构造方法上就报错了
1.4 获取类上的注解
JAVA提供了封装好的反射方法,基于Class对象,能获取到加在类上的注解
Class对象 . getAnnotation(注解名.class) | 返回类中指定名字的注解,此时得到的是一个注解对象 Annotation |
---|---|
Class对象 . getAnnotation() | 返回类中所有注解,此时得到的是一个注解数组 Annotation[] |
注解名 变量名 = (注解名) Annotation对象 | 通过上面的方法获得的Annotation对象需要强制转换为具体的注解,才能获取详细的属性 |
Annotation对象 . annotationType() | 获取到注解对象的全类名 |
注意:
getAnnotation()返回的是父接口类型的对象,就比如取一个对象,返回的是一个object对象,如果希望获取到对象中的具体的属性,必须向下造型。
方法:
实例 获取指定的注解:
①某个类设置的注解如图,一个类上可以设置多个注解,类中的方法或者变量也可以单独设置注解
②在test测试类中创建一个指向类的Class对象,再调用方法获取到类中指定名字的注解
③获取到注解对象后,可以进一步取值,注意必须使用强制转换
实例 获取多个注解:
获取到类中所有注解后,循环输出
1.5 获取类的构造器上的注解
如果需要获取加在类的构造器上的注解,不能通过类获取,得通过类的构造器
Constructor 变量名 = Class对象 . getConstructor() | 获取无参构造器 |
---|---|
Constructor 变量名 = Class对象 . getConstructor(String.class, String.class) | 通过参数类型获取有参的构造器,显然这得先知道想要的构造器的具体参数表 |
Constructor对象 . getAnnotation(注解名.class) | 返回类的构造器上指定名字的注解,此时得到的是一个注解对象 Annotation |
Constructor对象 . getAnnotation() | 返回类的构造器上所有注解,此时得到的是一个注解数组 Annotation[] |
注解名 变量名 = (注解名) Annotation对象 | 通过上面的方法获得的Annotation对象需要强制转换为具体的注解,才能获取详细的属性 |
注意:
getAnnotation()返回的是父接口类型的对象,就比如取一个对象,返回的是一个object对象,如果希望获取到对象中的具体的属性,必须向下造型。
实例:
Clazz指向的类的构造器:
对应的注解属性:
代码与结果:
①获取到的注解只是类的构造器上的值。
②注解的属性值被定义时就会修改,未被定义时就保持默认值
1.6 获取类的属性上的注解
如果需要取到类的属性上的注解,需要先获取到类的属性
Field 变量名 = Class对象 . getField( "变量名" ) | 获取类中指定名字的公开的成员变量,返回一个对象 |
---|---|
Field[] 变量名 = Class对象 . getFields() | 获取类中所有公开的成员变量,包括从父类继承的公开的成员变量,返回一个对象数组 |
Field 变量名 = Class对象 . getDeclaredField( "变量名" ); | 获取类中指定名字的成员变量,即便这个变量是否公开,返回一个对象 |
Field[] 变量名 = Class对象 . getDeclaredFields(); | 获取类中所有的成员变量,但不包括从父类继承的成员变量,返回一个对象数组 |
Field对象 . getAnnotation(注解名.class) | 返回类的构造器上指定名字的注解,此时得到的是一个注解对象 Annotation |
Field对象 . getAnnotation() | 返回类的构造器上所有注解,此时得到的是一个注解数组 Annotation[] |
注意:
通过类的属性获取到属性上的注解,直接就是注解对象,而不是父接口对象Annotation,不需要强制类型转换
实例: