Java Junit和反射原理详解

1、junit的使用

junit单元测试

        测试分类:

                1、黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值

                2、白盒测试:需要写代码,关注程序具体的执行流程

        junit其实就是白盒测试的一种

        使用步骤:

                1、定义一个测试类

package com.itheima.junit;

//定义一个计算器类
public class Calculator {

    //加法运算方法
    public int add(int a,int b){
        return  a + b;
    }

    //减法运算方法
    public int sub(int a,int b){
        return  a - b;
    }
}

                2、定义测试方法:可以独立运行

package com.itheima.test;

import com.itheima.junit.Calculator;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.security.PublicKey;

public class CalculatorTest {

    /**
     * 初始化方法:
     * 用于资源申请,所有测试方法在执行前都会先执行该方法
     */
    @Before
    public void init(){
        System.out.println("init...");
    }


    /**
     * 释放资源方法
     * 在所有测试方法执行完之后,都会自动执行该方法
     */
    @After
    public void close(){
        System.out.println("close...");
    }

    @Test
    public void testadd(){
        Calculator calculator = new Calculator();
        int result = calculator.add(1, 2);
        Assert.assertEquals(3,result);
    }

    @Test
    public void testsub(){
        Calculator calculator = new Calculator();
        int result = calculator.sub(1,1);
        Assert.assertEquals(0,result);
    }
}

                3、给测试方法加上@Test注解

                4导入junit依赖环境

判定结果:

        红色:失败

        绿色:成功

        一般我们会使用断言操作来处理结果

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

        补充:

                @Before:

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

                @After

                        修饰的方法会在测试方法执行之后被自动运行

2、反射

        反射被称为框架设计的灵魂

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

        反射:将类的各个组成部分封装为其他对象,这就是反射机制

                好处:

                        1、可以在程序运行过程中,操作这些对象

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

获取Class对象的方式:

        1、Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象

                多用于配置文件,将类定义在配置文件中,读取文件,加载类

        2、类名.Class:通过类名的属性class获取

                多用于参数的传递

        3、对象.getClass():getClass()方法在object类中定义着

                多用于对象的获取字节码的方式

package com.itheima.reflect;

import com.itheima.domain.Person;

public class ReflectDemo1 {

    /**
     *          1、Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象
     *
     *         2、类名.Class:通过类名的属性class获取
     *
     *         3、对象.getClass():getClass()方法在object类中定义着
     *
     */

    public static void main(String[] args) throws Exception {

        //1、Class.forName(“全类名”)
        Class cls1 = Class.forName("com.itheima.domain.Person");
        System.out.println(cls1);
        //2、类名.Class
        Class cls2 = Person.class;
        System.out.println(cls2);
        //3、对象.getClass()
        Person person = new Person();
        Class cls3 = person.getClass();
        System.out.println(cls3);

    }
}

结论:

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

Class对象功能:

        获取功能:

                1、获取成员变量们

                        Field[ ] getFields()       获取所有public修饰的成员变量

                        Field geiField(String name)        获取指定名称的public修饰的成员变量

                        Field[ ] getDeclareFields()

                        Field getDeclareField(String name)

                Field:成员变量

                        操作:

                                1、设置值        get()

                                2、获取值        set()

                                3、忽略访问权限修饰符的安全检查

                                        setAccessible(true):暴力反射

package com.itheima.reflect;

import com.itheima.domain.Person;

import java.lang.reflect.Field;

public class ReflectDemoField {

    /**
     * Class对象功能:
     *         获取功能:
     *                 1、获取成员变量们
     *                         Field[ ] getFields()
     *                         Field geiField(String name)
     *
     *                         Field[ ] getDeclareFields()
     *                         Field getDeclareField(String name)
     */

