1 Junit单元测试
1.1 测试分类
- 定义一个测试类(测试用例)
- 测试类名:被测试的类名Test
- 包名:xxx.xxx.xxx.test
- 定义测试方法(可以独立运行)
- 方法名:test测试的方法名
- 返回值:void
- 参数列表:空参
- 给方法加@Test
- 导入junit依赖
- 注意事项
- 方法前加
@Before则为初始化方法,用于资源申请,所有测试方法在执行之前都会先执行该方法 - 方法前加
@After则为释放资源的方法,在所有测试方法执行完后都会自动执行
- 方法前加
创建一个计算器类
public class Calculator {/*** @param a* @param b* @return*/public int add(int a, int b) {return a + b;}/*** @param a* @param b* @return*/public int sup(int a, int b) {return a - b;}}
测试类
import Junit.junit.Calculator;import org.junit.Assert;import org.junit.Test;public class CalculatorTest {@Testpublic void testAdd() {System.out.println("爷开始测试...");Calculator c = new Calculator();int result = c.add(1, 3);Assert.assertEquals(4, result);System.out.println("测试通过");}}
2 反射
2.1 反射的机制
将类的各个组成部分封装成为其他对象,这就是反射机制
反射的优点
- 可以在程序运行过程中,操作这些对象
-
2.2 Class对象
Class对象功能
获取成员变量
_Field[] getFields()_获取所有public修饰的成员变量_Field getField(String name)_获取指定名称的public修饰的成员变量_Field[] getDeclaredFields()_获取所有的成员变量_Field getDeclaredField(String name)_获取指定名称的成员变量,无论其修饰符是何 ```java import java.lang.reflect.Field;
public class Demo01 { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { // 0 获取Person的Class对象 Class personClass = Person.class; /**
* 1 使用Class对象获取成员变量* Field[] getFields() 获取所有public修饰的成员变量* Field getField(String name) 获取指定名称的public修饰的成员变量* Field[] getDeclaredFields() 获取所有的成员变量* Field getDeclaredField(String name) 获取指定名称的成员变量,无论其修饰符是何*/Field[] fields = personClass.getDeclaredFields();for (Field field : fields) {System.out.println(field);}Field a = personClass.getField("a");System.out.println(a);// 获取成员变量的值System.out.println("===================================");Person p = new Person();Object value = a.get(p);System.out.println(value);// 设置成员变量的值a.set(p, "Hello");System.out.println(p);// 操作私有变量System.out.println("===================================");Field name = personClass.getDeclaredField("name");// 忽略访问权限安全检查name.setAccessible(true); // 暴力反射Object nameVal = name.get(p);System.out.println(nameVal);}
}
**获取构造方法**- `Constructor<?>[] getConstructors()` 获取包含所有public变量构造的构造方法- `Constructor getConstructor(Class<?>... parameterTypes)` 获取一个构造器- `Constructor getDeclaredConstructor(Class<?>... parameterTypes)` 获取一个构造器,可以初始化私有变量- `Constructor<?>[] getDeclaredConstructors()` 获取包含所有变量构造的构造器```javaimport java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;public class Demo02 {public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Class<Person> personClass = Person.class;/*** 2 获取构造方法* Constructor<?>[] getConstructors() 获取所有构造方法* Constructor<T> getConstructor(Class<?>... parameterTypes) 获取一个构造器* Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取一个构造器* Constructor<?>[] getDeclaredConstructors() 获取所有构造方法*/Constructor<Person> constructor = personClass.getConstructor(String.class, int.class, String.class);System.out.println(constructor);Person p1 = constructor.newInstance("张三", 18);System.out.println(p1);System.out.println("==================================");Constructor<Person> constructor1 = personClass.getConstructor();Person p2 = personClass.newInstance();System.out.println(p2);}}
获取成员方法
- Method[] getMethods() 获取所有的方法,还包括自Object继承的方法
Method getMethod(String name Class<?>...parameterTypes)获取指定方法,传入参数包括方法的参数class对象Method[] getDeclaredMethods()获取自定义方法Method getDeclaredMethod(String name Class<?>...parameterTypes)获取自定义方法,传入参数包括方法的参数class对象 ```java import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class Demo03 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class
* Method[] getMethods() 获取所有的方法,还包括自Object继承的方法* Method getMethod(String name Class<?>...parameterTypes) 获取指定方法,传入参数包括方法的参数class对象* Method[] getDeclaredMethods() 获取自定义方法* Method getDeclaredMethod(String name Class<?>...parameterTypes) 获取自定义方法,传入参数包括方法的参数class对象*/Method[] methods = personClass.getMethods();for (Method method : methods) {System.out.println(method + "--->" + method.getName());}System.out.println("==================================");Method[] declaredMethods = personClass.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod);}System.out.println("==================================");Method eat_method = personClass.getMethod("eat");Person person = new Person();// 执行无参方法eat_method.invoke(person);System.out.println("==================================");Method drink_method = personClass.getMethod("drink", String.class);// 执行有参方法drink_method.invoke(person, "coffee");}
}
**获取类名** `String getName()`<a name="lIvTn"></a>### Field- `void get(Object obj)` 获取对象的属性值- `void set(Object obj, Object value)` 设置对象的属性值- `void setAccessible(boolean flag)` 暴力反射,设置Field对象可被访问<a name="DnH2L"></a>### Constructor- `T newInstance(Object...initargs)` 创建一个新对象- 如果使用空参获得构造器,可以使用Class的 `newInstance` 方法- `void setAccessible(boolean flag)` 暴力反射,设置构造器可访问私有变量<a name="jBLCj"></a>### Method- `Object invoke(Object obj, Object...args)` 执行方法- `String getName()` 获取方法名称- `void setAccessible(boolean flag)` 设置访问权限<a name="dc6sw"></a>## 2.3 案例需求:写一个“框架”,在不改变任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法<br />**实现需要** 配置文件、反射<br />**实现步骤**- 将需要创建的对象的全类名和需要执行的方法定义在配置文件中- 在程序中加载读取配置文件- 使用反射技术来加载类文件进内存- 创建对象- 执行方法创建一个文件config.properties```javaclassName=Reflection.PersonmethodName=eat
主程序
package Reflection;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Properties;public class DemoFinal {public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {// 加载配置文件Properties pro = new Properties();// 获取class目录下的配置文件ClassLoader classLoader = DemoFinal.class.getClassLoader();InputStream is = classLoader.getResourceAsStream("config.properties");pro.load(is);// 获取配置文件中定义的数据String className = pro.getProperty("className");String methodName = pro.getProperty("methodName");// 加载该类进内存Class cls = Class.forName(className);// 创建对象Object obj = cls.newInstance();// 获取方法对象Method method = cls.getMethod(methodName);// 使用方法method.invoke(obj);}}
2.4 补充
获取Class对象的三种方式
Class.forName("全类名")多用于配置文件,将类名定义在配置文件中,读取文件,加载类类名.class-
3 注解
3.1 基本概念
注解作用
编写文档:通过代码里标识的注解生成文档
javadoc AnnoDemo.java- 代码分析:通过代码里标识的注解对代码进行分析
编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查
3.2 JDK预定义注解
@Override方法重载检查@Deprecated该注解标注的内容表示已过时@SuppressWarnings(String type)压制警告,一般传递参数”all”表示压制所有警告3.3 自定义注解
注解本质上就是一个接口,该接口默认继承
java.lang.annotaion.Annotation接口
属性 注解接口中可以定义的抽象方法属性的返回值类型:基本数据类型、String、枚举、注解以及四种类型的数组
- 在别处使用注解时,需要给属性赋值(可以在定义时使用default赋初值)
- 如果只有一个属性,并且属性的名称是value,那么赋值时属性名称可以省略
元注解 用于描述注解的注解
@Target描述注解能够作用的位置- ElementType.TYPE 可以作用于类上
- ElementType.METHOD 可以作用于方法上
- ElementType.FIELD 可以作用于成员变量上
@Retention描述注解被保留的阶段- RetentionPolicy.SOURCE
- RetentionPolicy.CLASS 当前被描述的注解,会被保留到class字节码文件中,但不会被JVM读取到
- RetentionPolicy.RUNTIME 当前被描述的注解,会被保留到class字节码文件中,并被JVM读取到
@Documented描述注解是否被抽取到注解应用文件的 api文档中@Inherited描述注解应用类的子类是否应用注解
