java-注解

文章封面
摘要: 注解注解概述Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。Java 语言中的类、构造器、方法、成员变量、参数等都可以被注解进行标注。注解的作用对Ja

注解

注解概述

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。

Java 语言中的类、构造器、方法、成员变量、参数等都可以被注解进行标注。

image-20220728105523921

注解的作用

对Java中类、方法、成员变量、方法形参做标记,然后进行特殊处理,至于到底做何种处理由业务需求来决定。

例如:JUnit框架中,标记了注解@Test的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行。

自定义注解

自定义注解就是自己做一个注解来使用。

image-20220728110702544

自定义注解-格式:

image-20220728105740175

特殊属性:

value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写!!但是如果有多个属性, 且多个属性没有默认值,那么value名称是不能省略的。

自定义注解案例:

注解类1:

package com.itcast.annotation;

public @interface Book {//注解

String value(); //特殊属性

double price() default 22;
}

注解类2:

package com.itcast.annotation;

/**
* Author:lzj
* Create:2022-07-28-11:05
* Describe:
*/
public @interface MyBook { //MyBook为注解名称
//定义注解属性[和默认值]
public String name();
public String[] authors();
public double price();
public int age() default 18;
}

注解使用:

package com.itcast.annotation;
import org.junit.Test;
/**
* Author:lzj
* Create:2022-07-28-11:04
* Describe:学会自定义注解,掌握其定义格式和语法
*/
@MyBook(name = "JavaSE", authors = {"黑马", "尚硅谷", "千锋"}, price = 1999.5)
//@Book(value="/delete")
@Book("/delete")
public class AnnotationDemo1 {

@MyBook(name = "JavaSE", authors = {"黑马", "尚硅谷", "千锋"}, price = 1999.5)
public AnnotationDemo1() {
}
@MyBook(name = "JavaSE", authors = {"黑马", "尚硅谷", "千锋"}, price = 1999.5)
public static void main(String[] args) {
int age = 21;
}
}

元注解

元注解:注解注解的注解。【自定义注解类上的注解】

元注解常见有两个:

@Target: 约束自定义注解只能在哪些地方使用

@Target中可使用的值定义在ElementType枚举类中,常用值如下:

ElementType.TYPE,类,接口

ElementType.FIELD, 成员变量

ElementType.METHOD, 成员方法

ElementType.PARAMETER, 方法参数

ElementType.CONSTRUCTOR, 构造器

ElementType.LOCAL_VARIABLE, 局部变量

@Retention:约束自定义注解的存活范围。

@Retention中可使用的值定义在RetentionPolicy枚举类中,常用值如下:

RetentionPolicy.SOURCE: 注解只作用在源码阶段,生成的字节码文件中不存在

RetentionPolicy.CLASS: 注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值.

RetentionPolicy.RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)

设置注解的作用范围:

image-20220728112753173

设置注解的存活范围:

image-20220728114201762

注解解析

注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容。

与注解解析相关的接口:

Annotation: 注解的顶级接口,注解都是Annotation类型的对象

AnnotatedElement:该接口定义了与注解解析相关的解析方法

方法说明
Annotation[] getDeclaredAnnotations()获得当前对象上使用的所有注解,返回注解数组。
T getDeclaredAnnotation(Class<T> annotationClass)根据注解类型获得对应注解对象
boolean isAnnotationPresent(Class<Annotation> annotationClass)判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false

所有的类成分Class, Method , Field , Constructor,都实现了AnnotatedElement接口他们都拥有解析注解的能力

解析注解的技巧:

注解在哪个成分上,我们就先拿哪个成分对象。

比如注解作用成员方法,则要获得该成员方法对应的Method对象,再来拿上面的注解

比如注解作用在类上,则要该类的Class对象,再来拿上面的注解

比如注解作用在成员变量上,则要获得该成员变量对应的Field对象,再来拿上面的注解

注解解析的案例:

需求:注解解析的案例

分析

