javaEE进阶小结与回顾(七)

发布时间 2023-04-16 09:47:55作者: zFlame_5020

单元测试

概述

针对最小的功能单元(方法),编写测试代码对其进行正确性测试

  • 需要测试
  • 目前只能在main方法编写测试代码,去调用其他方法进行测试
  • 使用起来很不灵活,如果前面的方法测试有错,后面的方法就无法执行
  • 无法得到测试的报告,需要程序员自己去观察测试是否成功

Jnuit单元测试工具

  • 是一个开发源代码的Java测试框架
  • 常用的版本又Junit4和Junit5两个版本
优点
  • 可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立
  • 不需要程序员去分析测试的结果,会自动生成测试报告
  • 测试成功显示成绿色,失败显示成红色

Junit框架快速入门

步骤

  1. 将Junit框架的jar包导入到项目种
  2. 创建测试类,创建测试方法(注意:测试方法必须是公共的,无参数,无返回值的非静态方法)
  3. 在要测试方法上使用@Test注解修饰(标注该方法是一个测试方法)
  4. 在测试方法中,编写代码调用你写的功能
  5. 选中测试方法,右键选择"Junit运行"

Junit测试-断言测试

单元测试断言

  • 所谓断言,意思是程序员可以预测程序的运行结果,检查程序的运行结果是否与预期一致
  • 做法:使用Assert类的assertEquals(期望值,实际值)进行断言测试

优点

  • 断言结果一致,显示成绿色,断言结果不一致,显示成红色
  • 不需要程序员去分析测试的结果,会自动生成测试报告出来

Junit测试-常见注解

@Test
测试方法
@Before
用来修饰实例方法,该方法会在每一个测试方法执行之前执行一次
@After
用来修饰实例方法,该方法会在每一个测试方法执行之后执行一次
@BeforeClass
用来静态修饰方法,该方法会在所有测试方法之前只执行一次
@AfterClass
用来静态修饰方法,该方法会在所有测试方法之后只执行一次
@BeforeEach
用来修饰实例方法,该方法会在每个测试方法执行之前执行一次
@AfterEach
用来修饰实例方法,该方法会在每个测试方法执行之后执行一次
@BeforeAll
用来静态修饰方法,该方法会在所有测试方法之前只执行一次
@AfterAll
用来静态修饰方法,该方法会在所有测试方法之后只执行一次

  • 开始执行的方法:初始化资源
  • 执行完之后的方法:释放资源

反射

概述

  • java反射机制是指:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意方法和属性,这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制

简单说,反射就是一种机制,可以运行时,动态创建对象,动态调用方法

优缺点

优点

  • 提高程序的灵活性和扩展性
  • 降低耦合性,提高自适应能力
  • 它允许程序创建和控制任何类的对象,无需提前硬编码目标类

缺点

  • 性能问题:基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码,因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用
  • 维护问题:使用反射会模糊程序内部逻辑,程序员希望在源代码中看到程序的逻辑,反射却绕过源代码技术,因而带来维护问题,反射代码比相应直接代码更复杂

获取字节码对象

反射的使用步骤

  1. 加载某个类,得到Class对象
  2. 获取类中成员(成员变量Field对象,成员方法Method对象,构造方法Constructor对象)
  3. 调用这些对象的方法,使用它们

获取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表示关闭日志记录