【重难点】注解
一、概念
1、概念--Annotation
是 JDK5.0 引入的一种注释机制。 Java 语言中的类、方法、变量、参数和包等都可以被标注,用于说明程序,给计算机看。
(注释:用文字描述 程序,给程序员看)
2、使用:
- @注解名称
- @Override重写
- @Test
3、作用
- 编译检查
- 生成doc文档【文档注释】
- javadoc HelloWorld.java
- /**
- *@author ljh
- */
- 代码分析
4、常见的内置注解(Java预定义的注解)
- @Override:检查是否是重写(父类/接口)的方法
- @Deprecated:标记过时方法,编译时会警告
- @SuppressWarnings/@SuppressWarnings("all"):忽略注解中声明的警告
二、自定义注解
1、格式
元注解 public @interface 注解名称(){ 属性列表 }
2、本质
反编译后
本质上是一个接口,该接口默认继承Annotation 接口
Annotation 接口:所有注释类型扩展的公共接口,手动扩展这个接口不限定注释类型,此接口本身并不定义注释类型。
3、属性
接口中可以定义的抽象成员方法
要求
- 属性方法返回值
- 基本数据类型
- String
- 枚举
- 注解
- 上述类型的数组
- 不包括void空类型
- 使用时需要给属性赋值
- 数组赋值时需要使用{}包裹,一个元素可以省略
- 只有一个属性需要赋值且属性名为value时,可只写值省略value
- @SuppressWarnings("all")的属性是一个字符数组String[] value;
1 package com.liujinhui.Day1209BaseEnhance.annotation; 2 public @interface MyAnno { 3 int age(); 4 String name() default "张三"; 5 Person per(); 6 MyAnno2 anno2(); 7 String[] show3(); 8 } 9 10 @MyAnno(age = 1,name="张三")//所以称为属性 11 public void demo(){ 12 show1(); 13 Date date=new Date(); 14 }
4、元注解:描述注解的注解
1 @Target(ElementType.METHOD)//作用位置:方法 2 @Retention(RetentionPolicy.SOURCE)//能被保留到什么阶段:Source源码阶段 3 public @interface ZJName { 4 }
-
@Documented:描述 注解是否被抽取到API文档中
-
@Inherited:描述注解是否被子类继承,加注解后,子类会自动继承父类的注解
- @Target:描述注解能够作用的位置
- @Target(value = {ElementType.TYPE})//表示该Anno3注解可以作用于类上
-
@Target(value = {ElementType.METHOD})//表示该Anno3注解可以作用于方法上
-
@Target(value = {ElementType.FIELD})//表示该Anno3注解可以作用于成员变量上
-
@Target(value = {ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
- @Retention:描述注解被保留的阶段(Source/Class/Runtime)
- @Retention(RetentionPolicy.RUNTIME)当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
使用:自定义@MyAnno3注解
1 import java.lang.annotation.*; 2 @Target(value = {ElementType.TYPE,ElementType.FIELD,ElementType.METHOD}) 3 @Retention(RetentionPolicy.RUNTIME) 4 @Documented 5 //可以抽取到文档中 6 @Inherited 7 public @interface MyAnno3 { 8 }
5、解析注解:获取注解中的属性值
步骤:
- 获取注解定义的位置的对象(Class,Method,Field)
-
获取指定注解 getAnnotation(Class)
1 //其实就是在内存中生成了一个该注解接口的子类实现对象 2 public class ProIMpl implements Pro{ 3 public String className(){ 4 return"com.liujinhui.Day1209BaseEnhance.annotation.Demo1"; 6 } 7 public String methodName(){ 8 return "show"; 9 } 10 }
- 调用注解中的抽象方法获取配置的属性值
三、案例
1、自定义注解执行任意类的任意方法
1 package com.liujinhui.Day1209BaseEnhance.annotation; 2 3 public class Demo1 { 4 public void show(){ 5 System.out.println("demo1 show"); 6 } 7 }
1 package com.liujinhui.Day1209BaseEnhance.annotation; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 /* 9 描述需要执行的类名和方法名 10 */ 11 @Target({ElementType.TYPE}) 12 @Retention(RetentionPolicy.RUNTIME) 13 public @interface Pro { 14 String className(); 15 String methodName(); 16 } 17 /* 18 public class ProIMpl implements Pro{ 19 public String className(){ 20 return "com.liujinhui.Day1209BaseEnhance.annotation.Demo1"; 21 } 22 public String methodName(){ 23 return "show"; 24 } 25 26 */
1 package com.liujinhui.Day1209BaseEnhance.annotation; 2 import java.io.InputStream; 3 import java.lang.reflect.Method; 4 import java.util.Properties; 5 /* 6 假设的框架类 7 改配置文件使程序的扩展性更强,配置文件中使用了全类名,则使用了反射机制 8 * */ 9 @Pro(className = "com.liujinhui.Day1209BaseEnhance.annotation.Demo1",methodName = "show") 10 //要写全类名 11 public class ReflectTest { 12 /** 13 * @author: Liu Jinhui 14 * @description: 创建任意对象 15 * @date: 2020/12/9 20:42 16 * @return * @param null 17 */ 18 public static void main(String[] args) throws Exception{ 19 //可以创建任意类的对象,可以执行任意方法 20 /* 21 前提:不能改变该类的任何代码,可以创建任意类的对象,可以执行任意方法 22 * */ 23 //1.解析注解 24 //1.1获取该类的字节码文件对象 25 Class<ReflectTest> reflectTestClass = ReflectTest.class; 26 //2.获取上面的注解对象 27 //method也有getAnno 28 Pro an = reflectTestClass.getAnnotation(Pro.class); 29 //其实就是在内存中生成了一个该注解接口的子类实现对象 30 /* 31 public class ProIMpl implements Pro{ 32 public String className(){ 33 return "com.liujinhui.Day1209BaseEnhance.annotation.Demo1"; 34 } 35 public String methodName(){ 36 return "show"; 37 } 38 */ 39 //3.调用注解对象中调用的抽象方法,获取返回值 40 String className = an.className(); 41 String methodName = an.methodName(); 42 System.out.println(className+methodName); 43 //4.加载该类进内存 44 Class cls = Class.forName(className); 45 //5.创建对象 46 Object obj = cls.newInstance(); 47 //6.获取方法对象 48 Method method = cls.getMethod(methodName); 49 //7.执行方法 50 method.invoke(obj); 51 } 52 }
2、通过注解实现简单的测试框架
要求:
当主方法执行后,会自动执行被检测的所有方法(加了@Check的方法)
1 package com.liujinhui.Day1209BaseEnhance.annotation.demo; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 @Target(value = {ElementType.METHOD}) 9 @Retention(RetentionPolicy.RUNTIME) 10 @interface Check { 11 }
1 package com.liujinhui.Day1209BaseEnhance.annotation.demo; 2 3 /** 4 * 小明定义的计算器类 5 * 需要测试是否有错误 6 */ 7 public class Calculator { 8 //加法 9 @Check 10 public void add(){ 11 System.out.println("1+0="+(1+0)); 12 } 13 //减法 14 @Check 15 public void sub(){ 16 System.out.println("1 - 0 ="+(1 - 0)); 17 } 18 //乘法 19 @Check 20 public void mul(){ 21 System.out.println("1*0="+(1*0)); 22 } 23 //除法 24 @Check 25 public void div(){ 26 System.out.println("1/0="+(1/0)); 27 } 28 //结果 29 public void show(){ 30 System.out.println("永无bug..."); 31 } 32 }
1 package com.liujinhui.Day1209BaseEnhance.annotation.demo; 2 3 import java.io.BufferedWriter; 4 import java.io.FileWriter; 5 import java.io.IOException; 6 import java.lang.reflect.InvocationTargetException; 7 import java.lang.reflect.Method; 8 9 /** 10 * 简单的测试框架 11 * 当主方法执行后,会自动执行被检测的所有方法(加了@Check的方法) 12 * 判断方法是否有异常,并记录到文件中 13 */ 14 public class TestCheck { 15 public static void main(String[] args) throws IOException { 16 //1.创建计算器对象 17 Calculator c = new Calculator(); 18 //2.获取字节码文件对象 19 Class cls = c.getClass(); 20 //3.获取所有的方法 21 Method[] methods = cls.getMethods(); 22 int number=0;//记录异常出现的次数 23 BufferedWriter bw=new BufferedWriter(new FileWriter("bug.txt")); 24 for (Method method : methods) { 25 //4.判断方法上是否有check注解 26 if (method.isAnnotationPresent(Check.class)) { 27 //判断当前方法上有无指定注解 28 //5.有就执行该方法 29 try { 30 method.invoke(c); 31 } catch (Exception e) { 32 //6.捕获异常 33 number++; 34 //记录到文件中 35 bw.write(method.getName() + "方法出异常了"); 36 bw.newLine(); 37 bw.write("异常的名称:" + e.getCause().getClass().getSimpleName()); 38 bw.newLine(); 39 bw.write("异常的原因:" + e.getCause().getMessage()); 40 bw.newLine(); 41 bw.write("-----------------------"); 42 } 43 } 44 } 45 bw.write("本次测试共出现"+ number +"次异常"); 46 bw.flush(); 47 bw.close(); 48 } 49 }
3、总结
- 常用jdk内置注解而不是自定义注解
- 注解给编译器解析程序用
- 注解不是程序的一部分,而是相当于程序的标签
本文来自博客园,作者:哥们要飞,转载请注明原文链接:https://www.cnblogs.com/liujinhui/p/14295945.html