文章目录
一、Junit单元测试
测试的分类
- 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望值
- 白盒测试:需要写代码,关注程序具体的执行流程
Juint单元测试是白盒测试
1、Junit的使用
使用步骤:
- 定义一个测试类(测试用例)
建议:测试类名——被测试的类名Test,如:CalculatorTest;包名——cn.itcast.test - 定义测试方法:可以独立运行
建议:方法名——test+测试的方法名,如:testAdd();返回值:void;参数列表:空参 - 给方法加@Test
- 导入Junit依赖环境
判定结果:
- 控制台显示红色:表示失败
- 绿色:成功
- 一般我们会使用断言操作来处理结果
例如:Assert.assertEquals(期望的结果,运算的结果);
2、补充
- @Before:修饰的方法,会在测试方法之前被执行
- @After:修饰的方法,会在测试方法之后被执行
不管测试有没有出错,被这两个注解修饰的方法,一定会执行了
二、反射
反射是框架设计的灵魂。框架是半成品软件,可以在框架的基础上进行软件开发,简化编码。
1、反射的概念
将类的各个组成部分封装为其他对象,这就是反射机制(将成员变量封装为Filed对象,将构造方法封装为Constructor对象,将成员方法封装为Method对象)
2、反射的好处
- 可以在程序运行过程中,操作这些对象
- 可以解耦,提高程序的可扩展性
3、获取Class类对象的三种方式
-
Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象
多用于配置文件,将类名定义在配置文件中。读取文件,加载类 -
类名.class:通过类名的属性class获取
多用于参数的传递 -
对象.getClass():getClass()方法是在Object类中,所有对象都可以用这个方法
多用于对象的获取字节码的方式
结论:
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过上面的那种方式获取的Class对象都是同一个
4、Class类对象的功能
获取功能:
1.获取成员变量们
-
Filed[] getFields()
:获取所有public修饰的成员变量 -
Filed[] getField(String name)
:获取指定的public修饰的成员变量 -
Filed[] getDeclaredFileds()
:获取所有的成员变量, 不考虑修饰符 -
Filed[] getDeclaredFiled(String name)
:获取指定的成员变量,不考虑修饰符
Field(成员变量),对成员变量可进行的操作:
1.设置值:void set(Object obj, Object value)
2.获取值:get(Object obj)
3.忽略访问权限修饰符的安全检查:方法setAccessible(true):暴力反射
2.获取构造方法们
-
Constructor<?>[] getConstructors()
-
Constructor<T>[] getConstructor(类<?>... parameterTypes)
-
Constructor<?>[] getDeclaredConstructors()
-
Constructor<T>[] getDeclaredConstructor(类<?>... parameterTypes)
Constructor(构造方法),对构造方法可进行操作:
- 创建对象:
T newInstance(Object… initargs);
如果使用了空参数的构造方法创建对象,操作可以省略:直接可以使用Class对象的newInstance方法
3.获取成员方法们
-
Method[] getMethods()
-
Method[] getMethod(String name, 类<?>... parameterTypes)
-
Method[] getDeclaredMethods()
-
Method[] getDeclaredMethod(String name, 类<?>... parameterTypes)
Method(方法对象),操作有:
- 执行方法:Object invoke(Object obj, Object… args)
- 获取方法的名称:String getName——获取方法名
4.获取类名
String getName()
5、反射的案例
需求:写一个“框架”,在不能改变该类任何代码的前提下,可以创建任意类的对象,并执行其中任意方法
实现:1.配置文件;2.反射
实现步骤:
- 将需要创建对象的全类名和需要执行的方法定义在配置文件中
- 在程序中加载读取配置文件
- 使用反射技术来加载类文件进内存
- 创建对象
- 执行方法
配置文件(pro.properties):全类名可以该为cn.itcast.damain.Person,方法名可以改为eat
className=cn.itcast.damain.Student
methodName=sleep
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
// 用反射创建任意类的对象,到时候只用改配置文件内容,不用改代码
public class ReflectTest {
public static void main(String[] args) throws Exception {
// 1.加载配置文件
// 1.1创建Properties对象
Properties pro = new Properties();
// 1.2加载配置文件,转换为一个集合
// 1.2.1获取class目录下的配置文件
ClassLoader classLoader = ReflectTest.class.getClassLoader(); //class文件的类加载器
InputStream is = classLoader.getResourceAsStream("pro.properties");
pro.load(is);
// 2.获取配置文件中定义的数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
// 3.加载该类进入内存
Class cls = Class.forName(className);
// 4.创建对象
Object obj = cls.newInstance();
// 5.获取方法对象
Method method = cls.getMethod(methodName);
// 6.执行方法
method.invoke(obj);
}
}
改配置文件,比改程序的代码更好。
如果在配置文件里面有全类名,那这个地方用的就是反射机制。
三、注解
注解的概念: JDK1.5之后的新特性,用来说明程序的
使用注解:@注解名称
作用分类:
①编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
②代码分析:通过代码里标识的注解对代码进行分析【使用反射】
③编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】
1、JDK中预定义的一些注解
- @Override:检测被该注解标注的方法是否是继承自父类(接口)的
- @Deprecated:该注解标注的内容,表示已过时
- @SuppressWarnings:压制警告
一般传递参数all @SuppressWarnings(“all”)
@SuppressWarnings("all")
// 压制了该类的所有警告
public class AnnoDemo2 {
@Override
public String toString() {
return super.toString();
}
@Deprecated
public void show1() {
// 有缺陷
}
public void show2() {
// 代替show1方法
}
}
2、自定义注解
注解定义的格式:
元注解
public @interface 注解名称{
属性列表;
}
注解的本质: 注解本质上就是一个接口,该接口默认继承Annotation接口
public interface MyAnno extends java.lang.annotation.Annotation { }
注解的属性: [注解的属性]就是注解这个接口中的[抽象方法]
要求:
1.属性的返回值类型:
基本数据类型(四类八种),String类型,枚举类型,注解类型,以上类型的数组
2.定义了属性,在使用时需要给属性赋值
1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
2. 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。
3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略
元注解: 描述注解的注解
@Target:描述【注解能够作用的位置】
其中枚举ElementType有三个取值要记住:
TYPE:可以作用于类上
METHOD:可以作用于方法上
FIELD:可以作用于成员变量上
@Retention:描述【注解被保留的阶段(三个阶段)】
@Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到 class字节码文件中,并被 JVM 读取到
@Documented:描述注解是否被抽取到 API 文档中
@Inherited:描述注解是否被子类继承
3、在程序使用(解析)注解:获取注解中定义的属性值
-
获取注解定义的位置的对象 (Class,Method,Field)
-
获取指定的注解
getAnnotation(Class) // 其实就是在内存中生成了一个该注解接口的子类实现对象
public class ProImpl implements Pro{
public String className(){
return "cn.itcast.annotation.Demo1";
}
public String methodName(){
return "show";
}
}
- 调用注解中的抽象方法获取配置的属性值