    public static void main(String[] args) throws Exception {
        //获取Person的class对象
        Class personClass = Person.class;
        //1、 Field[ ] getFields() 获取所有public修饰的成员变量
        Field[] fields = personClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("--------------------");
        //2、Field geiField(String name) 获取指定名称的public修饰的成员变量
        Field a = personClass.getField("a");
        //获取成员变量a的值
        Person p = new Person();
        Object value = a.get(p);
        System.out.println(value);
        //设置a的值
        a.set(p,"张三");
        System.out.println(p);

        System.out.println("=================================");
        //3、Field[ ] getDeclareFields() 获取所有的成员变量,不考虑修饰符
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        System.out.println("--------------------");
        //4、Field getDeclareField(String name) 获取指定名称成员变量,不考虑修饰符
        Field d = personClass.getDeclaredField("d");
        //忽略访问权限修饰符的安全检查
        d.setAccessible(true);  //暴力反射
        Object value2 = d.get(p);
        System.out.println(value2);

    }

}

                2、获取构造方法们

        Constructor<?>[] getConstructors()

        Constructor<TgetConstructor(<?>... parameterTypes)

        Constructor<?>[] getDeclaredClasses()

        Constructor<TgetDeclaredConstructor(<?>... parameterTypes)

        Constructor:构造方法

                创建对象:

                     T newInstance(Object... initargs)

                     如果使用空参数构造方法创建对象,操作可以简化:class对象的newInstance方法

                

                        忽略访问权限修饰符的安全检查

                                        setAccessible(true):暴力反射

package com.itheima.reflect;

import com.itheima.domain.Person;

import java.lang.reflect.Constructor;

public class ReflectDemoConstructor {

       /*
               2、获取构造方法们
     *         Constructor<?>[] getConstructors()
     *         Constructor<T> getConstructor(类<?>... parameterTypes)
     *
     *         Constructor<?>[] getDeclaredClasses()
     *         Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
         */

    public static void main(String[] args) throws Exception {
        //获取Person的class对象
        Class personClass = Person.class;
        //1、Constructor<T> getConstructor(类<?>... parameterTypes)
        Constructor constructor = personClass.getConstructor(String.class, int.class);
        System.out.println(constructor);
        //创建对象
        Object person = constructor.newInstance("张三", 23);
        System.out.println(person);
        System.out.println("===============");
        //如果使用空参数构造方法创建对象,操作可以简化:class对象的newInstance方法
        Object o = constructor.newInstance();
        System.out.println(o);
    }
}

                3、获取成员方法们
                        Method[ ] getMethods();

                        Method getMethod(String name,<?>... parameterTypes)

                        Method[ ] getDeclareMethods();

                        Method getDeclareMethod(String name,<?>... parameterTypes)

                Method:方法对象

                        执行方法:

                                Object invoke(Object obj,Object... args)

                        获取方法的名称:

                                String getName:获取方法名

                4、获取类名

                        String getName()

package com.itheima.reflect;

import com.itheima.domain.Person;

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

public class ReflectDemoMethod {

    /*
        3、获取成员方法们
     *                         Method[ ] getMethods();
     *                         Method getMethod(String name,类<?>... parameterTypes)
     *
     *                         Method[ ] getDeclareMethods();
     *                         Method getDeclareMethod(String name,类<?>... parameterTypes)
     */

    public static void main(String[] args) throws Exception {
        //获取Person的class对象
        Class personClass = Person.class;
        //Method[ ] getMethods(); 获取指定名称的成员方法
        Method eat = personClass.getMethod("eat");
        Person p = new Person();
        //执行方法
        eat.invoke(p);

        System.out.println("=====================");
        Method eat1 = personClass.getMethod("eat", String.class);
        eat1.invoke(p,"饭");

        System.out.println("=====================");
        //获取所以public修饰的方法
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
            String name = method.getName();
            System.out.println(name);
//            method.setAccessible(true);

            System.out.println("======================");
            //获取类名
            String classname = personClass.getName();
            System.out.println(classname);

        }
    }
}

案例:

        需求:写一个“框架”,不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且之前其中任意的方法

        实现:

                1、配置文件

                2、反射

        步骤:

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

                例如:我拥有一个person类和一个student类

package com.itheima.domain;

public class Person {

    public void eat(){
        System.out.println("eat...");
    }
}
package com.itheima.domain;

public class Student {
    public void sleep(){
        System.out.println("sleep...");
    }
}

         里面有eat方法和sleep方法

        创建pro.properties配置文件并且将类的全类名和方法写入

className=com.itheima.domain.Student
methodName=sleep

              2、在程序中加载读取配置文件

         //1、加载配置文件
        //1.1创建properties对象
        Properties properties = new Properties();
        //1.2、加载配置文件,转换为一个集合
        //获取class目录下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
        properties.load(resourceAsStream);

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

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

//3、加载该类进内存
Class cls = Class.forName(className);

                4、创建对象

  //创建对象
        Object obj = cls.newInstance();

                5、执行方法

 //获取方法对象
        Method method = cls.getMethod(methodName);
        //执行方法
        method.invoke(obj);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值