1 Junit单元测试

1.1 测试分类

  • 黑盒测试 不需要写代码,给输入值,看程序是否能够输出期望的值
  • 白盒测试 需要写代码,关注程序具体执行流程,Junit是一种白盒测试

    1.2 Junit使用

  1. 定义一个测试类(测试用例)
    1. 测试类名:被测试的类名Test
    2. 包名:xxx.xxx.xxx.test
  2. 定义测试方法(可以独立运行)
    1. 方法名:test测试的方法名
    2. 返回值:void
    3. 参数列表:空参
  3. 给方法加@Test
  4. 导入junit依赖
  5. 注意事项
    1. 方法前加 @Before 则为初始化方法,用于资源申请,所有测试方法在执行之前都会先执行该方法
    2. 方法前加 @After 则为释放资源的方法,在所有测试方法执行完后都会自动执行

创建一个计算器类

  1. public class Calculator {
  2. /**
  3. * @param a
  4. * @param b
  5. * @return
  6. */
  7. public int add(int a, int b) {
  8. return a + b;
  9. }
  10. /**
  11. * @param a
  12. * @param b
  13. * @return
  14. */
  15. public int sup(int a, int b) {
  16. return a - b;
  17. }
  18. }

测试类

  1. import Junit.junit.Calculator;
  2. import org.junit.Assert;
  3. import org.junit.Test;
  4. public class CalculatorTest {
  5. @Test
  6. public void testAdd() {
  7. System.out.println("爷开始测试...");
  8. Calculator c = new Calculator();
  9. int result = c.add(1, 3);
  10. Assert.assertEquals(4, result);
  11. System.out.println("测试通过");
  12. }
  13. }

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. * 1 使用Class对象获取成员变量
  2. * Field[] getFields() 获取所有public修饰的成员变量
  3. * Field getField(String name) 获取指定名称的public修饰的成员变量
  4. * Field[] getDeclaredFields() 获取所有的成员变量
  5. * Field getDeclaredField(String name) 获取指定名称的成员变量,无论其修饰符是何
  6. */
  7. Field[] fields = personClass.getDeclaredFields();
  8. for (Field field : fields) {
  9. System.out.println(field);
  10. }
  11. Field a = personClass.getField("a");
  12. System.out.println(a);
  13. // 获取成员变量的值
  14. System.out.println("===================================");
  15. Person p = new Person();
  16. Object value = a.get(p);
  17. System.out.println(value);
  18. // 设置成员变量的值
  19. a.set(p, "Hello");
  20. System.out.println(p);
  21. // 操作私有变量
  22. System.out.println("===================================");
  23. Field name = personClass.getDeclaredField("name");
  24. // 忽略访问权限安全检查
  25. name.setAccessible(true); // 暴力反射
  26. Object nameVal = name.get(p);
  27. System.out.println(nameVal);
  28. }

}

  1. **获取构造方法**
  2. - `Constructor<?>[] getConstructors()` 获取包含所有public变量构造的构造方法
  3. - `Constructor getConstructor(Class<?>... parameterTypes)` 获取一个构造器
  4. - `Constructor getDeclaredConstructor(Class<?>... parameterTypes)` 获取一个构造器,可以初始化私有变量
  5. - `Constructor<?>[] getDeclaredConstructors()` 获取包含所有变量构造的构造器
  6. ```java
  7. import java.lang.reflect.Constructor;
  8. import java.lang.reflect.InvocationTargetException;
  9. public class Demo02 {
  10. public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
  11. Class<Person> personClass = Person.class;
  12. /**
  13. * 2 获取构造方法
  14. * Constructor<?>[] getConstructors() 获取所有构造方法
  15. * Constructor<T> getConstructor(Class<?>... parameterTypes) 获取一个构造器
  16. * Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取一个构造器
  17. * Constructor<?>[] getDeclaredConstructors() 获取所有构造方法
  18. */
  19. Constructor<Person> constructor = personClass.getConstructor(String.class, int.class, String.class);
  20. System.out.println(constructor);
  21. Person p1 = constructor.newInstance("张三", 18);
  22. System.out.println(p1);
  23. System.out.println("==================================");
  24. Constructor<Person> constructor1 = personClass.getConstructor();
  25. Person p2 = personClass.newInstance();
  26. System.out.println(p2);
  27. }
  28. }

获取成员方法

  • 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 personClass = Person.class; /**

  1. * Method[] getMethods() 获取所有的方法,还包括自Object继承的方法
  2. * Method getMethod(String name Class<?>...parameterTypes) 获取指定方法,传入参数包括方法的参数class对象
  3. * Method[] getDeclaredMethods() 获取自定义方法
  4. * Method getDeclaredMethod(String name Class<?>...parameterTypes) 获取自定义方法,传入参数包括方法的参数class对象
  5. */
  6. Method[] methods = personClass.getMethods();
  7. for (Method method : methods) {
  8. System.out.println(method + "--->" + method.getName());
  9. }
  10. System.out.println("==================================");
  11. Method[] declaredMethods = personClass.getDeclaredMethods();
  12. for (Method declaredMethod : declaredMethods) {
  13. System.out.println(declaredMethod);
  14. }
  15. System.out.println("==================================");
  16. Method eat_method = personClass.getMethod("eat");
  17. Person person = new Person();
  18. // 执行无参方法
  19. eat_method.invoke(person);
  20. System.out.println("==================================");
  21. Method drink_method = personClass.getMethod("drink", String.class);
  22. // 执行有参方法
  23. drink_method.invoke(person, "coffee");
  24. }

}

  1. **获取类名** `String getName()`
  2. <a name="lIvTn"></a>
  3. ### Field
  4. - `void get(Object obj)` 获取对象的属性值
  5. - `void set(Object obj, Object value)` 设置对象的属性值
  6. - `void setAccessible(boolean flag)` 暴力反射,设置Field对象可被访问
  7. <a name="DnH2L"></a>
  8. ### Constructor
  9. - `T newInstance(Object...initargs)` 创建一个新对象
  10. - 如果使用空参获得构造器,可以使用Class `newInstance` 方法
  11. - `void setAccessible(boolean flag)` 暴力反射,设置构造器可访问私有变量
  12. <a name="jBLCj"></a>
  13. ### Method
  14. - `Object invoke(Object obj, Object...args)` 执行方法
  15. - `String getName()` 获取方法名称
  16. - `void setAccessible(boolean flag)` 设置访问权限
  17. <a name="dc6sw"></a>
  18. ## 2.3 案例
  19. 需求:写一个“框架”,在不改变任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法<br />**实现需要** 配置文件、反射<br />**实现步骤**
  20. - 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
  21. - 在程序中加载读取配置文件
  22. - 使用反射技术来加载类文件进内存
  23. - 创建对象
  24. - 执行方法
  25. 创建一个文件config.properties
  26. ```java
  27. className=Reflection.Person
  28. methodName=eat

主程序

  1. package Reflection;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.lang.reflect.InvocationTargetException;
  5. import java.lang.reflect.Method;
  6. import java.util.Properties;
  7. public class DemoFinal {
  8. public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
  9. // 加载配置文件
  10. Properties pro = new Properties();
  11. // 获取class目录下的配置文件
  12. ClassLoader classLoader = DemoFinal.class.getClassLoader();
  13. InputStream is = classLoader.getResourceAsStream("config.properties");
  14. pro.load(is);
  15. // 获取配置文件中定义的数据
  16. String className = pro.getProperty("className");
  17. String methodName = pro.getProperty("methodName");
  18. // 加载该类进内存
  19. Class cls = Class.forName(className);
  20. // 创建对象
  21. Object obj = cls.newInstance();
  22. // 获取方法对象
  23. Method method = cls.getMethod(methodName);
  24. // 使用方法
  25. method.invoke(obj);
  26. }
  27. }

2.4 补充

获取Class对象的三种方式

  • Class.forName("全类名") 多用于配置文件,将类名定义在配置文件中,读取文件,加载类
  • 类名.class
  • 对象名.getClass()

    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 描述注解应用类的子类是否应用注解

注解的定义

3.4 注解的使用