Day01 Junit 单元测试 & 反射

JavaWeb 复习打卡day01: 2026年3月8日

视频链接:【黑马程序员JavaWeb全套基础教程】http://【黑马程序员JavaWeb全套基础教程,java web从入门到项目实战(IDEA版javaweb)】 https://www.bilibili.com/video/BV1qv4y1o79t/?share_source=copy_web&vd_source=2f0acee8af0c9fe3c199b29343736df5

目录

[一: Junit 单元测试](#一: Junit 单元测试)

[1. 测试分类](#1. 测试分类)

[2. Junit 使用步骤](#2. Junit 使用步骤)

[二: Java代码在计算机中经历的三个阶段](#二: Java代码在计算机中经历的三个阶段)

三:反射

[3.1 获取字节码文件Class对象的三种方法](#3.1 获取字节码文件Class对象的三种方法)

[3.2 Class对象功能](#3.2 Class对象功能)

(1)获取成员变量们

(2)获取构造方法们

(3)获取成员方法们

[3.3 反射案例](#3.3 反射案例)


一: Junit 单元测试

1. 测试分类

  • 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值
  • 白盒测试:需要写代码。关注程序具体的流程

2. Junit 使用步骤

(Junit 属于白盒测试)

(1).定义一个测试类(测试用例)

建议:测试类名为:被测试类名Test 如 CalculateTest

包名:xxx.xxx.xx.test 如 cn.itcast.test

(2) 定义测试方法:可以单独运行

建议:

*方法名:test测试的方法名 eg:testAdd()

*返回值:void

*参数列表:空参

(3) 给方法上面加上@Test

(4) 导入junit环境依赖

判定结果:

*❌红色:失败

*✅绿色:成功

*一般使用断言Assert来处理结果

即:Assert.assertEquals(期望的结果,运算的结果);

*补充:

@Before:修饰的方法会在测试方法之前被自动执行

@After:修饰的方法会在测试方法之后自动执行

二: Java代码在计算机中经历的三个阶段

  1. Source源代码阶段------Java源代码(.java)被编译成.class文件,放置在Java虚拟机(JVM)

  2. Class类对象阶段------Java虚拟机使用类加载器(ClassLoader)装载.class文件,将其加载进内存。

  3. Runtime运行阶段------类加载完成之后,会进行字节码校验(这里就存在一个字节码校验器),校验通过之后,JVM解释器会把字节码翻译成机器码交由操作系统执行。

知识点

类加载器:将.class字节码文件加载进内存
Class类:用来描述所有字节码文件的共同的一些特征和行为

Class类对象有哪些呢?

  1. 成员变量(用来拿到值,设置值)封装为Field对象

  2. 构造方法(用来创建对象)封装为Constructor对象

  3. 成员方法(用来执行它)封装为Method对象

故,Field对象、Constructor对象、Method对象这三个对象组成了Class类。

三:反射

(反射是框架设计的灵魂)

框架: 半成本软件,可以在框架的基础上进行软件开发,简化编码

反射机制:将类的各部分封装为其他对象

好处:可以在程序运行过程中,操作这些对象;

可以解耦,提高程序的可扩展性

3.1 获取字节码文件Class对象的三种方法

  • Class.formate("全类名"):将字节码文件加载进内存,返回Class对象。
  • 使用阶段:第一阶段,当Java代码还未加载进内存时,使用该方法

  • 使用场景:多用于配置文件,将类名定义在配置文件中,读取文件,加载类

  • 类名.class:通过Class类类名的属性class获取
  • 使用阶段:第二阶段,当字节码文件已经加载进了内存,这时有了Class对象,使用该方法

  • 使用场景:多用于参数的传递

  • 对象.getClass():该方法有在Object类中定义着
  • 使用阶段:有对象的情况下,使用该方法

  • 使用场景: 多用于对象获取字节码的方式

java 复制代码
package com.yinyao.domain;

public class Person {
    private String name;
    private int age;
    public String a;
    public int b;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", a='" + a + '\'' +
                ", b=" + b +
                '}';
    }

    public void eat(){
        System.out.println("在干饭中...");
    }

    public void eat(String food){
        System.out.println("正在吃" + food);
    }

}

总结

同一个字节码文件.class 在一次程序运行过程中,只会被加载一次,不论通过哪一种方法获取的Class 对象都是同一个。

3.2 Class对象功能

(1)获取成员变量们
  • Field[] getFields(): 获取所有public修饰的成员变量
  • Field getField(String name):获取指定public修饰的成员变量
  • Field[] getDeclaredFields(): 获取所有成员变量的值,不考虑修饰符
  • Field getDeclaredField(String name): 获取指定成员变量的值,不考虑修饰符

Field成员变量对象操作

  • void set(Object obj,Object value): 获取值
  • get(Object obj): 设置值
  • setAccessible(true):暴力反射忽略访问权限修饰符的安全检查(暴力反射)
java 复制代码
package com.yinyao.reflect;
import com.yinyao.domain.Person;
import java.lang.reflect.Field;


/**
 * 1. 获取成员变量们:
 *              *Field[] getFields():获取所有public修饰的成员变量
 *              *Field getField(String name):获取指定public修饰的成员变量
 *
 *              *Field[] getDeclaredFields():获取所有成员变量的值,不考虑修饰符
 *              *Field getDeclaredField(String name):获取指定成员变量的值,不考虑修饰符
 */

public class ReflectDemo2 {
    public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
        //0、获取Person的Class对象
        Class personClass = Person.class;


        //1.获取public修饰的成员对象们
        Field[] fields = personClass.getFields();
        //2.遍历public修饰的成员对象们(快捷键iter)
        for (Field field : fields) {
            System.out.println(field);//public java.lang.String com.yinyao.domain.Person.a
                                      //public int com.yinyao.domain.Person.b
        }

        //1.获取指定成员变量a
        Field a = personClass.getField("a");//getField()对其抛出异常
        //2.获取成员变量a的值
        Person person = new Person();//get()方法里面传入的是Person的一个对象
        Object o = a.get(person);
        System.out.println(o);//因为没有对其进行设置,所以默认是null
        //3.设置a的值
        a.set(person,"张三");
        System.out.println(person);//Person{name='null', age=0, a='张三', b=0}
        System.out.println(a);//public java.lang.String com.yinyao.domain.Person.a
        System.out.println(person.a);//张三

        //1.获取所有的成员变量,不考虑修饰符
        Field[] declaredFields = personClass.getDeclaredFields();
        //2.遍历
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        /**
         * 遍历后得:
         * private java.lang.String com.yinyao.domain.Person.name
         * private int com.yinyao.domain.Person.age
         * public java.lang.String com.yinyao.domain.Person.a
         * public int com.yinyao.domain.Person.b
         */

        //1.获取指定成员变量的值,不考虑修饰符
        Field age = personClass.getDeclaredField("age");
        System.out.println(age);//private int com.yinyao.domain.Person.age
        //2.获取age的值
        //2.1进行忽略访问权限修饰符的安全检查
        age.setAccessible(true);//暴力反射
        //2.2利用get方法获取
        Person person1 = new Person();
        Object o1 = age.get(person1);
        System.out.println(o1);//0
        //3.设置age的值
        age.set(person1,21);
        System.out.println(person1.getAge());//21
    }
}
(2)获取构造方法们
  • Constructor<?>[] getConstructors():获取所有public修饰的构造方法
  • Constructor<T>[] getConstructor(类<?>...parameterTypes):获取指定参数的公共构造方法
  • Constructor<?>[] getDeclaredConstructors():获取类中所有构造方法(不分权限)
  • Constructor<T>[] getDeclaredConstructor(类<?>...parameterTypes):获取指定参数的任意权限构造方法

Constructor构造方法对象操作

  • T newInstance(Object... initargs): 创建对象,如果使用空参构造方法创建对象,操作可以简化,即使用Class对象的 newInstance() 方法
  • setAccessible(true): 忽略访问权限修饰符的安全检查(暴力反射)
java 复制代码
package com.yinyao.reflect;
import com.yinyao.domain.Person;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
 *2. 获取构造方法们:
 *              *Constructor<?>[] getConstructors():获取所有public修饰的构造方法
 *              *Constructor<T>[] getConstructor(类<?>...parameterTypes)
 *
 *              *Constructor<?>[] getDeclaredConstructors()
 *              *Constructor<T>[] getDeclaredConstructor(类<?>...parameterTypes)
 */

public class ReflectDemo3 {
    public static void main(String[] args) throws NoSuchMethodException,
            InvocationTargetException, InstantiationException, IllegalAccessException {
        //0、获取Person的Class对象
        Class<Person> personClass = Person.class;
        //1.获取构造方法对象
        Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);//抛出异常
        System.out.println(constructor);//public com.yinyao.domain.Person(java.lang.String,int)
        //2.根据构造方法创建对象
        Person person = constructor.newInstance("张三", 23);//抛出异常
        System.out.println(person);//Person{name='张三', age=23, a='null', b=0}

        System.out.println("--------------------------------------------------------");

        //创建空参对象(不需要创建构造方法对象)
        Person person1 = personClass.newInstance();
        System.out.println(person1);//Person{name='null', age=0, a='null', b=0}

    }
}
(3)获取成员方法们
  • Method[] getMethods():自身 + 父类的所有 public 方法
  • Method getMethod(String name,类<?>...parameterTypes):自身 + 父类的指定 public 方法
  • Method[] getDeclaredMethods():仅自身的所有方法(任意权限)
  • Method getDeclaredMethod(String name,类<?>...parameterTypes):仅自身的所有方法(任意权限)

Method 构造方法对象操作

  • Object invoke(Object obj,Object... args): 执行方法
  • String getName : 获取执行方法名称
java 复制代码
package com.yinyao.reflect;

import com.yinyao.domain.Person;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 *  3. 获取成员方法们:
 *              *Method[] getMethods()
 *              *Method getMethod(String name,类<?>...parameterTypes)
 *
 *              *Method[] getDeclaredMethods()
 *              *Method getDeclaredMethod(String name,类<?>...parameterTypes)
 *
 *  4. 获取类名:
 *              *String getName()
 */
public class ReflectDemo4 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //0、获取Person的Class对象
        Class personClass = Person.class;
        //1.获取指定public修饰的成员方法(空参方法)
        Method eat_method = personClass.getMethod("eat");//抛出异常
        Person person = new Person();
        //2.执行方法
        eat_method.invoke(person);//在干饭中...           抛出异常
        System.out.println("--------------------------------------------");

        //1.获取指定public修饰的成员方法(带参数)
        Method eat_method1 = personClass.getMethod("eat", String.class);
        Person person1 = new Person();
        //2.执行方法
        eat_method1.invoke(person1,"糖醋鱼");//正在吃糖醋鱼
        System.out.println("---------------------------------------------");

        //获取全部public修饰的方法
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);//因为Person类继承Object类,所以打印出来后还会有一些隐藏的Object类里的方法
            String methodName = method.getName();//获取方法名称
            System.out.println(methodName);
        }
        System.out.println("************************************************");
        String className = personClass.getName();
        System.out.println(className);//com.yinyao.domain.Person
    }
}

