java高级之注解
注解的概念:
注解是JDK1.5的新特性。
- 注解相当一种标记,是类的组成部分,可以给类携带一些额外的信息。
- 注解可以加在包,类,字段,方法,方法参数以及局部变量上。
- 注解是给编译器看的,编译器可以根据注解来完成对应的功能。
注解的作用:给程序带入参数。
注解的定义格式:
修饰符 @interface 注解名{
属性
}
注解属性的定义格式:
- 格式1:数据类型 属性名(); 没有默认值的,使用时必须赋值。
- 格式2:数据类型 属性名() default 默认值; 有默认值的,使用时如果不赋值就会使用默认值,如果赋值就会覆盖掉默认值。
注解中能够定义什么类型的属性:
- 8种基本数据类型。
- String类型。
- Class类型。
- enum类型。
- 枚举类型。
- 以及上面所有的一维数组类型。
自定义注解示例代码:
public @interface MyAnnotation {
//String类型属性
String name();
//int类型属性
int age() default 20;
//String数组类型属性
String[] works();
}
注解使用的注意事项:
- 空注解可以直接使用。
- 一个对象中不能连续使用同一个注解多次,但是一个对象中可以使用多个不同的注解。
(不同的位置可以使用一样的注解,但是同样的位置不能使用一样的注解) - 使用带有属性注解的时候,注解中的属性一定要赋值,如果有多个属性,用(逗号)隔开,如果注解中的属性有数组,那么如果数组只有一个元素值,那么{}不用写,反之用写。
- 如果注解中的属性值有默认值,那么我们不必要写,也不用重新赋值,反之必须写上。
- 如果注解中只有一个属性,并且属性名叫value,那么使用注解的时候,属性名不用写。
注解的解析:
注解的解析就是获取注解中的属性值。
需要用到的接口:
- AnnotatedElement
需要用到的方法:
- boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判断该对象上是否存在指定的注解,传递的参数是 注解.class
- Annotation getAnnotation(Class annotationClass):返回该注解对象,传递什么类型,返回什么类型,传递的参数是 注解.class
代码演示:
//自定义注解代码,上面这两个元注解后面会说到
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
//String类型属性
String name();
//int类型属性
int age() default 20;
//String数组类型属性
String[] works();
}
//测试代码
//使用注解并赋值参数,有默认值的可以不赋值,如果本身有默认值,再次赋值会覆盖掉默认值
@MyAnnotation(name="猪皮",works={"写代码","测试代码"})
public class Test {
public static void main(String[] args)throws Exception {
//获取当前类对象的Class对象
Class c = Class.forName("cn.it.Work1.Test");
//判断当前类对象上是否有该注解
if(c.isAnnotationPresent(MyAnnotation.class)){
//如果有就获取当前注解对象
MyAnnotation m = (MyAnnotation) c.getAnnotation(MyAnnotation.class);
//输出属性内容
System.out.println(m.name());
System.out.println(m.age());
//遍历数组元素
for (String work : m.works()) {
System.out.println(work);
}
}
}
}
测试结果:
猪皮
20
写代码
测试代码
元注解:
元注解的作用:
- 控制自定义的注解可以写在哪里,(类,方法,变量上,包…)
- 控制自定义注解的生命周期
元注解1:@Target (作用域)
@Target 作用: 指定注解可出现的位置。
- 点进@Target底层发现,底层是 ElementType[] value(); 数组,可以赋值多个。
- 点进ElementType底层发现,底层的 ElementType的数据类型,是枚举,枚举的属性,都是静态修饰,直接类名调用。
ElementType中的属性:
-
TYPE:注解可以写在类上
-
FIELD:注解可以写在成员变量上
-
METHOD:注解可以写在方法上
-
PARAMETER:注解可以写在方法参数上
-
CONSTRUCTOR:注解可以写在构造方法上
注意:如果自定义注解的时候,不加该注解 (@Target) 那么默认就是在什么上面都可以使用。
元注解2:@Retention (生命周期)
@Retention 作用:指定注解的声明周期。
1.点到Retention底层发现,底层的 RetentionPolicy value(); 不是数组,只能赋值一个。
2.点到RetentionPolicy底层发现,底层的 RetentionPolicy数据类型是枚举,枚举的属性,都是静态修饰,直接类名调用。
RetentionPolicy中的属性:
- SOURCE(默认级别) 注解仅存在于源码中的java文件中(不在class文件中,也不在方法区中)。
- CLASS 注解存在于编译后的class文件中->Class文件中出现了,方法区中没有。
- RUNTIME 注解存在于运行时期的内存中–>方法区中出现了,一旦在方法区中出现了,我们才能利用反射获取到注解。
案例演示:
要求:模仿Junit中的@Test,让带有该注解的方法执行。
//定义一个空注解 MyTest
@Retention(RetentionPolicy.RUNTIME) //生命周期是运行时期生命周期
@Target(ElementType.METHOD) //只能作用在方法上
public @interface MyTest {
}
//测试
public class Work2 {
public static void main(String[] args)throws Exception {
//获取Work2的Class类对象
Class c = Work2.class;
//根据Class类对象获取所有public方法
Method[] methods = c.getMethods();
//根据Class对象获取当前类对象
Object o = c.newInstance();
//循环遍历所有的方法
for (Method method : methods) {
//判断如果存在 @MyTest 注解就返回 true
boolean flag = method.isAnnotationPresent(MyTest.class);
if (flag){
//执行方法
method.invoke(o);
}
}
}
@MyTest
public void method1(){
System.out.println("我是method1");
}
@MyTest
public void method2(){
System.out.println("我是method2");
}
public void method3(){
System.out.println("我是method3");
}
}
测试结果:带 @MyTest 注解的方法都被执行了。
我是method1
我是method2
注解解析案例:
//指的是作用在类上和方法上,如果不配置的话默认是在任何地方都可以使用
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) //存在于运行时期的内存中
public @interface MyPerson {
String name();
//有默认值的
float salary() default 2500.f;
int[] number();
}
//如果给数组赋值时,只有一个值不需要{},如果两个值要加上{}
@MyPerson(name = "猪皮",number = {1,2})
public class MyPersonTest {
public static void main(String[] args)throws Exception {
System.out.println("=============使用当前类对象对注解进行解析=============");
//获取类的Class对象
Class c = MyPersonTest.class;
//判断该类上是否包含指定注解
boolean flag = c.isAnnotationPresent(MyPerson.class);
if (flag) {
//如果有该注解,就获取该注解对象,并且强转成该类型
MyPerson mp = (MyPerson) c.getAnnotation(MyPerson.class);
//输出属性
System.out.println(mp.name());
System.out.println(mp.salary());
for (int i : mp.number()) {
System.out.println(i);
}
}
System.out.println("=============使用Method对象对注解进行解析=============");
method();
}
@MyPerson(name = "奥哥",salary = 3000.f,number = 5)
public static void method() throws Exception{
//获取类的Class对象
Class c = MyPersonTest.class;
//获取方法的Class对象
Method method = c.getMethod("method");
//判断***方法***上是否包含MyPerson注解
if (method.isAnnotationPresent(MyPerson.class)){
//获取MyPerson注解中的属性
MyPerson mp = method.getAnnotation(MyPerson.class);
//输出属性
System.out.println(mp.name());
System.out.println(mp.salary());
for (int i : mp.number()) {
System.out.println(i);
}
}
}
}
测试结果:使用不同的对象,解析不同作用域的注解
=============使用当前类对象对注解进行解析=============
猪皮
2500.0
1
2
=============使用Method对象对注解进行解析=============
奥哥
3000.0
5
如果有缺少的地方,请各位指点,我在加上。
转载:https://blog.csdn.net/weixin_45216092/article/details/105297692
查看评论