JAVA基础系列规划:
- JAVA基础(1)——基本概念
- JAVA基础(2)——数据类型
- JAVA基础(3)——容器(1)——常用容器分类
- JAVA基础(4)——容器(2)——普通容器
- JAVA基础(5)——并发(1)——总体认识
- JAVA基础(6)——并发(2)——原子
- JAVA基础(7)——并发(3)——锁机制
- JAVA基础(8)——并发(4)——线程池
- JAVA基础(9)——容器(3)——并发容器
- JAVA基础(10)——IO、NIO
- JAVA基础(11)——泛型
- JAVA基础(12)——反射
- JAVA基础(13)——序列化
- JAVA基础(14)——网络编程
个人把java反射理解为一种框架,在框架内可以通过名称来控制类结构及其对象。而框架的基础就是java.lang.Class类和java.lang.reflect包中的Field、Constructor、Method、Array类。
Class类的实例表示正在运行的Java应用程序中的类和接口,保存它们的运行时类型标识信息。因此,它是java反射的开始,只有获得Class类的对象,才能通过这个对象获取其他相关信息。
获取一个类对象的Class,有三种方式:
Class classInstance = Person.class; //类型名.class获取该类型对应的Class对象
Class classInstance = Class.forName("Person"); //Class类的forName()静态方法获得与字符串对应的Class对象
Class classInstance = new Person().getClass(); //调用Object类对象的getClass()方法类得到Class对象
1. 获取数据结构
从Class开始,可以获取classInstance所关联的类的类名:
classInstance.getName(); //获得类的完整名字
不仅如此,类里面的所有东西都可以获取,Field、Constructor、Method,分别对应着类的成员变量、构造方法和成员方法。
Field[] fields = classInstance.getFields(); //获得类的public类型的属性
这样就获取了类的属性,但注意,只是public类型的属性,要获取类的所有属性,需要
Field[] fields = classInstance.getDeclaredFields(); //获得类的所有属性
要通过属性名称来获取类属性,就需要下面的方法了:
Field field = classInstance.getField("profession"); //public类型属性适用
Field field = classInstance.getDeclaredFields("profession"); //所有类型属性均适用
获取构造方法类似:
Constructor[] cs = classInstance.getConstructors(); //获得类的public类型的构造方法
Constructor[] cs2 = classInstance.getDeclaredConstructors(); //获得类的所有构造方法
Class parameterTypes[] = { java.lang.String.class }; //parameterTypes参数指定构造方法的参数类型
Constructor c = classInstance.getConstructor(parameterTypes); //public类型构造方法适用
Constructor c2 = classInstance.getDeclaredConstructor(parameterTypes);//所有类型构造方法适用
Constructor c3 = classInstance.getEnclosingConstructor(); //获取本地或匿名类Constructor对象
获取成员方法类似:
Method[] ms = classInstance.getMethods();//获得类的public类型的方法
Method[] ms2 = classInstance.getDeclaredMethods();//获得类的所有方法
String methodName = "setName";
Class methodParaTypes[] = { java.lang.String.class }; //methodParaTypes参数指定方法的参数类型
Method m2 = classInstance.getMethod(methodName, methodParaTypes);//public类型构造方法适用
Method m3 = classInstance.getDeclaredMethod(methodName, methodParaTypes);//所有类型构造方法适用
2. 实例化对象
不仅可以获取类的内部结构,还可以实例化出对象,方法为:
Person p = (Person)classInstance.getConstructor(new Class[] {}).newInstance(new Object[] {}); //通过类的不带参数的构造方法创建类对象
上句是通过类的不带参数的构造方法创建类对象,还可以用另一种表达:
Person p2 = (Person)classInstance.newInstance(); //通过类的不带参数的构造方法创建类对象
对于带参数的构造方法,就只有一条路了:
Person p3 = (Person)classInstance.getConstructor(new Class[] {java.lang.String.class}).newInstance(new String[] {"best"}); //通过类的带参数的构造方法创建类对象。
3. 调用实例化对象方法
使用Method,传递参数,隐式调用执行对象的方法:
String methodName2 = "getName";
Method m4 = classInstance.getMethod(methodName2);
Object value = m4.invoke(new Person(), new Object[] {});
4. 举个栗子
仿commons-beanutils中复制对象,这是一个运行时复制对象的过程。
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class BeanHelper {
public static Object copy(Object object) throws Exception {
Class classInfo = object.getClass();
Object objectCopy = classInfo.newInstance();
Field fields[] = classInfo.getDeclaredFields();
for(int i=0; i<fields.length; i++) {
Field field = fields[i];
String fieldName = field.getName();
String firstLetter = fieldName.substring(0, 1).toUpperCase();
String getMethodName = "get" + firstLetter + fieldName.substring(1);
String setMethodName = "set" + firstLetter + fieldName.substring(1);
Method getMethod = classInfo.getMethod(getMethodName, new Class[] {});
Method setMethod = classInfo.getMethod(setMethodName, new Class[] { field.getType() });
Object value = getMethod.invoke(object, new Object[] {});
setMethod.invoke(objectCopy, new Object[] { value });
}
return objectCopy;
}
}
小测一下:
public class Main {
public static void main(String[] args) throws Exception {
Person p = new Person();
Person p2 = (Person)BeanHelper.copy(p);
System.out.println(p2.getName());
}
}
5. 反射与动态代理
在企业应用高级框架中大量用到代理模式,其原理主要就是应用到反射。
详见代理http://www.blogjava.net/baoyaer/articles/84080.html
6. 附
public class Person {
private String name;
private String sex;
private String age;
public Person() {
name = "default";
sex = "male";
age = "25";
}
public Person(String name) {
this.name = name;
sex = "male";
age = "25";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public void walk(float length) {
System.out.println("walk " + length);
}
}