3.3 反射案例

  • 需求:案例:写一个"框架",不能改变任何代码的前提下, 可以帮我们创建任意类的对象,并且执行其中任意方法。

  • 实现:配置文件 + 反射技术

  • 步骤:

  1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中

  2. 在程序代码中加载读取配置文件

  3. 使用反射技术来加载类文件进内存

  4. 创建对象

  5. 执行方法

java 复制代码
package com.yinyao.reflect;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * 案例:写一个"框架",
 * 不能改变任何代码的前提下,
 * 可以帮我们创建任意类的对象,并且执行其中任意方法
 */
public class ReflectDemo5 {
    public static void main(String[] args) throws IOException, ClassNotFoundException,
            InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //1.加载配置文件
        //1.1创建Properties对象
        Properties properties = new Properties();
        //1.2加载配置文件,转换为一个集合
        //1.2.1获取class目录下的配置文件
        ClassLoader classLoader = ReflectDemo4.class.getClassLoader();
        InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");//getResourceAsStream获取资源对应的字节流
        properties.load(resourceAsStream);

        //2.获取配置文件中定义的数据
        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");

        //3.加载该类进内存
        Class aClass = Class.forName(className);//抛出异常

        //4.创建对象
        Object o = aClass.newInstance();//抛出异常

        //5.获取成员方法对象
        Method method = aClass.getMethod(methodName);//抛出异常

