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 {
@Test
public 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()` 获取包含所有变量构造的构造器
```java
import 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
```java
className=Reflection.Person
methodName=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
描述注解应用类的子类是否应用注解