java中反射真的是个很难搞的机制,对于一开始学习java的新人来说,反射到底是什么?这玩意能干嘛,真的是个头疼的事情。本人,一开始学反射的时候,或者说学习整个java的时候,都是一知半解。说实话,整个java很多基础知识都是零碎的,需要一根完整的线串在一起。
这里我将说明反射到底是个什么东西,在学习反射的时候,看了不少博文,但是国内大多数博文都和教科书一样枯燥且乏味,自己看的懂,别人看不懂。因此,我在本文最后给出几篇给我印象比较深的文章以供读者参考。
本文是我自己对反射的一个总结,部分结论难免晦涩,新人看完难免一知半解,可以等以后回来看。
1、反射
反射:
根据一个已经实例化了的对象来获取类的完整信息
java能够反射的前提:
jvm已经加载过这个类
Java反射机制提供的功能:
(1)首先需要明白,一个类在极限情况下都有哪些内容?
-
一个父类,多个接口
-
多个属性
-
多个构造方法,包括构造的参数与类型
-
多个普通方法,包括参数及其类型,返回值类型
(2)反射既然是通过某种方式获取类的完整信息。那么,它获取的信息再多也不会超过一个类的极限内容。因此,Java反射机制提供的功能:
-
在运行时判断任意一个对象所属的类
-
在运行时构造任意一个类的对象
-
在运行时判断任意一个类所具有的成员变量和方法
-
在运行时调用任意一个对象的成员变量和方法
-
生成动态代理
(3)反射相关的主要API:
-
java.lang.Class:代表一个类
-
java.lang.reflect.Method:代表类的方法
-
java.lang.reflect.Field:代表类的成员变量
-
java.lang.reflect.Constructor:代表类的构造方法
2、Class类
class类的简介
(1)一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作。这就是正射。
Apple apple = new Apple(); //直接初始化,「正射」
既然反射可以通过实例化对象来还原一个类的所有信息,那么,我们可以使用反射做到等号右边的实例化。但是,一个新的问题,我们应该用什么类来创建这个实例,即我们怎么实现等号左边? 这样一个类,必须要用高度抽象的方式来描述像String,Integer,Person,Student这样不同的类,甚至于这个类可以抽象地描述所有的类。这个类就是Class类。
(2)在Object类中定义了以下的方法,此方法将被所有子类继承:
public final Class getClass()
以上的方法返回值的类型是一个Class类。
(3)为什么不用Object类来对所有类进行描述,而是特别地创造一个Class类来抽象描述所有类?
个人认为,Object类只是所有类的父类,Object自身并不能对所有类进行描述。打个比方,现在有一个Student类,它继承于Object类,一定程度上,相当于Student类中有一块内容(方法或者属性)要划给Object类,但是很多其他的内容是Object类不具备的,也是Object类不能描述的。因此,Object不足以描述Student类。
(4)反射可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个Class对象包含了特定某个类的有关信息。
- Class本身也是一个类
- Class 对象只能由系统建立对象
- 一个类在 JVM 中只会有一个Class实例
- 一个Class对象对应的是一个加载到JVM中的一个.class文件
- 每个类的实例都会记得自己是由哪个 Class 实例所生成
- 通过Class可以完整地得到一个类中的完整结构
class类的常用方法

