反射简介
反射是Java的高级特性之一,但是在实际的开发中,使用Java反射的案例却非常的少,但是反射确实在底层框架中被频繁的使用。
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
比如:JDBC中的加载数据库驱动程序,Spring框架中加载bean对象,动以及态代理,这些都使用到反射,因为我们要想理解一些框架的底层原理,反射是我们必须要掌握的。
理解反射我们先从他的概念入手,那么什么是反射呢?
反射就是在运行状态能够动态的获取该类的属性和方法,并且能够任意的使用该类的属性和方法,这种动态获取类信息以及动态的调用对象的方法的功能就是反射。
实现上面操作的前提是能够获取到该类的字节码对象,也就是.class文件,在反射中获取class文件的方式有三种:
- 类名.class 如:Person.class
- 对象.getClass 如:person.getClass
- Class.forName(全类名)获取 如:Class.forName("com.nowjava.service")
用途
在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。当然,也不是所有的都适合反射,之前就遇到一个案例,通过反射得到的结果与预期不符。阅读源码发现,经过层层调用后在最终返回结果的地方对应用的权限进行了校验,对于没有权限的应用返回值是没有意义的缺省值,否则返回实际值起到保护用户的隐私目的。
反射的实际场景的应用,这里主要列举这几个方面:
- 动态代理
- JDBC 的数据库的连接
- Spring 框架的使用
Class对象
对于反射的执行过程的原理,我这里画了一张图,以供大家参考理解。

我们看过JVM的相关书籍都会详细的了解到,Java文件首先要通过编译器编译,编译成Class文件,然后通过类加载器(ClassLoader)将class文件加载到JVM中。
在JVM中Class文件都与一个Class对象对应,在因为Class对象中包含着该类的类信息,只要获取到Class对象便可以操作该类对象的属性与方法。
在这里深入理解反射之前先来深入的理解Class对象,它包含了类的相关信息。
Java中我们在运行时识别对象和类的信息,也叫做RTTI,方式主要有来两种:
- 传统的RTTI(Run-Time Type Information)
- 反射机制
应用实例
public class User{ private String name; private Integer age; public User() { } public User(String name, Integer age) { = name; this.age = age; } private void privateMethod(){ System.err.println("privateMethod"); } public void publicMethod(String param){ System.err.println("publicMethod"+param); } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; }}Class clazz=User.class;//获取有参构造Constructor constructor = clazz.getConstructor(String.class, Integer.class);//获取该类对象并设置属性的值Object obj = constructor.newInstance("时代Java", 18);//获得类全类名,既包含包路径String fullClassName = clazz.getName();//获得类名String className = clazz.getSimpleName();//获得类中公共类型(public)属性Field[] fields = clazz.getFields();String fieldName="";for(Field field : fields){ // 获取属性名 fieldName=field.getName(); System.out.println(fieldName)}//获得类中全部类型属性(包括private)Field[] fieldsAll = clazz.getDeclaredFields();fieldName="";for(Field field : fieldsAll){ // 获取属性名 fieldName=field.getName(); System.out.println(fieldName)}//获得指定公共属性值Field age = clazz.getField("age");Object value = age.get(obj);System.err.println("公共指定属性:"+value);//获得指定的私有属性值Field name = clazz.getDeclaredField("name");//设置为true才能获取私有属性name.setAccessible(true);Object value2= name.get(obj);System.err.println("私有指定属性值:"+value2);//获取所有公共类型方法 这里包括 Object 类的一些方法Method[] methods = clazz.getMethods();String methodsName="";for(Method method : methods){ methodsName=method.getName();}//获取该类中的所有方法(包括private)Method[] methodsAll = clazz.getDeclaredMethods();methodsName="";for(Method method : methodsAll){ methodsName=method.getName();}//获取并使用指定方法Method privateMethod= clazz.getDeclaredMethod("privateMethod");//获取无参私有方法privateMethod.setAccessible(true);privateMethod.invoke(obj);//调用方法Method publicMethod= clazz.getMethod("publicMethod",String.class);//获取有参数方法publicMethod.invoke(obj,"时代Java");//调用有参方法反射优点
反射可以动态的获取对象,调用对象的方法和属性,并不是写死的,比较灵活,比如你要实例化一个bean对象,你可能会使用new User()写死在代码中。
但是使用反射就可以使用class.forName(user).newInstance(),而变量名user可以写在xml配置文件中,这样就不用修改源代码,灵活、可配置。
反射缺点
没有任何一项技术是十全十美的,Java反射拥有强大功能的同时也带来了一些副作用。
- 性能开销
反射涉及类型动态解析,所以JVM无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。 - 安全限制
使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如Applet,那么这就是个问题了。 - 内部曝光
由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
















