单元测试
概述
针对最小的功能单元(方法),编写测试代码对其进行正确性测试
- 需要测试
- 目前只能在main方法编写测试代码,去调用其他方法进行测试
- 使用起来很不灵活,如果前面的方法测试有错,后面的方法就无法执行
- 无法得到测试的报告,需要程序员自己去观察测试是否成功
Jnuit单元测试工具
- 是一个开发源代码的Java测试框架
- 常用的版本又Junit4和Junit5两个版本
优点
- 可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立
- 不需要程序员去分析测试的结果,会自动生成测试报告
- 测试成功显示成绿色,失败显示成红色
Junit框架快速入门
步骤
- 将Junit框架的jar包导入到项目种
- 创建测试类,创建测试方法(注意:测试方法必须是公共的,无参数,无返回值的非静态方法)
- 在要测试方法上使用@Test注解修饰(标注该方法是一个测试方法)
- 在测试方法中,编写代码调用你写的功能
- 选中测试方法,右键选择"Junit运行"
Junit测试-断言测试
单元测试断言
- 所谓断言,意思是程序员可以预测程序的运行结果,检查程序的运行结果是否与预期一致
- 做法:使用Assert类的assertEquals(期望值,实际值)进行断言测试
优点
- 断言结果一致,显示成绿色,断言结果不一致,显示成红色
- 不需要程序员去分析测试的结果,会自动生成测试报告出来
Junit测试-常见注解
@Test
测试方法
@Before
用来修饰实例方法,该方法会在每一个测试方法执行之前执行一次
@After
用来修饰实例方法,该方法会在每一个测试方法执行之后执行一次
@BeforeClass
用来静态修饰方法,该方法会在所有测试方法之前只执行一次
@AfterClass
用来静态修饰方法,该方法会在所有测试方法之后只执行一次
@BeforeEach
用来修饰实例方法,该方法会在每个测试方法执行之前执行一次
@AfterEach
用来修饰实例方法,该方法会在每个测试方法执行之后执行一次
@BeforeAll
用来静态修饰方法,该方法会在所有测试方法之前只执行一次
@AfterAll
用来静态修饰方法,该方法会在所有测试方法之后只执行一次
- 开始执行的方法:初始化资源
- 执行完之后的方法:释放资源
反射
概述
- java反射机制是指:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意方法和属性,这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制
简单说,反射就是一种机制,可以运行时,动态创建对象,动态调用方法
优缺点
优点
- 提高程序的灵活性和扩展性
- 降低耦合性,提高自适应能力
- 它允许程序创建和控制任何类的对象,无需提前硬编码目标类
缺点
- 性能问题:基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码,因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用
- 维护问题:使用反射会模糊程序内部逻辑,程序员希望在源代码中看到程序的逻辑,反射却绕过源代码技术,因而带来维护问题,反射代码比相应直接代码更复杂
获取字节码对象
反射的使用步骤
- 加载某个类,得到Class对象
- 获取类中成员(成员变量Field对象,成员方法Method对象,构造方法Constructor对象)
- 调用这些对象的方法,使用它们
获取Class类的对象
- 通过forName(String className)
这里需要的className是全类名 - 通过类名.class
- 通过对象.getClass()
获取类的构造器并使用
步骤
第一步:获取Class对象
第二步:通过Class对象获取Constructor构造器对象
Constructor[] getConstructors()
返回所有构造器对象的数组(只能拿public的)
Constructor[] getDeclaredConstructors()
返回所有构造器对象的数组,存在就能拿到
Constructor getConstructor(Class<?>...parameterTypes)
返回单个构造器对象(只能拿public的)
Constructor getDeclaredConstructor(Class<?>...parameterTypes)
返回单个构造器对象,存在就能拿到
第三步:使用Constructor构造器对象实例化一个实体对象
T newInstance(Object...initargs)
- 根据指定的构造器创建对象
public void setAccessiblie(boolean flag)
- 设置为true,表示取消访问检查,也叫暴力访问
- 如果构造器是private修饰的,那么在实例化之前需要调用setAccessiblie方法开启访问权限
获取类的成员变量并使用
步骤
第一步:获取Class对象
第二步:通过Class对象获取Field成员变量对象
Field[] getFields()
返回所有成员变量对象的数组(只能拿public的)
Field[] getDeclaredFields()
返回所有成员变量对象的数组,存在就能拿到
Field getField(String name)
返回单个成员变量对象(只能拿public的)
Field getDeclaredField(String name)
返回单个成员变量对象,存在就能拿到
第三步:使用Field对象给成员变量赋值或者获取值
void set(Object obj,Object value)
赋值
Object get(Object obj)
获取值,如果成员变量是private修饰的,那么在赋值/获取值之前需要调用setAccessible方法开启访问权限
获取类的成员方法并使用
步骤
第一步:获取Class对象
第二步:获得Method对象
Method[].getMethods()
返回所有成员方法对象的数组(只能拿public的)
Method[] getDeclaredMethods()
返回所有成员方法对象的数组,存在就能拿到
Method getMethod (String name,Class<?>...parameterTypes)
返回单个成员方法对象(只能拿public的)
Method getDeclaredMethod(String name,Class<?>...parameterTypes)
返回单个成员方法对象,存在就能拿到
第三步:执行方法
Object invoke(Object obj,Object...args)
运行方法
- 参数一:用obj对象调用该方法
- 参数二:调用方法的传递参数(如果没有就不写)
- 返回值:方法的返回值(没有就不写)
作用和应用场景
用来编写框架或者工具类
注解
概述,内置注解,注解的作用
概述
-
又称Java标注,是jdk1.5引入的新特性,与类,接口,枚举在同一层次
-
Java语言中的类,构造器,方法,成员变量,参数等都可以被注解进行标注
常用内置注解
@Override
检验方法重写的正确性
@FunctionalInterface
检验接口是否是函数式接口
@Deprecated
用来标记一个方法是已过时的方法
@SuppressWarnings
"警告类型":用来压制编译器的警告,警告类型了解两个
- deprecation:抑制过期方法警告
- all:抑制所有警告
作用
- 对Java中类,方法,成员变量做标记,然后进行特殊处理,至于到底做何种处理由业务需求来决定
- 例如:Junit框架中,标记了注解@Test的方法就可以被当初测试方法执行,而没有标记的就不能当成测试方法执行
自定义注解
格式
public @interface 注解名称{
public 属性类型 属性名() default 默认值;
... ...
}
- 属性可有可无,根据实际需求来定义
- 属性类型,Java支持的数据类型基本上都可以使用
- 默认值可以定义也可以不定义,如果不指定默认值,那么使用该注解时就必须给这个属性赋值
使用注解
- 在类,构造器,方法,成员变量,参数等位置使用注解
- @注解名称(属性名=属性值,属性名=属性值,...)
特殊属性
- value属性:如果有且仅有一个必须要赋值且名称叫value的属性,在给value属性赋值时可以省略value名称不写
- 如果有多个属性需要赋值,那么value名称是不能省略的
元注解
概念
定义在注解上,用来修饰注解的注解
常见元注解
@Target(...)
- 指定注解能写在哪些地方
- 可使用的值定义在ElementType枚举类中
TYPE
类,接口
FIELD
成员变量
METHOD
成员方法
PARAMETER
方法参数
CONSTRUCTOR
构造器
LOCAL_VARIABLE
局部变量
@Retention(...)
- 指定注解的作用范围,什么阶段起作用
- 可使用值定义在RetentionPolicy枚举类中
SOURCE
注解只作用在源码阶段,生成的字节码文件中不存在
CLASS
注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)
@Documented
指定注解可以生成到api帮助文档中
@Inherited
指定注解可以被子类继承
解析注解
概念
获取类,构造器,成员变量,成员方法等成分上的注解中的属性值的过程叫注解解析
与注解解析相关的接口
Annotation:注解的顶级接口,注解对象都是Annotation类型的对象
Class,Method,Field,Constructor,都实现了AnnotatedElement接口,具有以下方法获取注解对象
Annotation[] getDeclaredAnnotations()
获得当前对象上使用的所有注解,返回注解数组
T getDeclaredAnnotation(Class<T> annotationClass)
根据注解类型获得对应注解对象
boolean isAnnotationPresent(Class<Annotation> annotationClass)
判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false
注解解析的技巧
注解在哪个成分上,就先拿哪个成分对象
动态代理
概述
代理思想
- 就是为了增强被代理者(目标对象)的功能,或为了保护目标对象不被外界非法访问,需要找人(代理)代替自己去处理某些事
JDK动态代理
- 通过创建代理对象,在不改变原有代码的基础上,给程序增加新的功能,实现了程序的功能增强
- 要求:目标类必须要实现接口,JDK只能为实现了接口的类生成代理对象
快速入门
动态代理开发步骤
- 定义接口(Star),里面定义行为(sing和dance方法)
- 定义目标类(BigStart)实现Star接口,重写sing和dance方法,这个目标类就是被代理的类
- 在main方法中,创建目标对象
- 创建代理对象(重点)
- 调用代理对象的方法,观察结果...
如何创建代理对象
- Java的java.lang.reflect.Proxy包中提供一个静态方法,用于为目标对象生成一个代理对象返回
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)
- 参数一:类加载器,为代理类生成Class对象,从而产生代理对象
- 参数二:接口数组,代理类要实现的接口列表
- 参数三:调用处理器,当调用代理对象方法时,该处理器就来处理代理逻辑,也就是用来定义代理对象要做的事
- 返回值:生成的代理对象
InvocationHandler接口中的invoke方法
public Object invoke(Object proxy,Method method,Object[] args)作用
- 代理对象的任何方法被调用,此invoke方法就会执行
- 参数一:代理对象
- 参数二:调用代理对象的方法
- 参数三:调用代理对象方法传递的参数值
- 返回值:哪里调用代理对象方法,此处的返回值就返回到哪里
日志技术
概述
什么是日志
程序运行过程中产生的信息(数据)叫日志,我们可以把这些信息输出到控制台,文件等地方.一旦程序出现bug,或者出现一些意外情况,程序员可以通过分析日志文件,来排查问题
日志技术
把信息输出到控制台或者存储到文件/数据库中的技术叫日志技术
输出语句(sout)的弊端
- 信息只会展示在控制台
- 不能将日志记录到其他的位置(文件,数据库)
- 想取消日志,需要修改源代码才可以完成
日志技术的体系和Logback概述
日志接口
设计日志框架的一套标准,日志框架需要实现这些接口
- Jakarta Commons Logging(JCL)
- Simple Logging Facade for Java(SLF4J)
日志框架
牛人或者第三方公司已经做好的实现代码,后来者直接可以拿去使用
- JUL(java.util.logging)
- Log4j
- Logback
- 其他实现
注意
- 因为对Jakarta Commons Logging 接口不满意,有人就搞了SLF4J;因为对Log4j的性能不满意,有人就搞了Logback
- Logback是基于slf4j的日志规范实现的框架
框架有以下三个模块
logback-core
基础模块,是其他两个模块依赖的基础(必须有)
logback-classic
完整实现了slf4j API的模块(必须有)
logback-access
与Tomcat和Jetty等Servlet容器集成,以提供HTTP访问日志的功能(可选,以后再接触)
想使用Logback日志框架,至少需要在项目中整合一下三个jar包:
- slf4j-api:日志接口
- logback-core
- logback-classic
Logback快速入门
实现步骤
- 将资料中lib目录下的logback相关jar包复制到模块中,并add as library添加为模块依赖
- 创建Logback框架提供的Logger对象,然后用Logger对象调用其提供的方法就可以记录运行的日志信息了
Logback配置文件
核心配置文件logback.xml
我们可以在src目录中提供一个logback,xml配置文件来对Logback日志框架进行个性化控制
设置1:日志的输出位置,输出格式的设置
通常可以设置2个输出日志的位置,一个是控制台,一个是系统文件中
设置2:开启日志(ALL),取消日志(OFF)
<root level="ALL">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
Logback日志级别
日志级别指的是日志信息的类型,用于控制系统中哪些类型的日志可以输出,常见的日志级别如下(由低到高):
- trace:追踪,指明程序运行轨迹,开发中很少用
- debug:主要用于开发与测试过程中打印一些业务信息,不可以用于线上环境
- info:输出重要的运行信息,数据连接,网络连接,等等,使用较多
- warn:记录警告信息,不一定影响程序的运行
- error:用于记录ERROR和Exception信息
设置日志级别
<root levle="info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
- 只有日志的级别是大于或者等于配置文件的日志级别,才会被记录,否则不记录
- all表示输出所有级别的日志信息,off表示关闭日志记录