__________反射机制__________
反射的基石:Class类
概述
反射就是把Java类中的各种成分映射成相应的Java类。
Java程序中所有的类也是一类事物,Class类就是用于描述Java类的。Method类就是用于描述Java类中方法的。所有类在加载进去内存时都会生成一段唯一的字节码,创建对象的实例就是复制这份字节码生成新的对象。
Class对象为内存当中的一份字节码。在Java虚拟机启动的时候会预先加载8个预定义的Class实例对象(字节码):8个基本数据类型和关键字void。包装类型的TYPE就是基本数据类型的字节码获取字节码的方式
1、通过类名获得
String.class
2、通过类的对象获取
String str = "s";s.getClass();
3、通过Class类加载类文件,并返回这份字节码
Class.forName(java.lang.String);Constructor类
得到某个类所有的构造方法:
Constructor[] cons = Class.forName(java.lang.String).getConstructors();
得到某个类的某个构造方法:
//依靠参数类型,如获取String(StringBuilder builder):
Constructor con = Class.forName(java.lang.String).getConstructor(StringBuilder.class);
通过反射创建一个对象:
1.通过Class对象获取Constructor对象,调用对象的newInstance方法创建Constructor con = String.class.getConstructor(StringBuilder.class);
String str = (String)con.newInstance(new StringBuilder("abc"));
2.通过Class对象的newInstance:
/*
创建时调用的是无参数构造方法对象的newInstance方法。
此方法第一次调用后会将不带参数的构造方法Constructor对象缓存起来方便下次使用。
*/
String.class.newInstance();
Field类
概述:
用于描述类中成员变量的类。
简单操作演示:
public class Demo {
public static void main(String[] args) throws Exception {
ReflectPoint rp = new ReflectPoint(1,2);
//此方法只能得到可见的成员变量
Field fieldY = rp.getClass().getField("y");
System.out.println(fieldY.get(rp));
/**
* 注意这里能取得结果的原因是y是public变量
* 对于x为private,getField只能取得可访问的变量,getDeclaredField可取的不可见的变量
* 对于不可访问变量的值调用get时会抛异常,当然也可以这样取得(不推荐)-->取消访问检查
*/
Field fieldX = rp.getClass().getDeclaredField("x");
//取消Java语言访问检查
fieldX.setAccessible(true);
System.out.println(fieldX.get(rp));
//修改rp对象成员变量x的值
fieldX.set(rp, 3);
System.out.println(fieldX.get(rp));
}
}
class ReflectPoint {
private int x;
public int y;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
Method类
概述:
用于描述类中方法的类。
简单操作演示:
public static void main(String[] args) throws Exception {
String str = "abc";
Method methodCharAt = String.class.getMethod("charAt", int.class);
//当方法为静态方法时,传入对象为null就可以了
char c = (char) methodCharAt.invoke(str, 1);
/*
* JDK1.5版本以前的invoke方法传递的参数是对象+Object[]数组
* JDK1.5以后将数组替换成了可变参数,但是为了兼容老版本,所以兼容了数组的方式
* 所以当传入一个数组参数的时候,会被拆才当成多个参数,对此有两个解决方案,我们以foo方法为例
*/
Method method = Demo.class.getMethod("foo", String[].class);
//此方法传入的数组会被拆分成两个参数,报错
//method.invoke(null, new String[]{"cc","dd"});
//下面两种方式都可以:1.使用的是老版本的方法。2,使用的是新版的可变参数方法
method.invoke(null, new Object[]{new String[]{"cc","dd"}});
method.invoke(null, (Object)new String[]{"aa","bb"});
}
public static void foo(String[] args){
for(String s : args)
System.out.println(s);
}
Array类
概述:
Array 类提供了动态创建和访问 Java 数组的方法。
简单操作演示:
//打印方法,如果是数组就打印数组中的元素
//支持基本数据类型数组
public static void printObject(Object obj) {
Class clazz = obj.getClass();
if(clazz.isArray()) {
//Array类可以直接获取数组对象的长度
int len = Array.getLength(obj);
for(int i=0; i<len; i++) {
//通过Array可以直接获取数组元素
System.out.println(Array.get(obj, i));
}
} else
System.out.println(obj);
}
反射实现框架原理
概述:
框架与工具类不一样,框架就是调用用户提供的类,工具类是被用户类调用。前者在编译的时候是不知道用户会提供什么类的,后者却清楚。
原理:
从配置文件中读取用户提供的类名,利用反射加载并且创建类对象。