实例化Class类对象(四种方法)
• 前提:若已知具体的类,通过类的class属性获取,该方法最安全可靠,程序性能最高
Class clazz = String.class;
• 前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
Class clazz = “www.xyd.com”.getClass();
• 前提:已知一个类的全类名,且该类在类路径下,通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
Class clazz = Class.forName(“java.lang.String”);
• 其他方式(不做要求)
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(“类的全类名”);
//这个是以上实例化class类对象四种方法的代码
public class Test {
public static void main(String[] args) {
Person p = new Person();
Class clazz = p.getClass();//clazz对象中就包含对象p所属的Person类的所有的信息
//实例化Class类对象的方法
Class c0 = Person.class;//通过类名.class创建指定类的Class实例
Class c1 = p.getClass();//通过一个类的实例对象的getClass()方法,获取对应实例对象的类的Class实例
try {
//通过Class的静态方法forName(String className)来获取一个类的Class实例
//forName(String className)方法中的参数是你要获取的Class实例的类的全路径(包名.类名)
Class c2 = Class.forName("day14.Person");//这个是获取Class实例的常用方式
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
3、通过反射获取类的完整结构:接口、父类、构造器、方法、属性
1.实现的全部接口
public Class<?>[] getInterfaces()
确定此对象所表示的类或接口实现的接口
2.所继承的父类
public Class<? Super T> getSuperclass()
返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class
3.全部的构造器
public Constructor<T>[] getConstructors()
返回此 Class 对象所表示的类的所有public构造方法
public Constructor<T>[] getDeclaredConstructors()
返回此 Class 对象表示的类声明的所有构造方法
Constructor类中:
取得修饰符: public int getModifiers();
取得方法名称: public String getName();
取得参数的类型:public Class<?>[] getParameterTypes();
4.全部的方法
public Method[] getDeclaredMethods()
返回此Class对象所表示的类或接口的全部方法
public Method[] getMethods()
返回此Class对象所表示的类或接口的public的方法
Method类中:
取得全部的返回值:public Class<?> getReturnType()
取得全部的参数:public Class<?>[] getParameterTypes()
取得修饰符:public int getModifiers()
5.全部的属性
public Field[] getFields()
返回此Class对象所表示的类或接口的public的Field
public Field[] getDeclaredFields()
返回此Class对象所表示的类或接口的全部Field
Field方法中:
以整数形式返回此Field的修饰符:public int getModifiers()
得到Field的属性类型:public Class<?> getType()
返回Field的名称:public String getName()
6.类所在的包
Package getPackage()
获取类所在的包,可以使用getName()方法获取包名
4、通过反射调用类的完整结构
1、调用指定方法
通过反射,调用类中的方法,通过Method类完成。步骤:
(1)通过Class类的getMethod(String name,Class…parameterTypes) 方法取得一个Method对象, 并设置此方法操作时所需要的参数类型。
(2)使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。
对于Object invoke(Object obj, Object … args) 的说明:
1、Object 对应原方法的返回值,若原方法无返回值,此时返回null
2、若原方法若为静态方法,此时形参Object obj可为null
3、若原方法形参列表为空,则Object[] args为null
4、若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。
/**
* 通过反射调用类中的指定方法
*
* 注意:下面不论是反射调用setInfo还是test方法,都调用的obj对象的方法,obj对象实际上就是student对象
*/
Class clazz = Class.forName("day14.Student");//通过包名.类名的字符串,调用Class.forName方法获取指定类的Class实例
Constructor con = clazz.getConstructor();//获取无参构造
Object obj = con.newInstance();//使用无参构造创建对象,结果:调用的是public Student()
Method m = clazz.getMethod("setInfo", String.class, String.class);//获取名称叫setInfo,参数是String,String的方法
m.invoke(obj, "zhangsan","第一中学");//参数1是需要实例化的对象,后面的参数是调用当前的方法实际参数
//如果想要调用一个私有方法
Method m1 = clazz.getDeclaredMethod("test", String.class);//获取方法名为test,参数为1个String类型的方法
m1.setAccessible(true);//解除私有的封装,下面可以强制调用私有的方法
m1.invoke(obj, "李四");//结果:这是私有方法private void test(String name)
//调用一个重载方法
Method m2 = clazz.getMethod("setInfo", int.class);//setInfo的重载方法
m2.invoke(obj, 1);//结果:这个是public void setInfo(int age)方法
//有返回值的方法
Method m3 = clazz.getMethod("getSchool");//这是获取方法名为getSchool并且没有参数的方法
String school = (String)m3.invoke(obj);//调用有返回值的但是没有参数的方法
System.out.println(school);//结果:第一中学
2、调用指定属性(Field)
在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()和get()方法就可以完成设置和取得属性内容的操作。
public Field getField(String name)
返回此Class对象表示的类或接口的指定的public的Field。
public Field getDeclaredField(String name)
返回此Class对象表示的类或接口的指定的Field。
在属性中:
1、public Object get(Object obj) 取得指定对象obj上此Field的属性内容
2、public void set(Object obj, Object value) 设置指定对象obj上此Field的属性内容
注:在类中属性都设置为private的前提下,在使用set()和get()方法时,首先要使用Field类中的setAccessible(true)方法将需要操作的属性设置为可以被外部访问。
/**
* 通过反射调用类中的指定属性
*/
Class clazz = Class.forName("day14.Student");//通过包名.类名的字符串,调用Class.forName方法获取指定类的Class实例
//反射创建一个对象
Constructor con = clazz.getConstructor();
Student stu = (Student)con.newInstance();//结果:调用的是public Student()
Field f = clazz.getField("school");//获取名称为school的属性
f.set(stu, "第三中学");//对stu对象的school属性设置值"第三中学"
String school = (String)f.get(stu);//获取stu对象的school属性的值
System.out.println(school);//结果:第三中学
//如果是私有的属性
Field f1 = clazz.getDeclaredField("privateField");
f1.setAccessible(true);//解除私有的封装,下面就可以强制的调用这个属性
f1.set(stu, "测试私有属性");
System.out.println(f1.get(stu));//结果:测试私有属性
参考文献
1、深入理解Class类和Object类 cloud.tencent.com/developer/a…
2、Java中Class类与Object类之间有什么关系? blog.csdn.net/suyu_yuan/a…
3、Java Constructor类 www.51gjie.com/java/798.ht…
4、java中的反射总结(简洁易懂) www.cnblogs.com/nerxious/ar…