注解
概念:说明程序的,给计算机看
注释:用文字描述程序
先了解一些怎么正常javadoc文档
1:给类或者方法添加doc注释
2:通过命令javadoc 执行 类.java文件
新建的类:
/** * 注解doc演示 * @author quan * @since jdk 1.7 * @version 1.8 */ public class Annotation { /** * 计算两个数的和 * @param a 整数 * @param b 整数 * @return 两束的和 */ public int dd(int a,int b){ return a+b; } }
快捷键:
在类的所在的文件夹里面
shift+右键就能在这个路径下打开命令行
执行命令
查看生成的api文件
JDK种预定义的一些注解
没加入SupperssWarning的时候:
会出现一些告警
自定义注解
格式
public @interface 注解名称
本质: 注解的本质就是一个接口,改接口默认继承Annotation接口
PS C:\Users\quan\Desktop\date> javac .\Myannotation.java PS C:\Users\quan\Desktop\date> javap .\MyAnnotation.class Compiled from "Myannotation.java" public interface MyAnnotation extends java.lang.annotation.Annotation { }
属性:接口种可以定义的成员的方法
要求:
属性的只能返回值类型:基本数据类型 String 枚举 注解 以及他们的数组
定义了属性,在使用时需要给定属性的值
如果定义属性的时候,利用default关键字给定属性初始值,则使用注解时可以不赋值
如果只有一个属性需要赋值,并且属性名称时value,则value可以升序,直接定义值即可
数组赋值时,值使用大括号包裹,如果数组之哟一个值,大括号可以不写
枚举类:
public enum PersonE { p1,p2,p3; }
自定义注解:
public @interface MyAnnotation { //抽象方法 public String show() default "ALL"; public int age(); public String[] str(); public PersonE p(); }
使用自定义注解:
@MyAnnotation(show = "quan",age = 12,str = {"quan","zhi"},p=PersonE.p1) public void demo(){ }
元注解
用于描述注解的注解:
Target
/* ElementType的取值 TYPE:可以作用类上 METHOD:可以作用方法上 FIELD:可以作用与成员变量上 */
@Target(value = {ElementType.TYPE,ElementType.FIELD})//表示该MyAnnoT注解只能作用与类上 public @interface MyAnnoT { }
Retention
返回值时枚举类:
/* @Retention(RetentionPolicy.RUNTIME )当前白描述的注解,会保留到class字节码文件中国,并被JVM读取到 */
@Target(value = {ElementType.TYPE,ElementType.FIELD})//表示该MyAnnoT注解只能作用与类上 @Retention(RetentionPolicy.RUNTIME ) public @interface MyAnnoT { }
Documented
@Documented//表示,未来会集合到javadoc文档种
Inherited
@Inherited//表示是否会被继承
@Target(value = {ElementType.TYPE,ElementType.FIELD})//表示该MyAnnoT注解只能作用与类上 @Retention(RetentionPolicy.RUNTIME ) @Documented//表示,未来会集合到javadoc文档种 @Inherited//表示是否会被继承 public @interface MyAnnoT { }
在程序中实际应用注解,解析注解
获取注解中定义中的属性值
定义一个注解:
/** * 描述需要执行的类名和方法名 */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Pro { String className(); String methodName(); } /* public class ProImpl implements Pro{ String className(){ return "annotaion.Demo1"; } String methodName(){ retun "show"; } }
定义一个类:
package annotaion; public class Demo1 { public void show(){ System.out.println("demo1..show..."); } }
定义一个使用注解的累
@Pro(className = "annotaion.Demo1",methodName = "show") public class ReflectTest { public static void main(String[] args) throws Exception { /* 不能改变框架的任何代码 可以创建任意类的对象,可以执行任意方法 */ //111解析注解:获取该类的字节码文件对象 Class<ReflectTest> reflectTestClass = ReflectTest.class; //222获取上边的注解 //其实上面就是在内存中生成一个该注解接口子类实现对象 Pro an = reflectTestClass.getAnnotation(Pro.class); /* public class ProImpl implements Pro{ String className(){ return "annotaion.Demo1"; } String methodName(){ retun "show"; } } */ //333调用注解对象中的抽象方法,获取放回值 String className = an.className(); String methodName = an.methodName(); //利用Class的静态方法forName,传入全类名去获取指定类的Class对象 Class cls = Class.forName(className); System.out.println(cls);//class annotaion.Demo1 //通过Class对象的newInstance去实现无参实体类 Demo1 obj1 = (Demo1) cls.newInstance();//这里使用类的强制转换 obj1.show(); System.out.println(obj1);//annotaion.Demo1@61bbe9ba Object obj = cls.newInstance();//因为这里使用Object接受,多态。 System.out.println(obj);//annotaion.Demo1@61bbe9ba //通过Class对象去获取类的方法 Method method = cls.getMethod(methodName); System.out.println(method);//public void annotaion.Demo1.show() //执行方法,指定执行的实体类 method.invoke(obj); } }
re:
class annotaion.Demo1 demo1..show... annotaion.Demo1@61bbe9ba annotaion.Demo1@610455d6 public void annotaion.Demo1.show() demo1..show...
计算器检测bug案例
需要测试下面这个计算器有没有bug
package annotationDemo; public class Calulator { @Check public void add(){ String str = null; str.toString(); System.out.println("1 + 0 = " +(1 + 0)); } @Check public void sub(){ System.out.println("1 - 0 = " + (1 - 0)); } @Check public void mul(){ System.out.println("1 * 0 = " + (1 * 0)); } @Check public void div(){ System.out.println("1 / 0 = " + (1 / 0)); } public void show(){ System.out.println("no bug"); } }
定义一个注解去实现:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Check { }
程序中利用注解:
import java.io.BufferedOutputStream; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 简单测试 * 主方法执行,会制动执行被加了注解的方法,判断方法是否有异常 * 将异常记录到文件当中 */ public class TestCheck { public static void main(String[] args) throws IOException { //实体类 Calulator c = new Calulator(); //2获取字节码文件对象 Class cls = c.getClass(); //3获取所有方法 Method[] methods = cls.getMethods(); int number = 0;//出现异常的次数 //异常记录数据 BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt")); //4判断方法中是否有Check注释 for (Method method : methods) { if(method.isAnnotationPresent(Check.class)){ try { method.invoke(c); } catch (Exception e) { //6捕获异常 number++; bw.write(method.getName() + "方法出异常了"); bw.newLine(); bw.write("异常名称: " + e.getCause().getClass().getSimpleName()); bw.newLine(); bw.write("异常原因: " + e.getCause().getMessage()); bw.newLine(); bw.write("~~~~~~~~~~~~~~~~~~~~~"); bw.newLine(); //记录到文件里面 } } } bw.write("一共 " + number + "个异常"); bw.flush(); bw.close(); } }
结果生成的bug.txt