之前在看springIOC的视频,里面设计到了很多反射的知识,我对反射一直停留在会用的阶段,借着这个机会好好学习一下Java的反射机制。
一. 反射基本概念
反射机制是指在程序运行期间对于任意一个类可以知道它的全部属性和方法,对于任意一个对象可以调用他的所有方法。这种 动态的获取信息 以及 动态调用对象的方法 的功能称为 java 的反射机制。
一般来说我们可以通过new一个对象来达到正向创建对象的目的,这样创建出来的对象类型是编译期可知的,而我们可以借助反射机制在运行期间通过Class动态创建对象,这样的对象往往在编译期间是不可知的。
Java 反射主要提供以下功能:
- 在运行时判断任意一个对象所属的类;(isInstance)
- 在运行时构造任意一个类的对象;(newInstance)
- 在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
- 在运行时调用任意一个对象的方法(invoke)
二. 反射的使用
Class类获取
提到反射的使用,就不得不提class类,class类是标示一个运行时类的具体信息,它由JVM在装载一个类的时候自动创建用于记录该类的相关信息并存放在虚拟机堆中。他的创建方式一共有三种
第一种,使用 Class.forName 静态方法。当你知道该类的全路径名时,你可以使用该方法获取 Class 类对象。
1 | Class clz = Class.forName("java.lang.String"); |
第二种是使用 类.class直接获取类的Class对象
1 | Class clz = String.class; |
第三种是通过对象的getClass()方法获取Class对象
1 | String str = new String("Hello"); |
这里第二种方式需要在编译期前就确定Class类,这与反射机制的编译时不可知,运行时可知的特点相矛盾,而第三种已经创建出类的实体,再利用getClass方法获取类对象,对于反射来说已经意义不大了,所以我们再利用反射的时候通常使用第一种方式,通过全类名的方式获取class类,也符合编译器不可知的特点。
获取对象实例
通过反射创建类对象主要有两种方式:通过 Class 对象的 newInstance() 方法、通过 Constructor 对象的 newInstance() 方法。
第一种:通过 Class 对象的 newInstance() 方法。
1 | Class clz = Class.forName("java.lang.String"); |
这种方式只适用于适用无参的构造函数,有参数的无法使用。
第二种:通过 Constructor 对象的 newInstance() 方法
1 | Class clz = Class.forName("java.lang.String"); |
通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法。
获取类属性、方法
属性的获得一共有两种getField()和getDeclaredField()
第一种getField()
1 | Class<?> bookclz = Class.forName("com.mjj.book.Book"); |
这种方式可以获取类内以public方式声明的属性以及继承的public的属性,对于private和默认声明的属性无法获取。
第二种getDeclaredField()
1 | Class<?> bookclz = Class.forName("com.mjj.book.Book"); |
这种属性的获取方式可以获取到本类private属性的值,但是当我们在使用这样私有属性的时候,我们需要设置setAccessible(true);才可以正确使用。
方法获取的方式一样都有两种分别是
1 | //getDeclaredMethods 方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 |