注解随笔
⚫ 注解的定义以及使用
/*
自定义注解的格式:
public @interface 注解名 {
}
*/
public class Demo02Anno {
@Student(name = "王叔叔", age = 18, hobbies = "洗脚")
public void method() {
}
}
/*
在注解中,可以定义一些属性
属性格式:
数据类型 属性名();
数据类型 属性名() default 默认值;
注解中的属性的数据类型只能是下面这几种
1. 八种基本数据类型(byte short int long float double boolean char)
2. Class, String, 枚举, 注解
3. 以上所有类型的一维数组。
注解可以加在类上面, 方法上, 成员变量上, 方法参数上....
使用格式为@注解名
给注解属性赋值的格式
@注解名(属性名=属性值, 属性名=属性值)
注意:
1. 如果注解中的属性没有默认值,那么在使用的时候必须要进行赋值
2. 如果注解中的属性有默认值,那么在使用的时候可以赋值也可以不赋值, 如果不赋值该属性的值就是默认值。
3. 如果注解中的属性是一个数组, 那么在赋值的使用可以使用大括号包裹多个内容。
4. 如果注解中的属性是一个数组, 在赋值的时候只需要赋值一个元素,那么可以省略大括号。
*/
public @interface Student {
//姓名
String name();
//年龄属性,默认值为0
int age() default 0;
//爱好属性
String[] hobbies();
}
16. 注解中的特殊属性value
/*
特殊属性value
如果一个注解中只有一个没有默认值的属性(可以有多个属性,但是没有默认值必须是1个), 并且这个属性叫做value,那么在给该属性赋值的使用,可以省略属性名。否则必须写全。
*/
public @interface Book {
String value();
int price() default 10;
}
@Book("西游记")
public class Demo03Anno {
@Book("红楼梦")
int num;
@Book("三国演义")
public void method() {
}
}
17. Target元注解的使用
/*
元注解:
1. 元注解也是注解。
2. 元注解是用来修饰注解的注解。
3. 元注解要加在注解上面, 可以对某些注解进行一些限制。
常见的元注解:
1.@Target
2.@Retention
*/
@MyAnno
public class Demo01Anno {
@MyAnno
public void method() {
}
}
/*
@Target是一个元注解,用来修饰注解。
@Target用来限制注解的使用位置, 如果不使用@Target进行限制,那么注解可以在任何位置使用。
Target中有一个属性叫做value, 这个属性用来表示被修饰的注解可以使用在哪些位置。
value是ElementType数组类型, 里面可以传递多个数据。
ElementType是一个枚举,枚举就是一个特殊的类, 枚举中的每一个属性都是本身类型, 枚举中的属性可以通过枚举名直接调用。
ElementType中的每一个属性都有特别的含义:
ElementType.TYPE: 用在类,接口上
ElementType.FIELD:用在成员变量上
ElementType.METHOD: 用在方法上
ElementType.PARAMETER:用在参数上
ElementType.CONSTRUCTOR:用在构造方法上
ElementType.LOCAL_VARIABLE:用在局部变量上
我们要向Target的value属性位置传递ElementType中的属性,不同的属性有不同的含义。
*/
//@Target(ElementType.TYPE)//被修饰的注解只能使用在类的上面。
//@Target(ElementType.METHOD) //被修饰的注解只能用在方法上
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnno {
}
18. Retention元注解的使用
@MyAnno1
@MyAnno2
@MyAnno3
public class Demo02Anno {
}
/*
@Retention 元注解, 用来修饰注解。
@Retention用来限制注解的生命周期, 如果使用@Retention修饰, 注解默认只在源代码阶段以及.class文件中有效,运行时期内存中是没有的。
Retention只有一个属性叫做value, 这个属性是RetentionPolicy类型。 该属性表示的是被修饰的注解的生命周期。
RetentionPolicy是一个枚举类型, 里面的每一个属性都有特别的含义。 我们要向Retention的value属性位置传递RetentionPolicy的属性。
RetentionPolicy每个属性的含义:
RetentionPolicy.SOURCE: 被修饰的注解只在源代码阶段有效, 一旦编译,到了.class中就会消失。
RetentionPolicy.CLASS: 被修饰的注解只在源代码以及编译后的.class中有效
RetentionPolicy.RUNTIME: 被修饰的注解在源代码阶段,编译后的.class中,运行时内存中有效。
*/
@Retention(RetentionPolicy.SOURCE)//表示被修饰的注解只在源代码阶段有效
public @interface MyAnno1 {
}
@Retention(RetentionPolicy.CLASS)//被修饰的注解在源代码以及class中有效
public @interface MyAnno2 {
}
@Retention(RetentionPolicy.RUNTIME)//被修饰的注解在源代码,class,运行时内存中都有效。
public @interface MyAnno3 {
}
19. 注解的解析
/*
注解的解析: 注解解析就是获取注解中的内容(比如属性),并进行处理。
解析相关的API:
Annotation:接口, 所有注解都默认实现了这个接口。
AnnotatedElement: 接口, 里面定义了很多方法可以操作注解
Annotation[] getAnnotations():获取所有的注解
T getAnnotation(Class annotationClass):获取指定的注解, 方法参数传递的是哪个注解的Class,那么获取的就是哪个注解。
boolean isAnnotationPresent(Class annotationClass): 判断指定注解是否存在。 参数为注解的Class。
解析注解需要结合反射技术去使用, 我们之前学习的Class,Method,Constructor,File反射有关的都实现了AnnotatedElement接口
如果要操作类上面的注解,那么我们就使用Class调用AnnotatedElement中的方法操作注解就可以了
如果要操作方法上面的注解,那么我们就使用Method调用AnnotatedElement中的方法操作注解就可以了
如果要操作成员变量上面的注解,那么我们就使用Field调用AnnotatedElement中的方法操作注解就可以了
*/
//获取BookStore这个类上面的Book注解中的属性,并进行输出。
public class Demo01AnnoParse {
public static void main(String[] args) throws ClassNotFoundException {
//因为要获取BookStore类上面的注解,所以要先获取BookStore的Class对象
Class clazz = Class.forName("cn.itcast.demo05_anno_parse.BookStore");
//调用isAnnotationPresent判断这个类上面有么有注解。
boolean flag = clazz.isAnnotationPresent(Book.class);//判断有没有Book注解
//判断,如果有注解,那么就获取该注解
if(flag) {
//获取BookStore这个类上面Book注解
Annotation a = clazz.getAnnotation(Book.class);
//向下转型
Book book = (Book)a;
//获取book中的属性并输出
System.out.println(book.value());
System.out.println(book.price());
System.out.println(book.author());
}
}
}
@Book(value = "Java从入门到精通", author = "佚名")
public class BookStore {
}
@Retention(RetentionPolicy.RUNTIME) //修改该注解的生命周期,让这个注解在运行时期内存中也有效。
public @interface Book {
//value表示书名
String value();
//price表示价格
int price() default 100;
//author 作者
String author();
}
20. 模拟单元测试
/*
练习: 定义@MyTest注解, 模拟单元测试。
定义@MyTest注解,在多个方法上面加上这个@MyTest注解,然后运行带有@MyTest注解的方法。
步骤:
获取MyTestDemo的所有的方法,遍历这些方法,判断遍历到的方法上有没有@Test注解,如果有,就让该方法执行。
*/
public class Demo01Test {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
//获取MyTestDemo的Class对象
Class clazz = Class.forName("cn.itcast.demo06_anno_test.MyTestDemo");
//创建对象,以后调用方法使用。
Object obj = clazz.newInstance();
//clazz调用getMethods,获取到所有的方法(public权限)
Method[] methods = clazz.getMethods();
//遍历这些方法
for (Method method : methods) {
//判断遍历到的方法上有没有MyTest注解
if(method.isAnnotationPresent(MyTest.class)) {
//如果方法上有这个注解,那么就让这个方法执行。
method.invoke(obj);
}
}
}
}
@Retention(RetentionPolicy.RUNTIME) //使用元注解修饰, 让该注解在运行时期内存中也有效。
@Target(ElementType.METHOD)//限制该注解只能用在方法上。
public @interface MyTest {
}
public class MyTestDemo {
public void methodA() {
System.out.println("methodA....");
}
@MyTest
public void methodB() {
System.out.println("methodB....");
}
public void methodC() {
System.out.println("methodC....");
}
@MyTest
public void methodD() {
System.out.println("methodD....");
}
public void methodE() {
System.out.println("methodE....");
}
}