day14_Java高级技术

29 阅读8分钟

day14_Java高级技术

1. 单元测试

1.1 Junit框架

  • 单元测试
    • 就是针对最小的功能单元(方法),编写测试代码对其进行正确性测试
  • Junit单元测试框架
    • 可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立
    • 不需要程序员去分析测试的结果,会自动生成测试报告出来
    • 拥有更强大的测试能力
  • 操作步骤
    1. 将Junit框架的jar包导入到项目中
    2. 编写测试类、测试类方法,测试方法必须是公共的,无参数,无返回值的非静态方法
    3. 必须在测试方法上使用@Test注解,用于标注该方法是一个测试方法
    4. 在测试方法中,编写程序调用被测试的方法即可
    5. 选中测试方法运行即可,如果测试通过测试标志则是绿色,如果测试失败测试标志则是红色
  • 断言方法
    • Assert.assertEquals()

1.2 Junit常用注解

  • Junit 4.xxxx版本
注解说明
@Test测试方法
@Before用来修饰一个实例方法,该方法会在每一个测试方法执行之前执行一次。
@After用来修饰一个实例方法,该方法会在每一个测试方法执行之后执行一次。
@BeforeClass用来修饰一个静态方法,该方法会在所有测试方法之前只执行一次。
@AfterClass用来修饰一个静态方法,该方法会在所有测试方法之后只执行一次。
  • Junit 5.xxxx版本
注解说明
@Test测试方法
@BeforeEach用来修饰一个实例方法,该方法会在每一个测试方法执行之前执行一次。
@AfterEach用来修饰一个实例方法,该方法会在每一个测试方法执行之后执行一次。
@BeforeAll用来修饰一个静态方法,该方法会在所有测试方法之前只执行一次。
@AfterAll用来修饰一个静态方法,该方法会在所有测试方法之后只执行一次。

2. 反射

2.1 概述

  • 反射
    • 以编程的方式获取类中的各种成分,如成员变量、方法、构造器等
  • 优势
    • 使用反射创建对象,代码更复杂,无视修饰符,功能更强大灵活
  • 作用
    • 可以在运行时得到一个类的全部成分然后操作
    • 可以破坏封装性
    • 更重要的用途是适合:做Java高级框架。基本上主流框架都会基于反射设计一些通用技术功能

2.2 获取元素

2.2.1 获取类

  • 获取类是反射的第一步,即就是得到加载后的类对象

实现

// 方式一:直接获取
Class c1 = 类名.class;

// 方式二:Object提供的方法:public Class getClass()
Class c2 = 对象.getClass()

// 方式三:调用Class提供方法:public static Class forName(String package);
Class c3 = Class.forName(“全类名”);

2.2.2 获取类的构造器

  • Class提供了从类中获取构造器的方法
方法说明
Constructor<?>[] getConstructors()返回所有构造器对象的数组(只能拿public的)
Constructor<?>[] getDeclaredConstructors()返回所有构造器对象的数组,存在就能拿到
Constructor<T> getConstructor(Class<?>... parameterTypes)返回单个构造器对象(只能拿public的)
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)返回单个构造器对象,存在就能拿到
  • 获取到构造器的作用:依然是初始化一个对象返回
符号说明
T newInstance(Object... initargs)根据指定的构造器创建对象
public void setAccessible(boolean flag)设置为true,表示取消访问检查,进行暴力反射
  • 作用
    • 创建对象
    • 如果是非public的构造器,需要打开权限(暴力反射),然后再创建对象,即利用反射破坏封装性,执行非公开的构造器

2.2.3 获取类的成员变量

  • Class提供了从类中获取成员变量的方法
方法说明
public Field[] getFields()返回所有成员变量对象的数组(只能拿public的)
public Field[] getDeclaredFields()返回所有成员变量对象的数组,存在就能拿到
public Field getField(String name)返回单个成员变量对象(只能拿public的)
public Field getDeclaredField(String name)返回单个成员变量对象,存在就能拿到
  • 获取到成员变量的作用:依然是赋值、取值
方法名说明
void set(Object obj, Object value)赋值
Object get(Object obj)取值
public void setAccessible(boolean flag)设置为true,表示取消访问检查,进行暴力反射
  • 作用
    • 在某个对象中取值和赋值
    • 如果某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值

