【Java】深入理解反射机制

    xiaoxiao2022-07-14  125

    反射是非常重要的知识

    JAVA让我们运行时识别对象和类的信息,有俩个方式:一个是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息。另一种是反射机制,它允许我们运行时发现和使用类的信息。 –编程思想

    反射的描述

    JAVA反射机制是运行状态中,对于任意一个类,能够知道这个类的所有属性和方法,对于任意一个对象,能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用方法的功能称为java语言的反射机制。

    要想达到这样的效果,必须先要获取到该类的字节码文件对象,而达到这样效果使用的是Class类中的方法,所以先要获取到每个字节码文对应的Class类型对象。

    每个类都会产生一个对应的Class对象,且每个类只有一个,也就是保存在.class文件。所有类都是在对其第一次使用时,动态加载到JVM

    JAVA中反射的实现过程: JAVA语言在编译之后会产生成一个.class文件,反射就是通过字节码文件找到某一个类,类中的方法以及属性等。 下图2中,就是找到Class文件并创建Class对象(摘自网上) 下面是jdk到解释,说明反射就是把类中的各个成分反映为一个个对象

    Class类的类表示正在运行的Java应用程序中的类和接口。 枚举是一种类,一个注释是一种界面。 每个数组也属于一个反映为类对象的类,该对象由具有相同元素类型和维数的所有数组共享。 原始Java类型( boolean , byte , char , short , int , long , float和double ),和关键字void也表示为类对象。

    类没有公共构造函数。 相反, 类对象由Java虚拟机自动构建,因为加载了类,并且通过调用类加载器中的defineClass方法。

    我们不需要自己创建Class类,JVM自动帮我们创建好了。

    反射的作用

    JAVA反射的作用是什么: 反射机制指的是程序在运行时能够获取自身的信息。在JAVA中,只要给定类的名字,那么就可以通过反射机制来获取类的所有信息。

    获取Class对象的三种方式

    //1.java中每个类型都有class 属性** Class cls1 = String.class; Class cls2 = int.class; Class cls3 = Employee.class; (Employee是一个类) //2.通过class类的静态方法 Class.forName(ClassName) Class cls1 = Class.forName("Employee"); Class cls2 = Class.forName("java.lang.String"); //3.通过类的getClass()方法(Object的方法,因为所以方法都继承Object) Employee employee = new Employee(); Class cls = employee.getClass();

    反射的实现主要借助以下四个类:class:类的对象,Constructor:类的构造方法,field:类中的属性对象,Method类中的方法对象。

    通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问:

    通过反射获取构造方法并使用

    package fanshe; public class Student { //默认的构造方法 Student(String str){ System.out.println("默认的构造方法 s= "+str); } //无参数构造方法 public Student() { System.out.println("调用了公有,无参数构造方法执行了。。。"); } //有一个参数的构造方法 public Student(char name) { System.out.println("姓名:"+name); } //有多个参数的构造方法 public Student(String name,int age) { System.out.println("姓名:"+name+"年龄:"+age); } //受保护的构造方法 protected Student(boolean n) { System.out.println("受保护的构造方法 n = "+n); } //私有构造方法 private Student(int age) { System.out.println("私有的构造方法 年龄:"+age); } } package fanshe; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class Constructors { //加载class对象 public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //加载class对象 Class cls = Class.forName("fanshe.Student"); //Class cls = new Student().getClass(); //Class cls = Student.class; //获取所有公有的构造方法 System.out.println("**********************所有公有构造方法*********************************"); Constructor[] conArray = cls.getConstructors(); for(Constructor c:conArray) { System.out.println(c); } System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************"); conArray = cls.getDeclaredConstructors(); for(Constructor c : conArray){ System.out.println(c); } System.out.println("*****************获取公有、无参的构造方法*******************************"); Constructor con = cls.getConstructor(null); System.out.println("con = " + con); //创建此对象的一个新实例对象 Object obj = con.newInstance(); System.out.println("******************获取私有构造方法,并调用*******************************"); con = cls.getDeclaredConstructor(char.class); System.out.println(con); con.setAccessible(true); //用新实例对象的方法设置参数 obj = con.newInstance('男'); } }

    输出

    获取成员变量并调用

    package fanshe; public class Employee { public Employee() { } //***********字段****************** public String name; protected int age; char sex; private String phoneNum; @Override public String toString() { return "Employee [name=" + name + ", age=" + age + ", sex=" + sex + ", phoneNum=" + phoneNum + "]"; } } package fanshe; import java.lang.reflect.Field; public class Fields { public static void main(String[] args) throws Exception { //1.获取class对象 Class cls = Class.forName("fanshe.Employee"); //2.获取字段 System.out.println("***********获取所有公有字段************************"); Field []fieldArray = cls.getFields(); for(Field f: fieldArray) { System.out.println(f); } System.out.println("***********获取所有的字段(包括私有,受保护,默认的)*******"); fieldArray = cls.getDeclaredFields(); for(Field f: fieldArray) { System.out.println(f); } System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************"); fieldArray = cls.getDeclaredFields(); for(Field f : fieldArray){ System.out.println(f); } System.out.println("*************获取公有字段**并调用***********************************"); Field f = cls.getField("name"); System.out.println(f); //获取一个对象 Object obj = cls.getConstructor().newInstance();//产生Student对象--> Employee emp = new Employee(); //为字段设置值 f.set(obj, "刘德华"); //验证 Employee emp = (Employee)obj; System.out.println("验证姓名:" + emp.name); System.out.println("**************获取私有字段****并调用********************************"); f = cls.getDeclaredField("phoneNum"); System.out.println(f); f.setAccessible(true);//暴力反射,解除私有限定 f.set(obj, "18888889999"); System.out.println("验证电话:" + emp); } }

    获取成员方法并调用

    package fanshe; public class School { public void show1(String s){ System.out.println("调用了:公有的,String参数的show1(): s = " + s); } protected void show2(){ System.out.println("调用了:受保护的,无参的show2()"); } void show3(){ System.out.println("调用了:默认的,无参的show3()"); } private String show4(int age){ System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age); return "abcd"; } } package fanshe; import java.lang.reflect.Method; public class MethodClass { public static void main(String[] args) throws Exception { //1.获取Class对象 Class cls = Class.forName("fanshe.School"); //2.获取所有公有方法 System.out.println("***************获取所有的”公有“方法*******************"); cls.getMethods(); Method[] methodArray = cls.getMethods(); for(Method m : methodArray){ System.out.println(m); } System.out.println("***************获取所有的方法,包括私有的*******************"); methodArray = cls.getDeclaredMethods(); for(Method m : methodArray){ System.out.println(m); } System.out.println("***************获取公有的show1()方法*******************"); Method m = cls.getMethod("show1", String.class); System.out.println(m); //实例化一个Student对象 Object obj = cls.getConstructor().newInstance(); m.invoke(obj, "刘德华"); System.out.println("***************获取私有的show4()方法******************"); m = cls.getDeclaredMethod("show4", int.class); System.out.println(m); m.setAccessible(true);//解除私有限定 Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参 System.out.println("返回值:" + result); } }

    利用反射运行配置文件

    在src目录下建一个pro.txt配置文件,用来更新操作 pro.txt内容:

    ClassName=fanshe.Student1 MethodName=show

    package fanshe; public class Student1 { public void show() { System.out.println("is show"); } } package fanshe; import java.io.FileReader; import java.lang.reflect.Method; import java.util.Properties; public class Demo { public static void main(String[] args) throws Exception { //通过反射获取class对象 Class cls = Class.forName(getValue("ClassName")); //获取show方法 Method m = cls.getMethod(getValue("MethodName")); //调用show方法 m.invoke(cls.getConstructor().newInstance()); } private static String getValue(String key) throws Exception { Properties pro = new Properties();//获取文件配置对象 FileReader in = new FileReader("pro.txt"); pro.load(in); //将流加载到配置文件对象中 in.close(); return pro.getProperty(key); } }

    运行后

    is show

    当我们需要更改类时,创建一个新类Student2,然后只需要更改pro.txt的内容,就可以运行了。

    ClassName=fanshe.Student2 MethodName=show

    package fanshe; public class Student2 { public void show() { System.out.println("is show2"); } }

    其他不用改 输出:

    is show2

    以前写过的一些方法,那时理解很浅 点我

    最新回复(0)