Junit
- 单元测试,属于白盒测试,需要写代码,关注程序的具体执行流程
- 黑盒测试,只需要关注输入输出
使用步骤
- 导入
Junit依赖环境
- 定义一个测试类
类名+Test
- 放在
xxx.xxx.xxx.test包下
- 方法名
test+方法名,不用返回值,空参,加注解@Test
结果判断
public class CalculatorTest {
@Test
public void testAdd() {
int add = new Calculator().add(13, 142);
Assert.assertEquals(15,add);
}
}
初始化方法与释放资源方法
- 用于所有测试方法在执行之前和之后要调用的方法,如申请资源
@Before初始化
@After释放
@Before
public void init() {
System.out.println("init");
}
@After
public void close() {
System.out.println("close");
}
反射
- 框架,半成品软件,在框架基础上进行软件开发,简化代码
- 反射,将类的各个组成部分封装成其他对象(成员变量对象、构造方法对象、成员变量对象),可以在程序运行过程中操作对象;解耦合,提高可扩展性
- Java代码三个阶段,源代码阶、类对象阶段、运行时阶段

获取Class对象
- 同一个字节码文件,在一次程序的运行过程中,只会被加载一次
- 将字节码文件加载到内存,用于配置文件,加载类
Class<?> aClass = Class.forName("com.mzx.java.DemoReflect.Person")
System.out.println(aClass)
System.out.println(Person.class);
Person p1 = new Person()
System.out.println(p1.getClass())
获取方法
for (Field field : aClass.getFields()) {
System.out.println(field);
}
Field name = aClass.getField("name");
System.out.println(name);
Person p = new Person();
System.out.println(name.get(new Person("zhangsan", 18)));
name.set(p, "lisi");
System.out.println(p);
for (Field declaredField : aClass.getDeclaredFields()) {
System.out.println(declaredField);
}
Field name1 = aClass.getDeclaredField("name");
System.out.println(name1);
name1.setAccessible(true);
System.out.println(name1.get(new Person("zhangsan",20)));
Person p = new Person();
name1.set(p, "zhaoliu");
System.out.println(p);
for (Constructor<?> constructor : aClass.getConstructors()) {
System.out.println(constructor);
}
Constructor<?> constructor = aClass.getConstructor(String.class, int.class);
System.out.println(constructor);
Object person = constructor.newInstance("zhangsan", 242);
System.out.println(person);
for (Constructor<?> declaredConstructor : aClass.getDeclaredConstructors()) {
System.out.println(declaredConstructor);
}
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class);
System.out.println(declaredConstructor);
declaredConstructor.setAccessible(true);
//public和继承父类的方法
for (Method method : aClass.getMethods()) {
System.out.println(method.toString())
}
Method method = aClass.getMethod("setName", String.class)
System.out.println(method)
//执行方法
Person person = new Person("zhangsan", 20)
method.invoke(person, "lisi")
System.out.println(person)
//忽略修饰符,并且只输出类中已写出的方法
for (Method declaredMethod : aClass.getDeclaredMethods()) {
System.out.println(declaredMethod)
}
Method eat = aClass.getDeclaredMethod("eat", String.class)
System.out.println(eat)
//只获取方法名称
System.out.println(eat.getName())
//暴力反射
eat.setAccessible(true)
eat.invoke(person,"milk")
System.out.println(aClass.getName());
自定义框架
- 配置文件;反射
- 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
- 在程序终结在读取配置文件
- 使用反射技术加载类文件进内存
- 创建对象
- 执行方法
例子
public class ReflectClass {
public static void main(String[] args) throws Exception {
//加载配置文件
Properties pro = new Properties()
//获取class目录下的配置文件
//获取把这个class加载到内存中的对象,通过这个对象找到配置文件
ClassLoader classLoader = ReflectClass.class.getClassLoader()
InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties")
pro.load(resourceAsStream)
String className = pro.getProperty("className")
String methodName = pro.getProperty("methodName")
String parameter = pro.getProperty("parameter")
String parameterType = pro.getProperty("parameterType")
//加载类进内存
Class<?> aClass = Class.forName(className)
Object o = aClass.getConstructor().newInstance()
Method method = aClass.getDeclaredMethod(methodName, Class.forName(parameterType))
method.setAccessible(true)
method.invoke(o, parameter)
}
}
className = com.mzx.java.DemoReflect.Person
methodName = eat
parameter = beef
parameterType = java.lang.String
注解
Annotation
- 描述程序,给计算机看
- 就是一个标签,不属于程序的一部分
文档生成
javadoc DemoMain.java
public class DemoMain {
public int add (int a, int b) {
return a + b;
}
}
内置注解
@Override 该注解标注的方法是否继承父类
@Deprecated 该注解标注的内容已过时
@SuppressWarings 压制警告
@SuppressWarnings("all")
自定义注解
- 通过反编译可以看到注解的本质是
接口,该接口默认继承Annotation
(base) appledeMacBook-Pro-3:test apple$ javac MyAnnotation.java
(base) appledeMacBook-Pro-3:test apple$ javap MyAnnotation.class
Compiled from "MyAnnotation.java"
public interface com.mzx.java.DemoAnnotation.MyAnnotation extends java.lang.annotation.Annotation {
}
属性
- 接口中的抽象方法,必须返回基本数据类型、String、枚举、注解及以上类型的数组
- 使用时,除了
default后,必须给属性(抽象方法)赋值;如果只有一个属性需要赋值,并且名称为vale,则可以省略名字,直接赋值
@MyAnnotation(age = 1, person = Person.p1, override = @Override, strs = {"abc", "asdaw", "daczx"})
public @interface MyAnnotation {
int age();
String name() default "zhangsan";
Person person();
Override override();
String[] strs();
}
元注解
- 用于描述注解的注解
@Target 描述注解能够作用的位置
@Target(value = {ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented 描述注解是否能被抽取到API文档中
@Inherited 描述注解是否能被子类继承
注解解析
- 获取注解定义的位置的对象
- 获取执行注解
- 调用注解中的抽象方法获取配置的属性值
- 注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Properties {
String classname();
String methodname();
String parameter();
String parameterType();
}
@Properties(classname = "com.mzx.java.DemoAnnotation.Woker", methodname = "eat", parameter = "beef", parameterType = "java.lang.String")
public class ReflectClass {
public static void main(String[] args) throws Exception {
//解析注解
//获取本类
Class<ReflectClass> reflectClassClass = ReflectClass.class
//获取该类上的所有注解,在内存中声称了一个该注解接口的子类实现实现对象,重写的接口方法直接返回值
Properties annotation = reflectClassClass.getAnnotation(Properties.class)
//获取注解对象中定义的抽象方法,获取返回值
String classname = annotation.classname()
String methodname = annotation.methodname()
String parameter = annotation.parameter()
String parameterType = annotation.parameterType()
//执行
Class<?> aClass = Class.forName(classname)
Object o = aClass.getConstructor().newInstance()
Method declaredMethod = aClass.getDeclaredMethod(methodname, Class.forName(parameterType))
declaredMethod.setAccessible(true)
declaredMethod.invoke(o, parameter)
}
}
注解测试
public static void main(String[] args) throws IOException {
Calculator calculator = new Calculator()
Class<? extends Calculator> aClass = calculator.getClass()
Method[] methods = aClass.getMethods()
int num = 0
//文件
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("bug.txt"))
for (Method method : methods) {
//方法上是否有异常
if (method.isAnnotationPresent(Check.class)) {
try {
method.invoke(calculator)
} catch (Exception e) {
//捕获异常,记录到文件
num ++
bufferedWriter.write(method.getName() + " - 出现异常")
bufferedWriter.newLine()
bufferedWriter.write("异常的名称 - " + e.getCause().getClass().getSimpleName())
bufferedWriter.newLine()
bufferedWriter.write("异常的原因 - " + e.getMessage())
bufferedWriter.newLine()
bufferedWriter.write("------------------------------")
bufferedWriter.newLine()
}
}
}
bufferedWriter.write("本次一共出现 " + num + " 次异常")
bufferedWriter.flush()
bufferedWriter.close()
}