2.2.4 获取类的成员方法

  • Class提供了从类中获取成员方法的方法
方法说明
Method[] getMethods()返回所有成员方法对象的数组(只能拿public的)
Method[] getDeclaredMethods()返回所有成员方法对象的数组,存在就能拿到
Method getMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象(只能拿public的)
Method getDeclaredMethod(String name, Class<?>... parameterTypes)返回单个成员方法对象,存在就能拿到
  • 获取到成员方法的作用:依然是执行该方法
方法名说明
public Object invoke(Object obj, Object... args)触发某个对象的该方法执行。
public void setAccessible(boolean flag)设置为true,表示取消访问检查,进行暴力反射
  • 作用
    • 在某个对象中触发该方法执行
    • 如果某成员方法是非public的,需要打开权限(暴力反射),然后再触发执行

3. 注解

3.1 自定义注解

  • 注解

    • 就是Java代码里的特殊标记
    • Java程序中的类上、构造器上、方法上、成员变量上、参数、等都可以用注解进行标记
  • 作用

    • 对Java中类、方法、成员变量做标记,然后进行特殊处理
  • 自定义注解

    • 属性类型只能是一下类型或该类型的一维数组
      • 基本数据类型
      • String
      • Class
      • 注解
      • 枚举
    • value
      • value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写
      • 如果有多个属性,且多个属性没有默认值,那么value名称是不能省略的
// 自定义注解
public @interface 注解名称 {
    public 属性类型 属性名() default 默认值;
}

// 使用注解
@注解名(属性名1=值1, 属性名2=值2...)

3.2 元注解

  • 就是修饰注解的注解
  • 元注解有两个
    • @Target:约束自定义注解只能在哪些地方使用
    • @Retention:申明注解的生命周期

@Target中可使用的值定义在ElementType枚举类中,常用值如下

  • TYPE,类,接口
  • FIELD,成员变量
  • METHOD,成员方法
  • PARAMETER,方法参数
  • CONSTRUCTOR,构造器
  • LOCAL_VARIABLE,局部变量

@Retention中可使用的值定义在RetentionPolicy枚举类中,常用值如下

  • SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
  • CLASS: 注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
  • RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段

image-20230826192234750.png

3.3 注解的解析

  • 注解的解析

    • 注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容
  • 与注解解析相关的接口

    • Annotation:注解的顶级接口,注解都是Annotation类型的对象
    • AnnotatedElement:该接口定义了与注解解析相关的解析方法
    方法说明
    Annotation[] getDeclaredAnnotations()获得当前对象上使用的所有注解,返回注解数组。
    T getDeclaredAnnotation(Class<T> annotationClass)根据注解类型获得对应注解对象
    boolean isAnnotationPresent(Class<Annotation> annotationClass)判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false
  • 所有的类成分Class、Method、Field、Constructor都实现了AnnotatedElement接口,他们都拥有解析注解的能力

4. 动态代理

  • 代理

    • 代理思想就是被代理者没有能力,或者不愿意去完成某件事情,需要找个人(代理)代替自己去完成这件事
    • 是一个用来对被代理对象的行为进行增强的对象
  • 动态代理

    • 动态代理主要是对被代理对象的行为进行代理,对功能进行增强
  • Java中代理的代表类是java.lang.reflect.Proxy,它提供了一个静态方法,用于为被代理对象,产生一个代理对象返回

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
    
    • 参数一:类加载器,加载代理类,产生代理对象
    • 参数二:真实业务对象的接口,被代理的方法交给代理对象
    • 参数三:代理的核心处理程序
  • 实现动态代理的步骤

    • 必须存在接口
    • 被代理对象需要实现接口
    • 使用Proxy类提供的方法,为被代理对象创建一个代理对象
  • 代理对象调用方法的执行流程

    • 先走向代理
    • 代理中可以真正触发被代理对象的方法执行
    • 回到代理中,由代理负责返回结果给调用者
  • 动态代理的优点

    • 可以在不改变方法源码的情况下,实现对方法功能的增强,提高了代码的复用
    • 简化了编程工作、提高了开发效率,同时提高了软件系统的可扩展性
    • 可以为被代理对象的所有方法做代理
    • 非常的灵活,支持任意接口类型的实现类对象做代理