注解
-
注解演示
package cn.xiaoge.day22.annotation; /** * 注解javadoc演示 * * @author xiaoge * @version 1.0 * @since 1.5 */ public class AnnoDemo1 { /** * 计算两数只和 * @param a 整数 * @param b 整数 * @return 两数的和 */ public int add(int a, int b){ return a + b; } } // 运行: 在终端-->javadoc AnnoDemo1.java
-
注解_JDK内置注解
package cn.xiaoge.day22.annotation; /** * 注解: * 概念: 说明程序的. 给计算机看的 * 注释: 用文字描述程序的. 给程序员看的 * * 定义: 注解(Annotation), 也叫元数据. 一种代码级别的说明. 他是JDK1.5及以后版本引入的一个特性, * 与类 接口 枚举实在同一个层次. 它可以声明在包 类 字段 方法 局部变量 方法的参数等的前面, 用来 * 对这些元素进行说明, 注释. * * 概念描述: * - JDK1.5之后的新特性 * - 说明程序的 * - 使用注解: @注解名称 * * 作用分类: * 1. 编写文档: 通过代码里标识的注解生成文档 [生成文档doc文档] * 2. 代码分析: 通过代码里标识的注解对代码进行分析 [使用反射] * 3. 编译检查: 通过代码里标识的注解让编译器能够实现基本的编译检查 [Override] * * JDK中预定义的一些注解 * - @Override: 检测被该注解标注的方法是否是继承自父类(接口)的 * - @Deprecated: 该注解标注的内容, 标识已过时 * - @SuppressWarnings: 压制警告 * - 一般传递参数all @SuppressWarnings("all") * * 自定义注解: * 格式: * 元注解 * public @interface 注解名称{} * * 本质: 注解本质上就是一个接口, 该接口默认继承Annotation接口 * - public interface cn.xiaoge.day22.annotation.MyAnno extends java.lang.annotation.Annotation {} * * 属性: 接口中可以定义的成员方法 */ @SuppressWarnings("all") public class AnnoDemo2 { @Override public String toString() { return super.toString(); } @Deprecated public void show1(){ // 有缺陷 } // @SuppressWarnings("all") // 一般把这个注解写在类上 public void show2(){ // 替代show1方法 } public void demo(){ show1(); } }
-
自定义注解
package cn.xiaoge.day22.annotation; public @interface MyAnno { } // 运行: javac MyAnno.java javap MyAnno.class
-
自定义注解_属性定义
- 自定义注解
package cn.xiaoge.day22.annotation; /** * *自定义注解: * 格式: * 元注解 * public @interface 注解名称{ * 属性列表; * } * * 本质: 注解本质上就是一个接口, 该接口默认继承Annotation接口 * - public interface cn.xiaoge.day22.annotation.MyAnno extends java.lang.annotation.Annotation {} * * 属性: 接口中可以定义的成员方法 * - 要求: * 1. 属性的返回值类型有下列取值 * - 基本数据类型 * - String * - 枚举 * - 注解 * - 以上类型的数组 * * 2. 定义属性, 在使用时需要给属性赋值 * - 如果定义属性时, 使用default关键字给属性默认初始化值, 则使用注解时, 可以不进行属性的赋值. * - 如果只有一个属性需要赋值, 并且属性的名称是value, 则value可以省略, 直接定义值即可 列(@MyAnno(12)) * - 数组赋值时, 值使用{}包裹. 如果数组中只有一个值, 则{}省略 * * 元注解: 用于描述注解的注解 * @Target: 描述注解能够作用的位置 * - ElementType取值: * - TYPE: 可以作用于类上 * - METHOD: 可以作用于方法上 * - FIELD: 可以作用于成员变量上 * * @Retention: 描述注解被保留的阶段 * - @Retention(RetentionPolicy.RUNTIME): 当前被描述的注解, 会保留到class字节码文件中, 并被JVM读取到 * * @Documented: 描述注解是否被抽取到api文档中 * - 加了这个注解, 用javadoc命令生成api文档是, 你那些成员方法或成员变量加了该注解, 同时也会显示到该api文档中 * * @Inherited: 描述注解是否被子类继承 * * * 在程序使用(解析)注解: 获取注解中定义的属性值 * 1. 获取注解定义的位置的对象 (Class, Method, Field) * 2. 获取指定的注解 * - getAnnotation(Class对象) 列(一个类Test, 获取该类的Class对象, Test.class) * 3. 调用注解中的抽象方法获取配置的属性值 * */ public @interface MyAnno { int value(); Person per(); MyAnno2 anno2(); String[] strs(); // String name() default "张三"; // 用该注解时, 不给name赋值, 默认就是张三 /*String show2(); Person pro(); MyAnno2 mynoo(); String[] show3();*/ }
-
注解
package cn.xiaoge.day22.annotation; public @interface MyAnno2 { }
-
枚举
package cn.xiaoge.day22.annotation; // 枚举 public enum Person { p1, p2; }
-
自定义注解_元注解
-
MyAnno
package cn.xiaoge.day22.annotation; /** * *自定义注解: * 格式: * 元注解 * public @interface 注解名称{ * 属性列表; * } * * 本质: 注解本质上就是一个接口, 该接口默认继承Annotation接口 * - public interface cn.xiaoge.day22.annotation.MyAnno extends java.lang.annotation.Annotation {} * * 属性: 接口中可以定义的成员方法 * - 要求: * 1. 属性的返回值类型有下列取值 * - 基本数据类型 * - String * - 枚举 * - 注解 * - 以上类型的数组 * * 2. 定义属性, 在使用时需要给属性赋值 * - 如果定义属性时, 使用default关键字给属性默认初始化值, 则使用注解时, 可以不进行属性的赋值. * - 如果只有一个属性需要赋值, 并且属性的名称是value, 则value可以省略, 直接定义值即可 列(@MyAnno(12)) * - 数组赋值时, 值使用{}包裹. 如果数组中只有一个值, 则{}省略 * * 元注解: 用于描述注解的注解 * @Target: 描述注解能够作用的位置 * - ElementType取值: * - TYPE: 可以作用于类上 * - METHOD: 可以作用于方法上 * - FIELD: 可以作用于成员变量上 * * @Retention: 描述注解被保留的阶段 * - @Retention(RetentionPolicy.RUNTIME): 当前被描述的注解, 会保留到class字节码文件中, 并被JVM读取到 * * @Documented: 描述注解是否被抽取到api文档中 * - 加了这个注解, 用javadoc命令生成api文档是, 你那些成员方法或成员变量加了该注解, 同时也会显示到该api文档中 * * @Inherited: 描述注解是否被子类继承 * * * 在程序使用(解析)注解: 获取注解中定义的属性值 * 1. 获取注解定义的位置的对象 (Class, Method, Field) * 2. 获取指定的注解 * - getAnnotation(Class对象) 列(一个类Test, 获取该类的Class对象, Test.class) * 3. 调用注解中的抽象方法获取配置的属性值 * */ public @interface MyAnno { int value(); Person per(); MyAnno2 anno2(); String[] strs(); // String name() default "张三"; // 用该注解时, 不给name赋值, 默认就是张三 /*String show2(); Person pro(); MyAnno2 mynoo(); String[] show3();*/ }
-
MyAnno2
package cn.xiaoge.day22.annotation; public @interface MyAnno2 { }
-
MyAnno3
package cn.xiaoge.day22.annotation; import java.lang.annotation.*; /** * 元注解: 用于描述注解的注解 * @Target: 描述注解能够作用的位置 * - ElementType取值: * - TYPE: 可以作用于类上 * - METHOD: 可以作用于方法上 * - FIELD: 可以作用于成员变量上 * * @Retention: 描述注解被保留的阶段 * - @Retention(RetentionPolicy.RUNTIME): 当前被描述的注解, 会保留到class字节码文件中, 并被JVM读取到 * * @Documented: 描述注解是否被抽取到api文档中 * - 加了这个注解, 用javadoc命令生成api文档是, 你那些成员方法或成员变量加了该注解, 同时也会显示到该api文档中 * * @Inherited: 描述注解是否被子类继承 */ @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface MyAnno3 { }
-
Worker
package cn.xiaoge.day22.annotation; @MyAnno(value = 12, per = Person.p1, anno2 = @MyAnno2, strs = {"abc", "bbb"}) @MyAnno3 public class Worker { @MyAnno3 public String name = "aaa"; @MyAnno3 public void show(){} }
-
Teacher
package cn.xiaoge.day22.annotation; public class Teacher extends Worker { }
-
-
注解_解析注解
-
注解Pro
package cn.xiaoge.day22.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 描述需要执行的类名, 和方法名 */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Pro { String className(); String methodName(); } /* @Pro(className = "cn.xiaoge.day22.annotation.Demo1", methodName = "show") public class ReflectTest { public static void main(String[] args) throws Exception { // 1.1 获取该类的字节码文件对象 Class<ReflectTest> reflectTestClass = ReflectTest.class; // 其实就是在内存中生成了一个该注解接口的子类实现对象 Pro an = reflectTestClass.getAnnotation(Pro.class); } } Pro an = reflectTestClass.getAnnotation(Pro.class); 相当于: public class ProImpl implements Pro{ public String className(){ return "cn.xiaoge.day22.annotation.Demo1"; } public String classMethod(){ return "show"; } } */
-
ReflectTest
package cn.xiaoge.day22.annotation; /* 需求: 写一个"框架", 不能改变该类的任何代码, 可以帮我们创建任意类的独享, 并且执行其中任意方法 实现: 1. 配置文件 2. 反射 步骤: 1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中 2. 在程序中加载读取配置文件 3. 使用反射技术来加载类文件进内存 4. 创建对象 5. 执行方法 */ import java.io.InputStream; import java.lang.reflect.Method; import java.util.Properties; @Pro(className = "cn.xiaoge.day22.annotation.Demo1", methodName = "show") public class ReflectTest { /** * 框架类 */ public static void main(String[] args) throws Exception { // 可以创建任意类的对象, 可以执行任意方法 /* 前提: 不能改变该类的任何代码, 可以创建任意类的对象, 可以执行任意方法 */ // 1. 解析注解 // 1.1 获取该类的字节码文件对象 Class<ReflectTest> reflectTestClass = ReflectTest.class; // 2. 获取上边的注解对象 // 其实就是在内存中生成了一个该注解接口的子类实现对象 Pro an = reflectTestClass.getAnnotation(Pro.class); // 3. 调用注解对象中定义的抽象方法, 获取返回值 String className = an.className(); String methodName = an.methodName(); // System.out.println(className); // cn.xiaoge.day22.annotation.Demo1 // System.out.println(methodName); // show // 把该类加载进内存 Class cls = reflectTestClass.forName(className); // 创建该类对象 Object obj = cls.newInstance(); // 空参构造方法, 才可以这么调用, 有参构造, 必须先用getConstructor(类<?>... parameterTypes), 然后在newInstance // 获取该方法 Method methodObj = cls.getMethod(methodName); // 执行该方法 methodObj.invoke(obj); } } // 运行结果 demo1...show...
-
-
案例
- 类Calculator
package cn.xiaoge.day22.annotation.demo; /** * 定义计算器类 */ public class Calculator { // 加法 @Check public void add(){ 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("永无bug...."); } }
- 注解Check
package cn.xiaoge.day22.annotation.demo; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) // 当前被描述的注解, 会保留到class字节码文件中, 并被JVM读取到 @Target(ElementType.METHOD) // 可以作用于方法上 public @interface Check { }
- TestCheck
package cn.xiaoge.day22.annotation.demo; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Method; /** * 简单的测试框架 * * 当主方法执行后, 会自动自行被检测的所有方法(加了Check注解的方法), 判断方法是否有异常, 记录到文件中 * * * * 小结: * 1. 以后大多数时候,我们会使用注解,而不是自定义注解 * 2. 注解给谁用? * 1. 编译器 * 2. 给解析程序用 * 3. 注解不是程序的一部分,可以理解为注解就是一个标签 * */ public class TestCheck { public static void main(String[] args) throws IOException { // 1. 获取计算器对象 Calculator c = new Calculator(); // 2. 获取计算器字节码文件对象 Class cls = c.getClass(); // 3. 获取计算器所有的方法 Method[] methods = cls.getMethods(); int number = 0; // 出现异常的次数 BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt")); for (Method method : methods) { // 4. 判断方法是否有(Check)注解 if (method.isAnnotationPresent(Check.class)) { try { // 5. 有, 执行 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.getMessage()); bw.newLine(); bw.write("-------------------------------"); bw.newLine(); } } } bw.write("本次测试一共出现" + number + "次异常"); bw.flush(); bw.close(); } } // 运行结果 1 + 0 = 1 1 - 0 = 1 1 * 0 = 0
- bug.txt
div方法异常 异常的名称:ArithmeticException 异常的原因:null ------------------------------- 本次测试一共出现1次异常
- 类Calculator