注解
一、注解的概述
1.1注解的概念
- 注解是JDK1.5的新特性。
- 注解相当一种标记,是类的组成部分,可以给类携带一些额外的信息。
- 标记(注解)可以加在包,类,字段(成员变量),方法,方法参数以及局部变量上。
- 注解是给机器(jvm)看的,编译器或JVM可以根据注解来完成对应的功能;而注释是给人(程序员)看的!
1.2注解的作用
注解的作用就是给程序带入参数。【替换xml配置文件】
- JDK自带注解:
@Override:用于标记方法重写!(在编译阶段对重写的方法进行语法检查,若父类没有这个方法,或者你重写的方法签名错误,那么在编译阶段会报错!)
@SuppressWarnings:压制警告(防止在编码阶段,过多的警告,会影响程序员写代码的思路!)【后期投入使用的时候,需要将这个注解移除】
@Deprecated:标记方法过时(可能处于安全考虑,更换新的方法用于取代这个方法,但是考虑到JDK升级的兼容性,依旧保留了之前的这个方法,只是不建议使用!)
二、自定义注解
1.1 注解的本质
我们观看@SuppressWarnings注解的源代码,发现注解其本质就是一个接口!
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value(); // 注解的属性!
}
1.2 自定义注解格式
public @interface 注解名{
// 里面定义属性即可!
}
1.3 注解的属性
* 属性定义的格式:
格式1:数据类型 属性名();
格式2:数据类型 属性名() default 默认值;
* 属性定义的示例:
public @interface MyAnnotation {
// 为注解定义属性
包含属性:String value() ;//书名
包含属性:double price() ;//default 100价格,默认值为 100
包含属性:String[] authors() ;//多位作者
}
* 属性适用的数据类型
* 八种数据数据类型(int,short,long,double,byte,char,boolean,float)
* String,Class,注解类型,枚举类
* 以上类型的一维数组形式
1.4 使用自定义注解(为注解的属性赋值)
* 普通属性:
在使用注解的时候需要为注解的属性赋值!(定义注解属性给定的是什么类型的,那么使用的时候就给这个属性赋一个该类型的值)
* 特殊属性value:
如果注解中只有一个属性且名字叫value,则在使用该注解时可以直接给该属性赋值,而不需要给出属性名。
如果注解中除了value属性之外还有其他属性且只要有一个属性没有默认值,则在给属性赋值时value属性名也不能省略了。
* 小结:如果注解中只有一个属性时,一般都会将该属性名命名为value
/*
注解使用:
在方法上面添加自定义注解,然后为该注解的属性赋值!
*/
// 使用自定义注解的时候,需要为自定义注解的属性赋值!
@Book(value ="xxx", price = 68.0 , authors = {"传智播客","黑马程序员"})
public void method(){
}
}
// 若Book注解在定义的时候没有指定属性,那么使用这个注解的时候,不用为注解的属性赋值!
/*
① 若定义的注解中只有1个属性,而且属性的名字为value,那么在使用注解为属性赋值时,注解的属性名可以省略不写!(写上也不报错!)
*/
public @interface Book {
// 为注解定义属性
String value();
}
@Book("xxx") // 此处可以写成 @Book(value="xxxx",还可以省略属性名称value不写 @Book("yyyy"))
public void method(){
}
/*
② 若定义的注解中只有1个属性,属性的名字为value,并且为value赋默认值了,那么在使用注解为属性赋值时可以不用为注解属性赋值
*/
public @interface Book {
// 为注解定义属性
String value() default "vip";
}
@Book // 正确的!
public void method(){
}
//也可以这么干:
@Book(value="xxxx") // 正确的!
public void method(){
}
// 或者
@Book("xxxx") // 正确的!
public void method(){
}
1.5 为注解的属性赋值(各种类型演示)
自定义注解:
/*
注解属性支持的数据类型有:
* 八种数据数据类型(int,short,long,double,byte,char,boolean,float)
* String,Class,注解类型,枚举类
* 以上类型的一维数组形式
*/
public @interface itheima {
// 基本类型
char a();
// 字符串类型
String b();
// Class类型
Class c();
// 注解类型
MyAnnotation d();
// 枚举类型
Sex e();
// 数组
int[] f();
}
使用自定义注解(为注解的属性赋值):
/*
使用自定义注解@itheima
*/
public class TestItheima {
// 使用自定义注解,必须为注解的属性赋值!
@itheima(a = 'A', b = "666", c = Test01.class, d = @MyAnnotation(value = {"xxx", "ooo"}), e = Sex.FatBoy, f = {10, 20})
public void method() {
}
}
三、 元注解
元注解:对注解进行修饰的注解就是元注解!
Java官方提供的注解,任何官方提供的非元注解的定义都使用到了元注解。
常用的元注解
* @Target
作用:用来标识注解使用的位置,如果没有使用该注解标识,则自定义的注解可以使用在任意位置。
可使用的值定义在ElementType枚举类中,常量值如下
TYPE,类,接口
FIELD, 成员变量
METHOD, 成员方法
PARAMETER, 方法参数
CONSTRUCTOR, 构造方法
LOCAL_VARIABLE, 局部变量
......
* @Retention
作用:用来标识注解的生命周期(有效范围)
可使用的值定义在RetentionPolicy枚举类中,常用值如下
SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段
修改Book注解
@Target({ElementType.METHOD,ElementType.TYPE}) // 使用itheima注解只能作用于类(接口)上面或者方法上面!(用于其它位置就会报错!)
@Retention(RetentionPolicy.RUNTIME) // 使用注解,在代码运行的时候起到作用!
public @interface itheima {
// 基本类型
char a();
// 字符串类型
String b();
// Class类型
Class c();
// 注解类型
MyAnnotation d();
// 枚举类型
Sex e();
// 数组
int[] f();
}
四、注解解析
1.1 注解解析概念和原理
使用Java技术获得注解上数据的过程则称为注解解析
。与注解解析相关的接口
* Annotation: 注解类,该类是所有注解的父类。
* AnnotatedElement:该接口定义了与注解解析相关的方法(Method/Field/Constructor等都实现了该接口)
boolean isAnnotationPresent(Class<Annotation> annotationClass) //判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false
T getAnnotation(Class<T> annotationClass) // 根据注解类型获得对应注解对象
Annotation[] getAnnotations() //获得当前对象上使用的所有注解,返回注解数组,包含父类继承的
Annotation[] getDeclaredAnnotations() // 获得当前对象上使用的所有注解,返回注解数组,只包含本类的
* 获取注解数据的原理
注解作用在哪个成员上就会得该成员对应的对象来获得注解
比如注解作用成员方法,则要获得该成员方法对应的Method对象
比如注解作用在类上,则要该类的Class对象
比如注解作用在成员变量上,则要获得该成员变量对应的Field对象。
Field,Method,Constructor,Class等类都是实现了AnnotatedElement接口
1.2 注解解析演示
需求:
① 定义注解Book,要求如下:
② 定义BookStore类,在类和成员方法上使用Book注解
@Book(value = "JavaWeb核心指南", authors = {"张杰", "苏强"})
public class BookStore {
// 成员方法
@Book(value = "Linux删库跑路", authors = {"王金良", "何向日"}, price = 88)
public void show() {
}
}
③ 定义TestAnnotation测试类获取Book注解上的数据
/*
定义TestAnnotation测试类获取Book注解上的数据
比如注解作用成员方法,则要获得该成员方法对应的Method对象
比如注解作用在类上,则要该类的Class对象
比如注解作用在成员变量上,则要获得该成员变量对应的Field对象。
*/
public class TestAnnotaion {
/*
注解解析,获得BookStore类上面Book注解的里面属性对应的值
*/
@Test
public void testType(){
// 获得Class对象
Class<BookStore> bookStore = BookStore.class;
// 判断类BookStore上面有没有使用Book注解!
if(bookStore.isAnnotationPresent(Book.class)){
// 获得类BookStore上面的注解对象!
Book book = bookStore.getAnnotation(Book.class);
// 获得注解属性的值
String name = book.value();
String[] authors = book.authors();
double price = book.price(); // 获得默认值 100
// 打印
System.out.println("书名:" + name);
System.out.println("作者:" + Arrays.toString(authors));
System.out.println("价格:" + price);
}
}
/*
注解解析,获得BookStore类中show方法上面Book注解里面的属性对应的值
*/
@Test
public void testMethod() throws NoSuchMethodException {
// 获得字节码对象
Class<BookStore> bookStore = BookStore.class;
// 获得指定的方法对象
Method show = bookStore.getMethod("show");
// 判断show方法上面有没有使用@Book注解
if(show.isAnnotationPresent(Book.class)){
// 通过Method对象获得show方法上面的注解对象!
Book book = show.getAnnotation(Book.class);
// 获得注解属性的值
String name = book.value();
String[] authors = book.authors();
double price = book.price(); // 获得默认值 100
// 打印
System.out.println("书名:" + name);
System.out.println("作者:" + Arrays.toString(authors));
System.out.println("价格:" + price);
}
}
}
五、注解总结
一、注解的概念
1.注解是JDK1.5的新特性。
2. 注解相当一种标记,是类的组成部分,可以给类携带一些额外的信息。
3.标记(注解)可以加在包,类,字段(成员变量),方法,方法参数以及局部变量上。
4. 注解是给机器(jvm)看的,编译器或JVM可以根据注解来完成对应的功能;而注释是给人(程序员)看的!
二、自定义注解格式及属性格式
- public @interface 注解名{
// 里面定义属性即可!
} - 属性定义的格式:
格式1:数据类型 属性名();
格式2:数据类型 属性名() default 默认值;
三、元注解 - @Target 作用:用来标识注解使用的位置,如果没有使用该注解标识,则自定义的注解可以使用在任意位置。
可使用的值定义在ElementType枚举类中,常量值如下
TYPE,类,接口
FIELD, 成员变量
METHOD, 成员方法
PARAMETER, 方法参数
CONSTRUCTOR, 构造方法
LOCAL_VARIABLE, 局部变量
- @Retention 作用:用来标识注解的生命周期(有效范围)
可使用的值定义在RetentionPolicy枚举类中,常用值如下
SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段
四、注解解析
* Annotation: 注解类,该类是所有注解的父类。
* AnnotatedElement:该接口定义了与注解解析相关的方法(Method/Field/Constructor等都实现了该接口)
boolean isAnnotationPresent(Class<Annotation> annotationClass) //判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false
T getAnnotation(Class<T> annotationClass) // 根据注解类型获得对应注解对象
Annotation[] getAnnotations() //获得当前对象上使用的所有注解,返回注解数组,包含父类继承的
Annotation[] getDeclaredAnnotations() // 获得当前对象上使用的所有注解,返回注解数组,只包含本类的
* 获取注解数据的原理
注解作用在哪个成员上就会得该成员对应的对象来获得注解
比如注解作用成员方法,则要获得该成员方法对应的Method对象
比如注解作用在类上,则要该类的Class对象
比如注解作用在成员变量上,则要获得该成员变量对应的Field对象。
Field,Method,Constructor,Class等类都是实现了AnnotatedElement接口