> 文档中心 > 原来Java反射这么简单!!!

原来Java反射这么简单!!!


反射,是框架设计的灵魂。反射机制在框架设计中举足轻重,现在市面上绝大部分框架基本上都有使用Java的反射机制。例如加载数据库驱动的,用到的也是反射。Class.forName("com.mysql.jdbc.Driver");

反射机制,是Java进阶必不可少的知识。

反射机制

概念

在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。也就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。

反射就是把Java类中的各种成分映射成一个个的Java对象。

例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。

如图是类的正常加载过程:反射的原理在与class对象。

作用

  1. 可以在程序的运行过程中,动态操作这些对象

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

常用类


Java.lang.Class;

Java.lang.reflect.Constructor;

Java.lang.reflect.Field;

Java.lang.reflect.Method;

Java.lang.reflect.Modifier;

类加载机制

ClassLoader用来加载Class文件到JVM,以供程序使用的。Java程序可以动态加载类定义,而这个动态加载的机制就是通过ClassLoader来实现的。

      类加载器虽然只用于实现类的加载动作,但它在Java程序中起到的作用却远远不限于类加载阶段。对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类,都拥有一个独立的类名称空间。这句话可以表达得更通俗一些:比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义。否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。

ClassLoader介绍

1)启动类加载器/Bootstrap ClassLoader:前面已经介绍过,这个类加载器负责将存放在<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机内存中。启动类加载器无法被Java程序直接引用。

2)扩展类加载器/Extension ClassLoader:这个加载器由sun.misc.Launcher.ExtClassLoader实现,它负责加载<JAVA_HOME>\lib\ext目录中的类,开发者可以直接使用扩展类加载器。

3)应用程序类加载器/Application ClassLoader:这个类加载器由sun.misc.Launcher.AppClassLoader实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称它为系统类加载器。它负责加载用户类路径(Class Path)上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

举了例子验证一下吧


package reflectionDemo;public class ClassLoaderTest {    public static void main(String[] args) { ClassLoader loader = Thread.currentThread().getContextClassLoader(); System.out.println("current loader:      "+loader); System.out.println("parent loader:"+loader.getParent());    }}

控制台输出


current loader: sun.misc.Launcher$AppClassLoader@18b4aac2parent loader:  sun.misc.Launcher$ExtClassLoader@61bbe9ba

Java程序代码在计算机中运行经历的三个阶段:

反射实践

获取class信息

  1. Object.getClass()

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

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

Student类

package reflectionDemo;import lombok.*;@Datapublic class Student {    protected Integer age;    public String name;    private String Phone;    public String showName(String name){ System.out.println(name); return name;    }    protected void showAge(){ System.out.println("age");    }    private String showPhone(String Phone){ System.out.println("Phone"); return Phone;    }}

Demo:

package reflectionDemo;public class ReflectionDemo {    public static void main(String[] args) { //第一种方式获取Class对象;这一new 产生一个Student对象,一个Class对象。 Student stu1 = new Student(); Class stuClass = stu1.getClass();//获取Class对象 System.out.println(stuClass.getName()); //第二种方式获取Class对象 Class stuClass2 = Student.class; System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个 //第三种方式获取Class对象 try {     Class stuClass3 = Class.forName("reflectionDemo.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名     System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象 } catch (ClassNotFoundException e) {     e.printStackTrace(); }    }}

控制台输出

获取成员变量并调用


package reflectionDemo;import java.lang.reflect.Field;/* * 获取成员变量并调用: * * 1.批量的 * 1).Field[] getFields():获取所有的"公有字段" * 2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有; * 2.获取单个的: * 1).public Field getField(String fieldName):获取某个"公有的"字段; * 2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的) * *      设置字段的值: * Field --> public void set(Object obj,Object value): *   参数说明: *   1.obj:要设置的字段所在的对象; *   2.value:要为字段设置的值; */public class Demo_two {    public static void main(String[] args) throws Exception { //1.获取Class对象 Class stuClass = Class.forName("reflectionDemo.Student"); //2.获取字段 System.out.println("************获取所有公有的字段********************"); Field[] fieldArray = stuClass.getFields(); for(Field f : fieldArray){     System.out.println(f); } System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************"); fieldArray = stuClass.getDeclaredFields(); for(Field f : fieldArray){     System.out.println(f); } System.out.println("*************获取公有字段**并调用***********************************"); Field f = stuClass.getField("name"); System.out.println(f); //获取一个对象 //生成Student对象--> 等价Student stu = new Student(); Object obj = stuClass.getConstructor().newInstance(); //为字段设置值 f.set(obj, "软件质量保障"); //为Student对象中的name属性赋值--》stu.name = "软件质量保障" //验证 Student stu = (Student)obj; System.out.println("验证姓名:" + stu.name); System.out.println("**************获取私有字段****并调用********************************"); f = stuClass.getDeclaredField("Phone"); System.out.println(f); f.setAccessible(true);//解除私有限定 f.set(obj, "13240738783"); System.out.println("验证电话:" + stu);    }}

控制台输出:

获取成员方法并调用

package reflectionDemo;import java.lang.reflect.Method;/* * 获取成员方法并调用: * * 1.批量的: * public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类) * public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的) * 2.获取单个的: * public Method getMethod(String name,Class... parameterTypes): *   参数: *      name : 方法名; *      Class ... : 形参的Class类型对象 * public Method getDeclaredMethod(String name,Class... parameterTypes) * *      调用方法: * Method --> public Object invoke(Object obj,Object... args): *   参数说明: *   obj : 要调用方法的对象; *   args:调用方式时所传递的实参;): */public class Demo_three {    public static void main(String[] args) throws Exception { //1.获取Class对象 Class stuClass = Class.forName("reflectionDemo.Student"); //2.获取所有公有方法 System.out.println("***************获取所有的”公有“方法*******************"); stuClass.getMethods(); Method[] methodArray = stuClass.getMethods(); for(Method m : methodArray){     System.out.println(m); } System.out.println("***************获取所有的方法,包括私有的*******************"); methodArray = stuClass.getDeclaredMethods(); for(Method m : methodArray){     System.out.println(m); } System.out.println("***************获取公有的showPhone()方法*******************"); Method m = stuClass.getMethod("showName", String.class); System.out.println(m); //实例化一个Student对象 Object obj = stuClass.getConstructor().newInstance(); m.invoke(obj, "软件质量保障");  // 入参 System.out.println("***************获取私有的showName()方法******************"); m = stuClass.getDeclaredMethod("showPhone", String.class); System.out.println(m); m.setAccessible(true);//解除私有限定 Object result = m.invoke(obj, "13240282821");//需要两个参数,一个是要调用的对象(获取有反射),一个是实参 System.out.println("返回值:" + result);    }

控制台输出:


***************获取所有的”公有“方法*******************public boolean reflectionDemo.Student.equals(java.lang.Object)public java.lang.String reflectionDemo.Student.toString()public int reflectionDemo.Student.hashCode()public java.lang.String reflectionDemo.Student.getName()public void reflectionDemo.Student.setName(java.lang.String)public java.lang.String reflectionDemo.Student.showName(java.lang.String)public java.lang.Integer reflectionDemo.Student.getAge()public java.lang.String reflectionDemo.Student.getPhone()public void reflectionDemo.Student.setAge(java.lang.Integer)public void reflectionDemo.Student.setPhone(java.lang.String)public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedExceptionpublic final native void java.lang.Object.wait(long) throws java.lang.InterruptedExceptionpublic final void java.lang.Object.wait() throws java.lang.InterruptedExceptionpublic final native java.lang.Class java.lang.Object.getClass()public final native void java.lang.Object.notify()public final native void java.lang.Object.notifyAll()***************获取所有的方法,包括私有的*******************public boolean reflectionDemo.Student.equals(java.lang.Object)public java.lang.String reflectionDemo.Student.toString()public int reflectionDemo.Student.hashCode()public java.lang.String reflectionDemo.Student.getName()public void reflectionDemo.Student.setName(java.lang.String)public java.lang.String reflectionDemo.Student.showName(java.lang.String)private java.lang.String reflectionDemo.Student.showPhone(java.lang.String)protected void reflectionDemo.Student.showAge()public java.lang.Integer reflectionDemo.Student.getAge()public java.lang.String reflectionDemo.Student.getPhone()public void reflectionDemo.Student.setAge(java.lang.Integer)public void reflectionDemo.Student.setPhone(java.lang.String)protected boolean reflectionDemo.Student.canEqual(java.lang.Object)***************获取公有的showPhone()方法*******************public java.lang.String reflectionDemo.Student.showName(java.lang.String)软件质量保障***************获取私有的showName()方法******************private java.lang.String reflectionDemo.Student.showPhone(java.lang.String)Phone返回值:13240282821

附录:

解读ClassLoade