        //6.执行方法
        method.invoke(o);//抛出异常
    }
}
相关推荐
逆境不可逃2 小时前
【从零入门23种设计模式16】行为型之迭代器模式
java·开发语言·数据结构·算法·设计模式·职场和发展·迭代器模式
JTCC2 小时前
Java 设计模式西游篇 - 第七回:责任链模式过难关 通关文牒层层批
java·设计模式·责任链模式
Java练习两年半2 小时前
互联网大厂 Java 求职面试:探讨微服务与云原生
java·微服务·云原生·面试·技术栈
I_LPL2 小时前
day49 代码随想录算法训练营 图论专题2
java·算法·深度优先·图论·广度优先·求职面试
xu_ws2 小时前
idea新建Spring-ai项目-ollama
java·intellij-idea·ai编程
JTCC2 小时前
Java 设计模式西游篇 - 第九回:外观模式简化繁 如来神掌一指定
java·设计模式·外观模式
慧都小项2 小时前
JAVA开发工具IntelliJ IDEA v2026更新前瞻:更优的交互视觉,编程体验升级
java·开发语言·intellij-idea
ノBye~2 小时前
IntelliJ IDEA 2024创建项目Maven和Maven Archetype
java·maven·intellij-idea
hopsky2 小时前
idea 运行maven项目出现莫名的错误
java·maven·intellij-idea