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());
复制代码
获取方法
- 获取成员变量们,设置值/获取值
//获取所有public修饰的成员变量
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);
复制代码
- 获取构造方法们
//获取public修饰的构造器
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
复制代码
- java文件
/**
* @author 99永远差一分
* @version 1.0
* @since 2021.8.12
*/
public class DemoMain {
/**
* 加
* @param a 整数一
* @param b 整数二
* @return 两数之和
*/
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
描述注解被保留的阶段
//被描述的注解,会保留到class字节码的文件中,并被JVM读到
@Retention(RetentionPolicy.RUNTIME)
//CLASS 会保存到字节码文件中,但不会被读到
//SOURCE 不会保存到字节码文件中
复制代码
@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();
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END