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);
}
}