一、反射机制是什么?
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。其实反射就是学习一个叫Class的类,这个特殊的类可以对其他类进行操作。
二、通常用反射做什么?
判断对象是否属于某个类,获取一个类对象对应类的成员属性,构造方法和成员方法,获取属性的修饰符或类型,获取方法的修饰符和方法的返回类型,在运行时实例化对象,调用任意一个类的方法,或者对任意一个类的属性进行操作等等。
下面的代码以下面这个类做讲解:
public class Reflect implements Serializable{
static class Student{
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void StudentReflect1(){
System.out.println("无参数的方法");
}
public void StudentReflect2(String name,int age){
System.out.println(name+" "+age);
}
}
}
三、反射相关API的使用
① 获取对象完整的的包名和类名
Student stu = new Student();
//查看完整的包名.类名
System.out.println(stu.getClass().getName());
或者可以
Class<?> clazz = Class.forName("Reflect");
② 获取父类或接口
//Class类的父类是Object类,getSuperClass()就是获取父类对象 System.out.println(clazz.getSuperclass().getName());
//获取类的各个接口
Class<?> interfaces[] = clazz.getInterfaces();
for(Class c : interfaces){
System.out.println("接口有:"+c.getName());
}
③ 获取类的构造方法并实例化对象
//获取类的各个构造方法
Constructor<?> cons[] = stu.getClass().getConstructors();
for(int i = 0; i < cons.length; i++){
Class<?>[] clazzs = cons[i].getParameterTypes();
}
stu = (Student) cons[1].newInstance("惠惠",21);
//通过类的对象获得类的实例化对象操作
stu = (Student)stu.getClass().newInstance();
④ 获取类的属性的修饰语、属性的类型、属性名
clazz = stu.getClass();
//获取本类的属性的数组集合,getFields()是获取父类的属性
Field f[] = clazz.getDeclaredFields();
for(int i = 0; i < f.length; i++){
//获取属性的修饰语
int mo = f[i].getModifiers();
String modi = Modifier.toString(mo);
//获取属性的类型
Class<?> type = f[i].getType();
System.out.print("权限修饰符:"+modi+" ");
System.out.print("属性类型:"+type.getName()+" ");
System.out.println("属性名:"+f[i].getName()+" ");
}
⑤ 获取类的方法并执行方法
//获取类的方法
Method methods[] = clazz.getMethods();
for(int i = 0; i < methods.length; i++){
System.out.println(methods[i].getModifiers()+" "+methods[i].getName());
}
//通过反射调用类的方法,注意不是构造方法
Method m = clazz.getMethod("StudentReflect1");
//唤醒(执行该方法)
m.invoke(clazz.newInstance());
//获取指定方法
m = clazz.getMethod("StudentReflect2", String.class,int.class);
//使用invoke实例化对象,并传入指定的参数到给该对象,最终执行该方法
m.invoke(clazz.newInstance(), "刘德华",22);
⑥ 操作类的属性
Class<?> clazz = stu.getClass();
Field nameField = clazz.getDeclaredField("name");
Field ageField = clazz.getDeclaredField("age");
Object obj = clazz.newInstance();
//将modifier为private的属性设置为可访问
nameField.setAccessible(true);
ageField.setAccessible(true);
nameField.set(obj, "刘德华");
ageField.set(obj, 23);
System.out.println(nameField.get(obj));
System.out.println(ageField.get(obj));
四、其他的一些使用
反射给存放Integer类型对象的容器存放String类型对象:
//使用反射可以给一个装Integer对象的容器添加进String类型的对象
List<Integer> list = new ArrayList<Integer>();
Method me = list.getClass().getMethod("add", Object.class);
me.invoke(list,"反射机制");
for(int i = 0 ; i < list.size(); i++){
System.out.println(list.get(i));
}
获取操作数组的信息:
//反射获取数组的类型
int arr[] = {1,2,3,4};
Class<?> cla = arr.getClass().getComponentType();
System.out.println("数组类型:"+cla.getName());
System.out.println("数组长度:"+Array.getLength(arr));
System.out.println(Array.get(arr, 0));
//对数组指定索引处的值进行修改
Array.set(arr, 0, 5);
System.out.println(Array.get(arr, 0));
修改数组的长度:
int arr[] = {1,2,3,4};
System.out.println("------------------反射修改数组大小---------------");
System.out.println("arr的数组长度为:"+arr.length);
int newArr[] = (int [])arrayInc(arr,5);
System.out.println("增加后的arr的数组长度为:"+newArr.length);
public static Object arrayInc(Object obj,int len){
//获取数组的Class类的对象
Class<?> arr = obj.getClass().getComponentType();
int originalLen = Array.getLength(obj);
Object newArr = Array.newInstance(arr, originalLen+len);
System.arraycopy(obj, 0, newArr, 0, originalLen);
return newArr;
}
还有运用于工厂模式和动态代理,不过暂时还搞不懂先Mark一下
参考文章:http://baike.xsoftlab.net/view/209.html#3