什么是反射?反射是Java编程语言的特性之一,它允许动态发现和绑定类、方法、字段和所有其他结果元素。通过反射,可以在需要的时候完成创建实例、调用方法、访问字段的工作。反射机制主要提供运行时判断任意对象的类的功能,运行时构造任意类的对象,运行时判断任意类的成员变量和方法,运行时调用任意对象的方法,通过反射您甚至可以调用私有修改方法来生成动态代理。Reflection在牛逼框架中使用了Spring框架的IOC,基于反射创建对象和设置依赖属性。SpringMVC的request调用相应的方法,也是通过反射。JDBC的Class#forName(StringclassName)方法也使用了反射。反思一下,Class.forName和ClassLoader有什么区别?两者都可以用来加载类。不同的是:Class#forName(…)方法除了将类的.class文件加载到JVM中外,还会解释类并执行类中的静态块。ClassLoader只做一件事,就是将.class文件加载到JVM中,并不会执行static中的内容。只有在newInstance中才会执行静态块。反射的常用类Java中大部分与反射相关的类都在rt.jar下的java.lang.reflect中。其实需要的课并不多。主要有以下几种:java.lang.ClassClass实例表示它运行的是Java类和接口。java.lang.reflect.Field提供有关类或接口的属性信息,以及对其的动态访问。反射字段可以是类(静态)属性或实例属性。简单理解可以认为是一个类,封装了反射类的属性。有点绕,慢慢看吧。java.lang.reflect.Constructor提供有关类的单个构造函数的信息和访问权限。这个类不同于Field类。Field类封装了反射类的属性,而Constructor类封装了反射类的构造方法。java.lang.reflect.Method提供有关类和接口上各个方法的信息。被反射的方法可以是类方法,也可以是实例方法(包括抽象方法)。这个类不难理解,它的作用就是封装了一类反射类的方法。java.lang.reflect.Modifier提供用于解码类和成员访问修饰符的静态方法和常量。一组修饰符表示为一个整数,不同的位位置代表不同的修饰符。java.lang.reflect.Array提供了动态创建和访问数组的静态方法。此类中的所有方法都是静态方法。反射的优点和缺点优点这些对象可以在程序运行时被操作。可以解耦,提高程序的可扩展性。缺点因为是JVM运行,性能会有下降。很容易对程序源代码造成一些混乱。探索Classjava文件被编译成class文件,class文件被类加载器加载到内存中,JVM根据它们的字节数组创建对应的Class对象。Class类是Java反射的起源。对于我们要使用的任何一个类,首先只为它生成一个Class对象,然后通过Class对象获取其他信息即可。JVM为每个类管理一个唯一的类对象。当我们需要为每个类创建一个对象时,JVM会检查要加载的类对应的Class对象是否已经存在。如果不存在,JVM会根据类加载机制加载创建对应的Class对象,最后使用Class对象创建我们平时使用的实例对象。获取Class类的三种方法1、调用Object类的getClass()方法获取Class对象。2.使用Class类的forName("com.tian.XXX")静态方法获取字符串对应的对象(类或接口的全限定名)。3、使用.class获取本类的Class对象。Class有很多常用的方法。获取类信息了解了Java反射的细节之后,我们就可以使用反射机制来获取类中的信息了。创建对象使用无参数构造函数创建对象。例如下面的代码:Classclazz=Class.forName("java.lang.String");Stringstr=(String)clazz.newInstance();这里注意这个类必须是没有参数的构造方法,否则这个方法会报错。使用参数化构造方法可以分三步完成:1.获取指定类对应的Class对象2.通过Class对象获取满足指定参数类型要求的构造器类对象3.调用对应的newInstance方法给指定的Constructor,通过回车对应的参数值来创建我们想要的实例对象。Classclazz=Class.forName("java.lang.String");Constructorconstructor=clas.getConstructor(String.class);Stringstr=(String)constructor.newInstance("helloworld");这将创建一个String对象实例。调用Method我们之前讲过Method类,我们可以通过Method类中的invoke方法来动态调用方法。publicfinalclassMethodextendsExecutable{publicObjectinvoke(Objectobj,Object...args){//...}}该方法的第一个参数是一个对象类型,表示要在指定的对象上调用该方法(方法名)。第二个参数是一个可变参数,用来给这个方法传递参数值;invoke方法中返回的值用于表示动态调用指定方法后的返回值。如果调用私有方法,首先调用setAccessible(true)实现Java语言堆方法的访问检查,然后调用invoke方法真正执行私有方法。访问成员变量的值使用反射获取类的成员变量的对象代表。成员变量的对象代表是java.lang.reflect.Field类的一个实例。您可以使用它的getXyy()方法获取指定对象上的值。也可以使用setXyy()方法动态修改指定对象上的值,其中xyy为成员变量。例如:setAge(22);其中年龄是成员变量。数组操作也是一项,可以通过反射查看数组的各个属性的信息,比如ingt[]intArr=newInt[10];Sysytem.out.prinlt("Arraytype:"+intArr.getClass.getComponentType().getName());Objectobj=Array.newInstance(int.class,10);//维数数组赋值for(inti=0;i<10;i++){Array.setInt(obj,i,i);}for(inti=0;i<10;i++){System.out.print("第一个"+i+"好的元素是"+Array.getInt(obj,i));}反射和动态代理代理方式是在Java中最常用的设计模式之一,尤其是在Spring、Mybatis、Dubbo等框架中,其中一个应用就是反射。静态代理模式就不用说了。相当于一个业务需要一个代理,你要为它创建一个代理类。全部手动完成。动态代理的原理是在程序运行时根据需要动态创建目标类的代理对象。典型应用场景:JDK动态代理CGlib动态代理关于动态代理,后面会有专门的文章分析。我们与反思相关的评论到此结束。具体来说,建议往下手动敲代码体验一下,加深理解。总结面试问的时候,建议回答以下几个方面:1.什么是反射2.提供什么功能3.常用的类有哪些4.有什么优缺点5.其他框架中文应用(动态代理)本文转载自微信公众号《Java后端技术全栈》,可通过以下二维码关注。转载本文请联系Java后端技术全栈公众号。