①定义注解Book,要求如下: - 包含属性:String value() 书名 - 包含属性:double price() 价格,默认值为 100 - 包含属性:String[] authors() 多位作者 - 限制注解使用的位置:类和成员方法上 - 指定注解的有效范围:RUNTIME

②定义BookStore类,在类和成员方法上使用Book注解

③定义AnnotationDemo03测试类获取Book注解上的数据

注解类@Book:

package com.itcast.annotation;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
String value(); //特殊属性
double price() default 100;
String[] authors();
}

BookStore类使用@Book注解:

package com.itcast.annotation;

/**
* Author:lzj
* Create:2022-07-28-11:52
* Describe:
*/
@Book(value = "《Java语言程序设计》", price = 59.9, authors = {"11", "22"}) //作用在类上
public class BookStore {
int cc;

@Book(value = "《西游记》", price = 39.9, authors = {"罗贯中", "..."}) //作用在成员方法上
public void test() {

}
}

测试类:【解析注解】

package com.itcast.annotation;
import org.junit.Test;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* Author:lzj
* Create:2022-07-28-11:22
* Describe:完成注解解析
*/
public class AnnotationDemo3 {
@Test
public void parseClass() throws Exception {
//先得到类对象
Class c = BookStore.class;
//判断当前(类)对象是否使用了指定注解
if (c.isAnnotationPresent(Book.class)) {
//根据注解类型获得对应注解对象(此注解对象是类上的)
Book book = (Book) c.getDeclaredAnnotation(Book.class);
//获取注解对象的属性值(这里是获取写在类上的注解的属性值)
System.out.println("book.value:" + book.value());
System.out.println("book.price:" + book.price());
System.out.println("book.authors:" + Arrays.toString(book.authors()));
/**
book.value:《Java语言程序设计》
book.price:59.9
book.authors:[11, 22]
*/
}
//获得BookStore类成员方法对象
Method test = c.getDeclaredMethod("test");
//判断当前成员方法对象是否使用了@Book注解
if (test.isAnnotationPresent(Book.class)) {
//根据注解类型获得对应注解对象(此注解对象是类中成员方法上的)
Book book = test.getDeclaredAnnotation(Book.class);
//获取注解对象的属性值(这里是获取写在类中成员方法上的注解的属性值)
System.out.println("book.value:" + book.value());
System.out.println("book.price:" + book.price());
System.out.println("book.authors:" + Arrays.toString(book.authors()));
/**
book.value:《西游记》
book.price:39.9
book.authors:[罗贯中, ...]
*/
}
}
}

注解的应用场景一:junit框架

需求

定义若干个方法,只要加了MyTest注解,就可以在启动时被触发执行

分析

①定义一个自定义注解MyTest,只能注解方法,存活范围是一直都在。

②定义若干个方法,只要有@MyTest注解的方法就能在启动时被触发执行,没有这个注解的方法不能执行。

package com.itcast.annotation;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class AnnotationDemo4 {
@MyTest
public void test1() {
System.out.println("====test1====");
}

public void test2() {
System.out.println("====test2====");
}

@MyTest
private void test3() {
System.out.println("====test3====");
}


/**
* 启动类,有注解的方法才被调用
*
* @param args
*/
public static void main(String[] args) throws Exception, IllegalAccessException {
//a,获取类对象
Class c = AnnotationDemo4.class;
//b,提取全部方法对象
Method[] methods = c.getDeclaredMethods();
//c,遍历方法,查看是否有MyTest注解,有就run它
for (Method method : methods) {
//查看成员方法是否有MyTest注解
if (method.isAnnotationPresent(MyTest.class)) {
//执行方法
//获取构造器对象
Constructor constructor = c.getDeclaredConstructor();
//使用构造器对象创建对象
AnnotationDemo4 annotationDemo4 = (AnnotationDemo4) constructor.newInstance();
//也可以直接在前面使用:AnnotationDemo4 annotationDemo41 = new AnnotationDemo4();创建对象使用
method.invoke(annotationDemo4);
}
}

}
}
//结果:
====test1====
====test3====

546 阅读 ← 返回技术栈
图片放大