文章目录
1.Junit单元测试
-
测试分类:
-
黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。
-
白盒测试:需要写代码的。关注程序具体的执行流程。
-
1.1 Junit介绍
- Junit是一个Java语言的单元测试框架,属于白盒测试,简单理解为可以用于取代java的main方法。Junit属于第三方工具,需要导入jar包后使用。
1.2 Junit的使用
-
编写测试类,简单理解Junit可以用于取代java的main方法
-
在测试类方法上添加注解 @Test
-
@Test 修饰的方法要求:public void 方法名() {…} ,方法名自定义建议test开头,没有参数。
-
添加Junit库到lib文件夹中,然后进行jar包关联
-
使用:点击方法左侧绿色箭头,执行当前方法(方法必须标记 @Test )。执行结果红色:代表失败;执行结果绿色:代表成功
-
Junit的注意事项:
- 没有被 @Test 注解修饰的方法,不能使用junit单独执行
- Junit只能执行public void 修饰的空参数方法
1.3 常用注解
- @Test ,用于修饰需要执行的测试方法
- @Before ,修饰的方法会在测试方法之前被自动执行
- @After ,修饰的方法会在测试方法执行之后自动被执行
- 注意:
@Before和 @After 修饰的方法,不能单独执行
2.反射:框架设计的灵魂
-
框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
-
反射:将java代码的各个组成部分封装为其他对象,可以在程序运行过程中操作这些对象,这就是java的反射机制,如下图。
-
反射的好处:
- 可以在程序运行过程中,操作这些对象。
- 可以解耦,提高程序的可扩展性。
-
反射的概念图解:
2.1 获取Class对象的方式
- 获取class文件对象的方式:
获取class对象方式 | 作用 | 应用场景 |
---|---|---|
Class.forName(“全类名”) | 通过指定的字符串路径获取 | 多用于配置文件,将类名定义在配置文件中。读取文件,加载类 |
类名.class | 通过类名的属性class获取 | 多用于参数的传递 |
对象.getClass() | 通过对象的getClass()方法获取 | 多用于对象的获取字节码的方式 |
- 注意:
class文件对象是由类加载器创建的,我们无论使用那种方式获取,都是同一个class文件对象(class文件对象只有一个)
-
编写代码演示
-
提示:同一个字节码文件 (*.class) 在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
public static void main(String[] args) throws ClassNotFoundException { //1.可以使用Object类中的方法,获取class文件对象 Person p = new Person(); Class c1 = p.getClass(); System.out.println(c1);//class com.sgw.demo02.Reflect.Person (包名+类名) //2.可以使用数据类型.class属性,获取class文件对象 /*int.class; double.class; String.class;*/ Class c2 = Person.class; System.out.println(c2);//class com.sgw.demo02.Reflect.Person //3.可以使用Class类中的静态方法,获取class文件对象 Class c3 = Class.forName("com.sgw.demo02.Reflect.Person"); System.out.println(c3); //class文件对象只有一个 引用数据类型==号比较的是对象地址值 System.out.println(c1==c2);//true System.out.println(c1==c3);//true System.out.println(c2==c3);//true }
-
2.2 获取Class对象的信息
- 知道怎么获取Class对象之后,接下来就介绍几个Class类中常用的方法了。
2.2.1 Class对象相关方法
-
String getSimpleName(); 获得简单类名,只是类名,没有包
-
String getName(); 获取完整类名,包含包名+类名
-
T newInstance();创建此 Class对象所表示的类的一个新实例。要求:类必须有public的无参数构造方法
-
代码示例:
- 获取简单类名、获取完成类名
- 创建对象
public static void main(String[] args) throws ClassNotFoundException { //获取class文件对象 会执行类中的静态代码块-->mysql-->JDBC Class clazz = Class.forName("com.sgw.demo02.Reflect.Person"); String simpleName = clazz.getSimpleName(); System.out.println(simpleName);//Person String name = clazz.getName(); System.out.println(name);//com.sgw.demo02.Reflect.Person }
2.3 Constructor类
-
Constructor是构造方法类,类中的每一个构造方法都是Constructor的对象,通过Constructor对象可以实例化对象。
-
使用Constructor时,先创建一个Person对象,便于测试
public class Person { private String name; private int age; static { System.out.println("静态代码块");} public Person() {System.out.println("Person类的空参数构造方法");} public Person(String name, int age) { this.name = name; this.age = age; System.out.println("Person类的满参数构造方法"); } private Person(String name) { this.name = name; System.out.println("Person类的私有构造方法"); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } private void method(){System.out.println("私有方法");} public String getName() {return name;} public void setName(String name) {this.name = name;} public int getAge() {return age;} public void setAge(int age) {this.age = age;}
2.3.1 Class类中与Constructor相关方法
- Constructor getConstructor(Class… parameterTypes):根据参数类型获取构造方法对象,只能获得public修饰的构造方法。如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。
- Constructor getDeclaredConstructor(Class… parameterTypes):根据参数类型获取构造方法对象,包括private修饰的构造方法。如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。
- Constructor[] getConstructors():获取所有的public修饰的构造方法
- Constructor[] getDeclaredConstructors():获取所有构造方法,包括privat修饰的
2.3.2 Constructor类中常用方法
-
T newInstance(Object… initargs):根据指定参数创建对象。
-
void setAccessible(true):暴力反射,设置为可以直接访问私有类型的构造方法。
-
编写代码演示:
- 实现步骤:
- 获取类的class文件对象
- 使用class文件对象中的方法getConstructor/Constructors获取类中的构造方法Constructor
- 使用Constructor类中的方法newInstance创建/实例化对象
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //1.获取类的class文件对象 Class clazz = Class.forName("com.sgw.demo02.Reflect.Person"); //2.使用class文件对象中的方法getConstructor/Constructors获取类中的构造方法Constructor /*Constructor<?>[] getConstructors() 获取类的所有公共构造方法。 了解: Constructor<?>[] getDeclaredConstructors()获取类声明的所有构造方法。 包括公共、保护、默认(包)访问和私有方法 */ Constructor[] cons = clazz.getConstructors(); for (Constructor con : cons) { System.out.println(con); } System.out.println("---------------------------"); Constructor[] declaredCons = clazz.getDeclaredConstructors(); for (Constructor con : declaredCons) { System.out.println(con); } System.out.println("---------------------------"); /*Constructor<T> getConstructor(Class<?>... parameterTypes) 获取指定公共构造方法。 了解:Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取指定构造方法。 包括公共、保护、默认(包)访问和私有方法 参数: Class<?>... parameterTypes:构造方法参数的class文件对象 int.class,String.class... 注意: 如果类中没有指定的构造方法,会抛出NoSuchMethodException没有方法异常 */ //public Person() 方法 Constructor con1 = clazz.getConstructor(); System.out.println(con1);//public com.sgw.demo02.Reflect.Person() //public Person(String name, int age) 方法 Constructor con2 = clazz.getConstructor(String.class, int.class); System.out.println(con2);//public com.sgw.demo02.Reflect.Person(java.lang.String,int) //private Person(String name) 方法 Constructor con3 = clazz.getDeclaredConstructor(String.class); System.out.println(con3);//private com.sgw.demo02.Reflect.Person(java.lang.String) System.out.println("---------------------------"); //3.使用Constructor类中的方法newInstance创建/实例化对象 /*java.lang.reflect.Constructor<T>:描述构造方法的类 T newInstance(Object... initargs) :实例化对象,创建对象 参数: Object... initargs:构造方法创建对象实际使用的参数 返回值: T:创建好的对象,类型使用Object */ //public Person() 方法 Object obj1 = con1.newInstance();//此方法相当于 new Person(); System.out.println(obj1);//Person{name='null', age=0} /*Person p = (Person)obj1; System.out.println(p);//Person{name='null', age=0}*/ //public Person(String name, int age) Object obj2 = con2.newInstance("狗头老高",30);//此方法相当于 new Person("狗头老高",30); System.out.println(obj2);//Person{name='狗头老高', age=30} /*私有的构造方法,我们是没有权限访问的,执行的时候有权限检查 会抛出IllegalAccessException:非法访问异常 使用Constructor的父类中的方法解决这个问题 Constructor extends java.lang.reflect.AccessibleObject void setAccessible(boolean flag) 将此对象的 accessible 标志设置为指示的布尔值。 值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。 值为 false 则指示反射的对象应该实施 Java 语言访问检查。 注意: 暴力反射不建议使用,破坏了类的封装性 */ //private Person(String name) 方法 con3.setAccessible(true);//取消con3构造方法的权限检查-->暴力反射 Object obj3 = con3.newInstance("小花"); System.out.println(obj3);//Person{name='小花', age=0} }
- 实现步骤:
-
使用反射技术获取构造方法并创建对象的简便方式(重点):
-
在Class类中有一个方法,可以直接获取空参数构造方法并创建对象返回
- T newInstance() 创建此 Class 对象所表示的类的一个新实例。
-
省略了获取Constructor的过程
-
使用前提:
- 类中的必须有空参数构造方法
- 空参数构造方法修饰符不能是private,建议使用public
-
代码演示:
public static void main(String[] args) throws Exception { //获取class文件对象 Class clazz = Class.forName("com.sgw.demo02.Reflect.Person"); //直接使用newInstance方法获取对象 Object obj = clazz.newInstance(); System.out.println(obj);//Person{name='null', age=0} //取代了 Object obj2 = clazz.getDeclaredConstructor().newInstance(); System.out.println(obj2); }
-
2.4 Method类
- Method是方法类,类中的每一个方法都是Method的对象,通过Method对象可以调用方法。
2.4.1 Class类中与Method相关方法
- Method getMethod(“方法名”, 方法的参数类型… 类型):根据方法名和参数类型获得一个方法对象,只能是获取public修饰的
- Method getDeclaredMethod(“方法名”, 方法的参数类型… 类型):根据方法名和参数类型获得一个方法对象,包括private修饰的
- Method[] getMethods():获取所有的public修饰的成员方法,包括父类中。
- Method[] getDeclaredMethods():获取当前类中所有的方法,包含私有的,不包括父类中。
2.4.2 Method类中常用方法
-
Object invoke(Object obj, Object… args):根据参数args调用对象obj的该成员方法如果obj=null,则表示该方法是静态方法
-
void setAccessible(boolean flag):暴力反射,设置为可以直接调用私有修饰的成员方法
-
编写代码演示:
- 实现步骤:
- 获取类的class文件对象
- 使用class文件对象中的方法 getMethod/getMethods 获取成员方法Method
- 使用Method类中的方法invoke执行获取到的成员方法
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { //1.获取类的class文件对象 Class clazz = Person.class; //2.使用class文件对象中的方法getMethod/getMethods获取成员方法Method /*Method[] getMethods() 获取类中所有的公共成员方法,包含父类的和接口中的 了解: Method[] getDeclaredMethods() 获取声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 */ Method[] methods = clazz.getMethods(); for (Method m : methods) { System.out.println(m); } System.out.println("-------------------------------"); Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method method : declaredMethods) { System.out.println(method); } System.out.println("-------------------------------"); /*Method getMethod(String name, Class<?>... parameterTypes) 获取指定公共成员方法。 了解: Method getDeclaredMethod(String name, Class<?>... parameterTypes) 获取指定已声明方法。 参数: String name:方法名称 Class<?>... parameterTypes:成员方法参数列表的class文件对象 注意: 类中没有指定的成员方法,会抛出NoSuchMethodException */ //public String getName() 方法 Method getNameMethod = clazz.getMethod("getName"); System.out.println(getNameMethod);//public java.lang.String com.sgw.demo02.Reflect.Person.getName() //public void setName(String name) Method setNameMethod = clazz.getMethod("setName", String.class); System.out.println(setNameMethod);//public void com.sgw.demo02.Reflect.Person.setName(java.lang.String) //private void method() 方法 Method privateMethod = clazz.getDeclaredMethod("method"); System.out.println(privateMethod);//private void com.sgw.demo02.Reflect.Person.method() System.out.println("---------------------------"); //3.使用Method类中的方法invoke执行获取到的成员方法 /*java.lang.reflect.Method:描述成员方法的类 Object invoke(Object obj, Object... args) 执行成员方法 参数: Object obj:invoke方法需要对象支持,执行的是哪个类的方法,就传递哪个类的对象 执行的是Person类的方法,传递Person对象(Objec obj = clazz.newInstance()) Object... args: 成员方法执行的时候,需要的实际参数 返回值: Object:方法的返回值 如果方法有返回值,返回对应的值 如果方法没有返回值,返回值类型是void,返回null */ Object obj = clazz.newInstance(); //public String getName() 方法 Object v1 = getNameMethod.invoke(obj);//此方法相当于执行了getName方法,获取成员变量name的值 System.out.println("v1:"+v1);//v1:null name的默认值 //public void setName(String name) 方法 Object v2 = setNameMethod.invoke(obj, "小龙女");//此方法相当于执行了setName方法,给成员变量name赋值 System.out.println("v2:"+v2);//v2:null 方法没有返回值 System.out.println(obj);//Person{name='小龙女', age=0} v1 = getNameMethod.invoke(obj);//此方法相当于执行了getName方法,获取成员变量name的值 System.out.println("v1:"+v1);//v1:小龙女 /*了解 私有方法我们没有权限执行,有权限检查,会抛出IllegalAccessException 可以使用暴力反射,取消方法的权限检查 */ privateMethod.setAccessible(true); //private void method() 方法 privateMethod.invoke(obj);//私有方法 }
- 实现步骤:
2.5 反射案例
-
需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
-
实现:
- 配置文件
- 反射
-
步骤:
- 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
- 在程序中加载读取配置文件
- 使用反射技术来加载类文件进内存
- 创建对象
- 执行方法
-
编写代码演示:
-
定义了3个类,有3个方法
-
我们可以创建Person对象,调用eat方法
package com.sgw.demo03.ReflectTest; public class Person { public void eat(){ System.out.println("饿了要吃饭!"); } }
-
我们可以创建Student对象,调用study方法
package com.sgw.demo03.ReflectTest; public class Student { public void study(){ System.out.println("程序猿就得敲代码!"); } }
-
我们可以创建Worker对象,调用work方法
package com.sgw.demo03.ReflectTest; public class Worker { public void work(){ System.out.println("工作不停的工作,国庆来了!70周年岁"); } }
-
我们可以创建任意的对象,调用任意方法
-
-
要求:只能创建一个对象,在不修改代码的前提下,执行任意的方法
-
可以使用反射技术实现
- 可以把全类名(包名+类名)和方法的名称存储到Properties集合的配置文件(键值对)
- 使用Properties集合+IO流,读取配置文件,把键值对保存到集合中
- 使用Properties集合中的方法getProperty,通过key获取value值(全类名,方法名称)
- 使用获取到的全类名,通过反射技术,创建class文件对象
- 使用class文件对象中的方法newInstance实例化对象
- 使用class文件对象中的方法getMethod,通过方法名称获取到方法的Method对象
- 使用Method对象中的方法invoke执行方法
-
代码实现:
public static void main(String[] args) throws Exception { //new Person().eat();通常的实例化对象 //2.使用Properties集合+IO流,读取配置文件,把键值对保存到集合中 Properties prop = new Properties(); //文件存放在文件夹sgw下,文件名为prop.txt prop.load(new FileReader("sgw\\prop.txt")); //3.使用Properties集合中的方法getProperty,通过key获取value值(全类名,方法名称) String className = prop.getProperty("className"); String methodName = prop.getProperty("methodName"); //4.使用获取到的全类名,通过反射技术,创建class文件对象 Class clazz = Class.forName(className); //5.使用class文件对象中的方法newInstance实例化对象 Object obj = clazz.newInstance(); //6.使用class文件对象中的方法getMethod,通过方法名称获取到方法的Method对象 Method method = clazz.getMethod(methodName); //7.使用Method对象中的方法invoke执行方法 method.invoke(obj); }
-
3.注解
3.1 注解概述
- 定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
- 作用分类:
- 编写文档:通过代码里标识的注解生成文档【例如,生成文档doc文档】
- 代码分析:通过代码里标识的注解对代码进行分析【例如,注解的反射】
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【例如,Override】
- 常见注解:
- @author:用来标识作者名
- @version:用于标识对象的版本号,适用范围:文件、类、方法。
- @Override :用来修饰方法声明,告诉编译器该方法是重写父类中的方法,如果父类不存在该方法,则编译失败。
3.2 自定义注解
3.2.1 定义格式
-
自定义注解:使用关键字@interface,格式:
元注解 public @interface 注解名称{ 属性列表; }
-
注解本质上就是一个接口,该接口默认继承Annotation接口
public interface MyAnno extends java.lang.annotation.Annotation {}
-
3.2.2 注解的属性
-
属性的作用
可以让用户在使用注解时传递参数,让注解的功能更加强大。 -
属性的格式:(自定义带属性的注解:属性可以看成是包含默认值的抽象方法)
public @interface 注解名{ 修饰符 数据类型 属性名(); 修饰符 数据类型 属性名() default 默认值; }
-
属性定义示例
public @interface MyAnnotation02 { //定义一个int类型的属性,不包含默认值 public abstract int a(); //定义一个double类型的属性,默认值使用8.8 public abstract double d() default 8.8; //定义一个String数组类型的属性 public abstract String[] arr(); //定义一个Class类型的属性,了解 public abstract Class clazz(); //定义一个注解类型的属性,了解 MyAnnotation01 my01(); //定义一个枚举类型的属性,了解 public abstract Color c(); }
-
属性适用的数据类型
- 修饰符:固定使用public abstract,不写默认也是,建议写出,增强代码阅读性
- 八种基本数据类型(int,float,boolean,byte,double,char,long,short)
- String类型,Class类型,枚举类型,注解类型
- 以上所有类型的一维数组
3.3 使用自定义注解
- 在程序中使用(解析)注解的步骤(获取注解中定义的属性值):
- 获取注解定义的位置的对象 (Class,Method,Field)
- 获取指定的注解 getAnnotation(Class)
- 调用注解中的抽象方法获取配置的属性值
3.3.1 定义注解
-
定义一个注解:Book
- 包含属性:String value() 书名
- 包含属性:double price() 价格,默认值为 100
- 包含属性:String[] authors() 多位作者
public @interface Book { //书名 public abstract String name(); //价格,默认值为 100 public abstract double price() default 100; //多位作者 public abstract String[] authors(); }
3.3.2 使用注解
-
定义类在成员方法上使用Book注解
public @interface Book { //书名 public abstract String name(); //价格,默认值为 100 public abstract double price() default 100; //多位作者 public abstract String[] authors(); }
-
使用注意事项
- 如果属性有默认值,则使用注解的时候,这个属性可以不用赋值。
- 如果属性没有默认值,那么在使用注解时一定要给属性赋值。
3.3.3 特殊属性value
-
当注解中只有一个属性且名称是value,在使用注解时给value属性赋值可以直接给属性值,无论value是单值元素还是数组类型。
// 定义注解Book public @interface Book { // 书名 String value(); } // 使用注解Book public class BookShelf { @Book("西游记") public void showBook(){ } } 或 public class BookShelf { @Book(value="西游记") public void showBook(){ } }
-
如果注解中除了value属性还有其他属性,且至少有一个属性没有默认值,则在使用注解给属性赋值时,
value属性名不能省略。// 定义注解Book public @interface Book { // 书名 String value(); // 价格 double price() default 100; // 多位作者 String[] authors(); } // 使用Book注解:正确方式 @Book(value="红楼梦",authors = "曹雪芹") public class BookShelf { // 使用Book注解:正确方式 @Book(value="西游记",authors = {"吴承恩","白求恩"}) public void showBook(){ } } // 使用Book注解:错误方式 public class BookShelf { @Book("西游记",authors = {"吴承恩","白求恩"}) public void showBook(){ } } // 此时value属性名不能省略了。
3.4 注解之元注解
- 默认情况下,注解可以用在任何地方,比如类,成员方法,构造方法,成员变量等地方。如果要限制注解的使用位置怎么办?那就要学习一个新的知识点:元注解。
- @Target
- @Retention
3.4.1 元注解之@Target
-
作用:指明此注解用在哪个位置,如果不写默认是任何地方都可以使用。
- 可选的参数值在枚举类ElemenetType 中包括:
TYPE: 用在类,接口上 FIELD:用在成员变量上 METHOD: 用在方法上 PARAMETER:用在参数上 CONSTRUCTOR:用在构造方法上 LOCAL_VARIABLE:用在局部变量上
3.4.2 元注解之@Retention
-
作用:定义该注解的生命周期(有效范围)。
- 可选的参数值在枚举类型RetentionPolicy中包括
SOURCE:注解只存在于Java源代码中,编译生成的字节码文件中就不存在了。 CLASS:注解存在于Java源代码、编译以后的字节码文件中,运行的时候内存中没有,默认值。 RUNTIME:注解存在于Java源代码中,编译以后的字节码文件中,运行时内存中,程序可以通过反射获取该注解。
3.4.3 元注解使用示例
-
@Target({ElementType.METHOD,ElementType.TYPE}) @interface Stu{ String name(); } // 类 @Stu(name="jack") public class AnnotationDemo02 { // 成员变量 @Stu(name = "lily") // 编译失败 private String gender; // 成员方法 @Stu(name="rose") public void test(){} // 构造方法 @Stu(name="lucy") // 编译失败 public AnnotationDemo02(){} }
3.5 注解解析
3.5.1 什么是注解解析
- 通过Java技术获取注解数据的过程则称为注解解析。
3.5.2 与注解解析相关的接口
-
Anontation:所有注解类型的公共接口,类似所有类的父类是Object。
-
AnnotatedElement:定义了与注解解析相关的方法,常用方法以下四个:
boolean isAnnotationPresent(Class annotationClass); 判断当前对象是否有指定的注解,有则返回true,否则返回false。 T getAnnotation(Class<T> annotationClass); 获得当前对象上指定的注解对象。 Annotation[] getAnnotations(); 获得当前对象及其从父类上继承的所有的注解对象。 Annotation[] getDeclaredAnnotations();获得当前对象上所有的注解对象,不包括父类的。
3.5.3 获取注解数据的原理
-
注解作用在那个成员上,就通过反射获得该成员的对象来得到它的注解。
-
如注解作用在方法上,就通过方法(Method)对象得到它的注解
// 得到方法对象 Method method = clazz.getDeclaredMethod("方法名"); // 根据注解名得到方法上的注解对象 Book book = method.getAnnotation(Book.class);
-
如注解作用在类上,就通过Class对象得到它的注解
// 获得Class对象 Class c = 类名.class; // 根据注解的Class获得使用在类上的注解对象 Book book = c.getAnnotation(Book.class);
-
3.5.4 使用反射获取注解的数据
3.5.4.1 需求说明
- 定义注解Book,要求如下:
- 包含属性:String value() 书名
- 包含属性:double price() 价格,默认值为 100
- 包含属性:String[] authors() 多位作者
- 限制注解使用的位置:类和成员方法上
- 指定注解的有效范围:RUNTIME
- 定义BookStore类,在类和成员方法上使用Book注解
- 定义TestAnnotation测试类获取Book注解上的数据
3.5.4.2 代码实现
-
注解Book
@Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Book { // 书名 String value(); // 价格 double price() default 100; // 作者 String[] authors(); }
-
BookStore类
@Book(value = "红楼梦",authors = "曹雪芹",price = 998) public class BookStore { @Book(value = "西游记",authors = "吴承恩") public void buyBook(){ } }
-
TestAnnotation类
public class TestAnnotation { public static void main(String[] args) throws Exception{ System.out.println("---------获取类上注解的数据----------"); test01(); System.out.println("---------获取成员方法上注解的数据----------"); test02(); } /** * 获取BookStore类上使用的Book注解数据 */ public static void test01(){ // 获得BookStore类对应的Class对象 Class c = BookStore.class; // 判断BookStore类是否使用了Book注解 if(c.isAnnotationPresent(Book.class)) { // 根据注解Class对象获取注解对象 Book book = (Book) c.getAnnotation(Book.class); // 输出book注解属性值 System.out.println("书名:" + book.value()); System.out.println("价格:" + book.price()); System.out.println("作者:" + Arrays.toString(book.authors())); } } /** * 获取BookStore类成员方法buyBook使用的Book注解数据 */ public static void test02() throws Exception{ // 获得BookStore类对应的Class对象 Class c = BookStore.class; // 获得成员方法buyBook对应的Method对象 Method m = c.getMethod("buyBook"); // 判断成员方法buyBook上是否使用了Book注解 if(m.isAnnotationPresent(Book.class)) { // 根据注解Class对象获取注解对象 Book book = (Book) m.getAnnotation(Book.class); // 输出book注解属性值 System.out.println("书名:" + book.value()); System.out.println("价格:" + book.price()); System.out.println("作者:" + Arrays.toString(book.authors())); } } }
-
输出结果:
3.6 注解案例
- 案例说明
3.6.1 案例说明
- 模拟Junit测试的@Test
3.6.2 案例分析
- 模拟Junit测试的注释@Test,首先需要编写自定义注解@MyTest,并添加元注解,保证自定义注解只能修饰方法,且在运行时可以获得。
- 然后编写目标类(测试类),然后给目标方法(测试方法)使用 @MyTest注解,编写三个方法,其中两个加上@MyTest注解。
- 最后编写调用类,使用main方法调用目标类,模拟Junit的运行,只要有@MyTest注释的方法都会运行。
3.6.3 案例代码
-
注解MyTest
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyTest {}
-
目标类MyTestDemo
public class MyTestDemo { @MyTest public void test01(){ System.out.println("test01"); } public void test02(){ System.out.println("test02"); } @MyTest public void test03(){ System.out.println("test03"); } }
-
调用类TestMyTest
public class TestMyTest { public static void main(String[] args) throws Exception{ // 获得MyTestDemo类Class对象 Class c = MyTestDemo.class; // 获得所有的成员方法对象 Method[] methods = c.getMethods(); // 创建MyTestDemo类对象 Object obj = c.newInstance(); // 遍历数组 for (Method m:methods) { // 判断方法m上是否使用注解MyTest if(m.isAnnotationPresent(MyTest.class)){ // 执行方法m m.invoke(obj); } } } } **输出结果:** test01 test03