反射:基于Class类信息及java.lang.reflect包提供的类对运行时字节码(.class文件)进行字段操作、对象创建、方法调用等进行动态操作。
反射的基石:Class类信息
当类的class字节码加载到JVM内存时,会在内存的方法区保存类的基本信息(包括类名,方法,字段,接口,父类等信息),并会在堆中创建类的唯一Class实例对象,方法区保存对该对象的引用。
通过三种方式可以获取Class对象的引用:
以java.lang.String类为例
1,Class clazz1 = String.class;
2,Class clazz2 = Class.forName("java.lang.String");
3,Class clazz3= new String("abc").getClass();
其中clazz1 ==clazz2 返回true,clazz1 ==clazz3返回true,引用指向唯一对象。
java.lang.reflect包
反射构造函数
//获取String构造函数参数为StringBuffer的构造器
Constructor<String> c= String.class.getConstructor(StringBuffer.class)
//调用构造方法,创建String对象
String s = c.newInstance(new StringBuffer("abc"));
以上是有参构造方法创建对象的过程(无参构造方法创建对象也可以这样创建),另外还有一种无参构造方法创建对象的简单方式:
String s = String.class.newInstance();//通过class对象的newIntance方法创建无参的String对象
反射字段
class Person{
public String name = "master";
private int age = 22;
}
通过反射读取Person对象成员变量的值:
Person p = new Person();
Field nameField = p.getClass().getField("name");
String name =(String) nameField .get(p);//通过get方法获取p对象中的name字段
Field ageField = p.getClass().getDeclaredField("age");//age字段被private修饰,必须通过getDeclaredField方法获取
ageField.setAccessible(true);//设置private字段可访问
int age = ageField .getInt(p);//对基本数据类型使用对应的get方法获取字段的值
反射方法
String str = "abcd";
//反射String的charAt(int index)方法
Method meh = str.getClass().getMethod("charAt", int.class);char ch = (char)meh.invoke(str, 3);//返回字符d,其中str为调用方法的对象,3为传入方法的参数
反射数组
int[] arr = new int[]{1,2,3};
int[]表示一个数组对象,类型及纬度相同的数组为同一Class对象:
int[][] a1 = new int[2][3];
int[][] a2 = new int[3][4];
int[] a3 = new int[3];
String[] a4 = new String[4];
a1.getClass()==a2.getClass(),返回true
a1.getClass()==a3.getClass(),编译失败
a3.getClass()==a4.getClass();编译失败
数组和Object:
通过java.lang.reflect.Array
boolean b = a3.getClass().isArray();//返回true
int len = Array.getLenth(a3);//返回3
Object obj = Array.get(a3,1 );//返回a3数组中角标为1的元素对象