1:反射的作用
笼统的来说,反射可以让Java程序在运行阶段对类进行操作。
在说这个问题前我们需要了解一下Java程序运行的过程。
编译源码->编译->class文件
这个过程是我们所熟悉的,可是class文件并不只是能够直接运行的。
class->装载->获得原信息
随后class会由类加载器装载,然后在JVM中将形成一份描述class结构的原信息对象。
通过原信息对象可以获知Class文件的结构信息,如构造函数,属性方法等。
之后的过程发生在虚拟机里
加载->链接->校验->转换->解析->初始化
之后虚拟机把原信息对象加载到内存,并对数据进行校验、转换、解析和初始化、最终形成可以被虚拟机直接使用的Java类型。
而类的初始化的时机大概有下面几个:
1:使用new关键字实例化对象的时候,读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。
2:当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
当虚拟机启动是,用户需要指定一个要执行的主类(包含main()方法的那个类)虚拟机会先初始化这个主类。
3:使用java.lang.reflect包方法对类进行反射调用的时候,如果类没有进行过初始化则需要先触发其初始化。
也就是说在类的初始化的过程中会执行反射调用,而这个过程在编译之后发生!
接下来是实现细节:
Java提供了一个javaBean规范来用于反射:
javaBean的规范为
1:必须提供私有字段
2:必须提供get和set方法
3:必须提供无参构造
4:必须实现序列化接口java.io.Serializable
但是使用反射往往要经历以下几个步骤:
1:获得对象
2:获得构造对象
3:获得实例
一:获得class对象
我们可以通过三种不同的方法来获得class对象:
方式:
- 1:通过字符串(全限定类名)获得
-
格式:Class clazz=Class.forName(String)
-
全限定类名:包名+类名
- 2:通过Java类型获得
-
格式: Class clazz=类型.class;
- 3:通过实例对象(变量名)获得
-
格式:Class clazz=obj.getClass()
此处假设我们已经通过三种方法之一获得了class对象;
2:获得构造对象
2.1:获得公有构造对象,并调用
使用getConstructor()获得单个构造对象(若无参则()内不填任何东西若有参则如下)
-
Constructor constroctor=clazz.getConstructor(String.class,...);
2.2:获得私有构造对象
1:获得指定形参的私有构造
使用getDeclaredConstructor()获得单个构造对象(无参情况同上)
-
Constructor constructor=clazz.getDeclaredConstructor(String.class,...);
2:通知JVM虚拟机允许实例化的私有构造(默认是不允许的)
constructor.setAccessible(true);
默认已获得构造 constructor
3:获得实例
获得实例并传入参数。
-
Object object=constructor.newInstance("111");
二:获取成员变量并使用
关键字:
(1)Field[] getFields() ;获取所有的“公有字段
(2)Field[] getDeclaredFileds();获取所有字段,包括私有、默认、受保护、公有
(3)public Field getField(String fieldName);获取某个公有字段
(4)public Filed geDeclaredtField(String fieldName);;获取某个字段,包括私有、默认、受保护、公有
具体操作与获得构造方法的方式相同,不再详述。
三:获取成员方法并使用
(1)Method[] getMethods;获得所有“公有成员方法”
(2)Method[] getDeclaredMetod;获取所有的成员方法,获取所有字段,包括私有、默认、受保护、公有
(3)Method getMethod(String name,Class<?>… parameterTypes)获取某个公有成员方法
参数:
name : 方法名;
Class … : 形参的 Class 类型对象
(4)Method getDeclaredMethod(String name,Class<?>… parameterTypes);获取某个方法,包括私有、默认、受保护、公有
看到这里,相信前面关于构造函数的几个方法,大家也能猜出来了,可以测试下自己猜的是否正确。了解下java的命名规则,就可以通过命名来大致的了解该方法的功用了。
此外还可以通过set来获取字段的值,通过invoke来调用成员方法。这位博主在这方面说的非常详细就不再复述
https://blog.csdn.net/lwl20140904/article/details/80163880