Java基础回顾——反射

2021/5/21 12:29:46

本文主要是介绍Java基础回顾——反射,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目录
  • 基础加强
    • Junit单元测试
      • 测试分类
      • Junit使用:白盒测试
        • 步骤
    • 反射:框架设计的灵魂
    • 获取Class对象的方式
      • class对象功能:
        • 1.获取功能:
    • 反射的案例
      • 需求:
      • 实现:
      • 步骤:

基础加强

Junit单元测试

测试分类

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

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

Junit使用:白盒测试

步骤

  1. 定义一个测试类(测试用例)
    建议∶
    测试类名:被测试的类名Test calculatorTest
    包名∶xxx.xxx.xx.test com.niu.test
  2. 定义测试方法:可以独立运行
    建议︰
    方法名: test测试的方法名 testAdd()
    返回值: void
    参数列表:空参
  3. 给方法加@Test
  4. 导入junit依赖环境

判定结果︰
红色:失败
绿色:成功
一般我们会使用断言操作来处理结果
Assert.assertEquals(期望得结果,运算的结果);
补充:
@Before
初始化方法:用于资源申请,所有测试方法在执行之前都会先执行该方法
@After
释放资源方法:在所有测试方法执行完后,都会自动执行该方法

个人理解:以前咋们测试程序是否正常都是用main方法,在主函数里调用方法来验证是否运行成功,这样会有很多缺点,比如:

  1. 为了让多个方法之间不会互相产生影响,每次测试一个方法之前要把测试的其他方法注释掉;
  2. 用来测试的程序和要测试的方法程序放在同一个目录下,比较混乱,不好管理;
  3. 等等不方便的地方。

所以我们要学注解@Test

import org.junit.Assert;
import org.junit.Test;

public class CalculatorTest {
    @Test
    public void testAdd(){
        Calculator c = new Calculator();
        int add = c.add(1, 22);
        System.out.println(add);
        //断言 我断言
    }

    @Test
    public void testSub(){
        Calculator c = new Calculator();
        int sub = c.sub(2, 1);
        //断言,括号里的参数,前面一个参数是期望值,后面一个参数是真实得到的值
        //如果二者一样 就说明程序没什么问题了,运行结果没有任何异常,也没有返回值。
        Assert.assertEquals(1,sub);
    }

}


注解:@Before和@After

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class CalculatorTest {

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

    /**
     * 释放资源方法:
     *      在所有测试方法执行完后,都会自动执行该方法
     */
    @After
    public void close(){
        System.out.println("close...");
    }
    @Test
    public void testAdd(){
        Calculator c = new Calculator();
        int add = c.add(1, 22);
        System.out.println(add);
        //断言 我断言
    }

    @Test
    public void testSub(){
        Calculator c = new Calculator();
        int sub = c.sub(2, 1);
        //断言,括号里的参数,前面一个参数是期望值,后面一个参数是真实得到的值
        //如果二者一样 就说明程序没什么问题了,运行结果没有任何异常,也没有返回值。
        Assert.assertEquals(1,sub);
    }

}


反射:框架设计的灵魂

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

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

使用反射的好处:

  1. 在程序的运行过程中,操作这些对象
  2. 可以解耦,来提高程序的可扩展性。

获取Class对象的方式

  1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
    多用于配罩i文件,将类名定义在配置i文件中。读取文件,加载类
  2. 类名.Class:通过类名的属性class来获取
    多用于参数的传递
  3. 对象.getClass :getClass()方法在Object类中定义着
    多用于对象的获取字节码的方式

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

class对象功能:

1.获取功能:
  1. 获取成员变们

    Field[] getFields()
    Field getField(string name)
    Field[getDeclaredFields()
    Field getDeclaredField(string name)
    
  2. 获取构造方法们

    Constructor<?>[] getConstructors(
    Constructor<T> getConstructor(类<?>... parameterTypes)
    Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)* 
    Constructor<?>[] getDeclaredConstructors()
    
    
  3. 获取成员方法们∶

    Method[]getMethods(
    Method getMethod(string name,类<?>... parameterTypes)
    Method[] getDeclaredMethods()
    Method getDeclaredMethod(string name,类<?>... parameterTypes)
    
  4. 获取类名

    String getName()
    

暴力反射:setAccessible();//忽略访问权限修饰符安全检查

反射的案例

需求:

​ 写一个"框架"【类】,在不改变该类的任意代码的前提下,可以帮助我们创建任意类的对象,并执行其中任意方法

实现:

1.配置文件

2.反射

步骤:

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

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

3.使用反射技术,来加载类文件进内存,并创建对象,并执行方法

代码:

Person.java

package domain;

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

    public Person() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

    public void eat(){
        System.out.println("eat...");
    }
}

Student.java

package domain;

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

a.properties

className=domain.Student
methodName=sleep

ReflectTest.java

package domain;

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

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //可以创建任意类的对象,可以执行任意方法
        /*
            可以称为框架的前提:不能改变该类的任意代码,可以创建任意类的对象,可以执行任意方法
         */
        /*Person p = new Person();
        p.eat();*/

        /*Student student = new Student();
        student.sleep();*/

        /*
            1.将需要创建的对象的全类名和需要执行的方法定义在配置文件中
            2.在程序中加载读取配置文件
            3.使用反射技术,来加载类文件进内存,并创建对象,并执行方法
         */
        //1.加载配置文件
        //1-1创建Properties对象
        Properties pro = new Properties();
        //1.2加载配置文件,转换为一个集合(双链Map集合,因为Properties是Map的一个子类)
        //1.3获取文件路径(class目录下的配置文件)
        ClassLoader cl = ReflectTest.class.getClassLoader();//获取到了类加载器
        InputStream ras = cl.getResourceAsStream("a.properties");//得到了a.properties文件的字节流
        pro.load(ras);

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

        //3.加载该类进内存
        Class cls = Class.forName(cN);
        //4.创建对象
        Object obj = cls.newInstance();
        //5.获取方法对象
        Method method = cls.getMethod(mN);
        //6.执行方法
        method.invoke(obj);
    }
}

改写配置文件a.properties文件之前

改写配置文件a.properties文件之后

a.properties

className=domain.Person
methodName=eat


个人总结:用了反射之后,我们只需要更改配置文件,就可以让程序完成不同的工作,不用去改源代码,这样代码也更好管理~



这篇关于Java基础回顾——反射的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程