一、反射的概述
java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
二、获取class对象
要使用反射,我们首先获取这个类的class对象,获取class对象有三种方法:
1.类名.class;
Class stringClass = String.class;
2.类的对象名.getClass();
String s="";
Class stringClass1 = s.getClass();
3.Class.forName("类的全限定名");
Class stringClass2 = Class.forName("java.lang.String");
三、反射的使用
获取了class对象后,我们就可以使用class提供的各种方法来获取我们所需要的各种信息。
测试类
package com;
public class ReflectDemo {
public ReflectDemo(){
}
public ReflectDemo(String a){
}
private ReflectDemo(int message){
}
protected ReflectDemo(char c){
}
private static char c = 'q';
private int a = 10;
public String b = "我啊";
public static byte d = 1;
public long lo = 147L;
public void fun(){
System.out.println("fun");
}
private void demo(String mes){
System.out.println("私有方法"+mes);
}
protected String mad(){
return "ada";
}
private static void stafun(){
}
public static void pubfun(){
}
}
构造方法
----------------------------------------------------------------------------------------------------------------------------------
1. 获取共有的构造方法。
Class re = ReflectDemo.class;
Constructor a[] = re.getConstructors();
for (Constructor constructor : a) {
System.out.println(constructor);
}
2. 获取所有的构造方法。
Class re = ReflectDemo.class;
Constructor a[] = re.getDeclaredConstructors();
for (Constructor constructor : a) {
System.out.println(constructor);
}
3. 获取单个私有的构造方法。(可以获取私有、公有、保护、默认等所有的单个构造方法)
Class re = ReflectDemo.class;
Constructor a = re.getDeclaredConstructor(int.class);
System.out.println(a);
4. 获取单个公有的构造方法。
Class re = ReflectDemo.class;
Constructor a = re.getConstructor();
System.out.println(a);
实例字段
----------------------------------------------------------------------------------------------------------------------------------
1. 获取公共单个静态字段
Class re = ReflectDemo.class;
Field f = re.getField("d");
System.out.println(f.get(f));
2. 获取所有字段
Class re = ReflectDemo.class;
Field f[] = re.getDeclaredFields();
for (Field field : f) {
System.out.println(field);
}
3. 获取私有字段
Class re = ReflectDemo.class;
Field f = re.getDeclaredField("a");
System.out.println(f);
4. 获取所有公共字段
Class re = ReflectDemo.class;
Field f[] = re.getFields();
for (Field field : f) {
System.out.println(field);
}
获取方法
----------------------------------------------------------------------------------------------------------------------------------
1. 获取所有公共方法(包括继承的所有公共方法)
Class re = ReflectDemo.class;
Method m[] = re.getMethods();
for (Method method : m) {
System.out.println(method);
}
2. 获取所有方法(不包括继承的方法,只包含自己声明的方法)
Class re = ReflectDemo.class;
Method m[] = re.getDeclaredMethods();
for (Method method : m) {
System.out.println(method);
}
3. 获取单个公共方法(包含继承的公共方法)
Class re = ReflectDemo.class;
Method m = re.getMethod("wait");
System.out.println(m);
4. 获取单个方法(只有自己类,不包含继承)
Class re = ReflectDemo.class;
Method m = re.getDeclaredMethod("demo", String.class);
System.out.println(m);
总结上面的,反射可以获取一个类的所有属性和方法。
4.2. getDeclaredFields的实现
在JDK源码中,可以知道class.getDeclaredFields()
方法实际调用的是native方法getDeclaredFields0()
,它在JVM主要实现步骤如下
- 根据Class结构体信息,获取
field_count
与fields[]
字段,这个字段早已在load过程中被放入了 - 根据
field_count
的大小分配内存、创建数组 - 将数组进行forEach循环,通过
fields[]
中的信息依次创建Object对象 - 返回数组指针
主要慢在如下方面
- 创建、计算、分配数组对象
- 对字段进行循环赋值
4.3. Method.invoke的实现
以下为无同步、无异常的情况下调用的步骤
- 创建Frame
- 如果对象flag为native,交给native_handler进行处理
- 在frame中执行java代码
- 弹出Frame
- 返回执行结果的指针
主要慢在如下方面
- 需要完全执行ByteCode而缺少JIT等优化
- 检查参数非常多,这些本来可以在编译器或者加载时完成
4.4. class.newInstance的实现
- 检测权限、预分配空间大小等参数
- 创建Object对象,并分配空间
- 通过Method.invoke调用构造函数(
<init>()
) - 返回Object指针