java反射 映射_原来Java反射这么简单!

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

反射机制

概念

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

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

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

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

4977593c7f6cd2bbca588972a3bd20fb.png

作用

可以在程序的运行过程中,动态操作这些对象可以解耦,提高程序的可扩展性

常用类

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)上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

9956b6c932d80e799309eb39821e1ec2.png

举了例子验证一下吧

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程序代码在计算机中运行经历的三个阶段:

104379de33ff5e9f5056e2f80a51d2eb.png

反射实践

获取class信息

Object.getClass()类名.class:通过类名的属性class获取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(); } }}

控制台输出

b0fc35dc51b87f7cdf602472d9ff7350.png

获取成员变量并调用

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

控制台输出:

379b73dcc30a897cf3c6ab41086b3298.png

获取成员方法并调用

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

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源包含源代码 易看易懂 其实就是一发射机制 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。其中LEAD/LEAD++ 、OpenC++ 、MetaXa和OpenJava等就是基于反射机制的语言。最近,反射机制也被应用到了视窗系统、操作系统和文件系统中。 反射本身并不是一个新概念,它可能会使我们联想到光学中的反射概念,尽管计算机科学赋予了反射概念新的含义,但是,从现象上来说,它们确实有某些相通之处,这些有助于我们的理解。在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。可以看出,同一般的反射概念相比,计算机科学领域的反射不单单指反射本身,还包括对反射结果所采取的措施。所有采用反射机制的系统(即反射系统)都希望使系统的实现更开放。可以说,实现了反射机制的系统都具有开放性,但具有开放性的系统并不一定采用了反射机制,开放性是反射系统的必要条件。一般来说,反射系统除了满足开放性条件外还必须满足原因连接(Causally-connected)。所谓原因连接是指对反射系统自描述的改变能够立即反映到系统底层的实际状态和行为上的情况,反之亦然。开放性和原因连接是反射系统的两大基本要素。13700863760 Java中,反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接。反射允许我们在编写与执行时,使我们的程序代码能够接入装载到JVM中的类的内部信息,而不是源代码中选定的类协作的代码。这使反射成为构建灵活的应用的主要工具。但需注意的是:如果使用不当,反射的成本很高。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值