Java类的反射机制

Java类的反射机制

类的反射(Reflection) 被称为是 动态语言 的关键,反射机制允许程序在执行期间借助Reflection API 取得任何类的任何内部信息 其中包括类中私有的属性,方法,构造器等,并能直接操作任何对象的内部属性方法等。

反射与一般对象的生成及调用的不同:
在这里插入图片描述
反射相关的主要API
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造器

如果要操作Reflection 那么我们至少要得到Class类。
如何获取CLass的操作:

package Reflection;

import org.junit.jupiter.api.Test;

public class ReflectionTest {
    /**
     *  关于java.lang.Class类的理解
     *  1 类的加载过程:
     *  程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)
     *  接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件
     *  加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,
     *  此运行时类,就作为Class的一个实例。
     *
     *  2 换句话说,Class的实例就对应这一个运行时类
     *
     *  3 加载到内存中的运行时类,会缓存一定得到时间。在此时间之内,我们可以通过不同的方式
     *    来获取此运行是的类。
     *
     */

    // 获取Class的实例的方式 并不是创建
    // 前三种需要掌握
    @Test
    public void test1() throws ClassNotFoundException {
        // 方式一:调用运行时类的属性:.class
        Class personClass = Person.class;
        System.out.println(personClass);

        // 方式二:通过运行时类的对象,通过对象调用getClass的方法
        Person p1 = new Person();
        Class p1Class = p1.getClass();
        System.out.println(p1Class);

        // 方式三: 调用Class的静态方法 forName(String class path)
        Class p2Class = Class.forName("Reflection.Person");
        System.out.println(p2Class);

        System.out.println(personClass == p1Class);
        System.out.println(personClass == p2Class);

        // 方式四:使用类的加载器
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class loadClass = classLoader.loadClass("Reflection.Person");
        System.out.println(p1Class == loadClass);
    }
}

在这里插入图片描述

ClassLoader:
在这里插入图片描述

    @Test
    public void test1(){
        // 对于自定义类,使用系统类加载器进行加载
        // 得到一个app 的系统类加载器
        ClassLoader loader = ClassLoaderTest.class.getClassLoader();
        System.out.println(loader); // 输出 sun.misc.Launcher$AppClassLoader@18b4aac2

        // 得到扩展类加载器
        ClassLoader loader1 = loader.getParent();
        System.out.println(loader1); // 输出 sun.misc.Launcher$ExtClassLoader@71dac704

        // 尝试调用 引导类加载器
        // 但是引导类加载器主要负责java的核心类库无法加载自定义类。
        ClassLoader loader2 = loader1.getParent();
        System.out.println(loader2); // 输出 null
    }

使用ClassLoader读取配置文件:

    // 读取配置文件的操作
    @Test
    public void test2() throws Exception {
        // 用properties去获取配置文件
        // 此文件默认为当前module下
//        Properties pros = new Properties();
//        FileInputStream fis = new FileInputStream("jdbc.properties");
//        pros.load(fis);

        // 方式二: 用classLoader去获取
        // 此方法默认为 当前module的src 文件的src 下
        Properties pros = new Properties();
        ClassLoader loader = ClassLoaderTest.class.getClassLoader();
        InputStream lis = loader.getResourceAsStream("jdbc1.properties");
        pros.load(lis);
        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        System.out.println("user: " + user + " password: " + password);
    }

创建类的对象:调用Class对象的newInstance()方法

package Reflection;

import org.junit.jupiter.api.Test;

/**
 *  通过反射机制创建对应的运行时类的对象
 *
 */
public class NewInstanceTest {

    @Test
    public void test1() throws IllegalAccessException, InstantiationException {

        Class clazz = Person.class;
        // newInstance(); 调用此方法创建对应的运行时类的对象。内部调用运行时类的空参类的构造器
        // 要想此方法正常的创建运行时类的构造器要求:
        // 1 运行时类必须提供空参构造器
        // 2 空参构造器权限得够

        /**
         * 在javabean中通常需要提供空参构造器
         * 1 便于通过反射,创建运行时类的对象
         * 2 便于子类继承此运行时类,默认使用调用super() 时,保证父类有此构造器
         */
        Person instance = (Person) clazz.newInstance();  // 调用的是person类空参的构造器
        System.out.println(instance);
    } 
}

调用运行时类中指定的结构:属性、方法、构造器

package Reflection;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 *  调用运行时类中指定的结构:属性、方法、构造器
 */
public class ReflectionFieldTest {

    @Test
    public void test1() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
        //开发中常用的,能设置私有的属性及方法
        Class personClass = Person.class;

        // 创建运行时类的对象
        Person p = (Person) personClass.newInstance();

        // 1 getDeclaredField(String filedName): 获取运行时类指定的变量名的属性
        Field name = personClass.getDeclaredField("name");

        // 2  保证当前的属性能访问
        name.setAccessible(true);
        // 3 设置指定对象的属性值
        name.set(p,"Jerry");

        System.out.println(name.get(p));
    }

    // 如何操作运行时类的指定的方法
    @Test
    public void test2() throws Exception {
        // 拿到运行时类的实例
        Class personClass = Person.class;

        // 创建运行时类的对象
        Person p = (Person) personClass.newInstance();

        // 1 获取指定的某个方法: getDeclaredMethod
        // 参数1: 指明获取的方法名  参数2: 指明方法的形参列表
        Method display = personClass.getDeclaredMethod("display", String.class);
        // 2 保证当前的方法是课访问的
        display.setAccessible(true);

        // 3 调用方法的invoke()
        // 参数1: 指明方法的调用者 参数2: 设置形参列表
        // invoke方法的返回值即为对应类中调用方法的返回值
        Object returnValue = display.invoke(p, "CHN");
        System.out.println(returnValue);

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

        // 调用静态的方法
        // private static void showDec()
        Method showDec = personClass.getDeclaredMethod("showDec");
        showDec.setAccessible(true);

        showDec.invoke(p);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值