在java运行时环境中,对任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能发调用它的任意一个方法?答案肯定是能的。这种动态获取类信息以及动态调用对象方法的功能来自java语言的反射(Reflection)机制。
java反射机制提供以下功能:
在JDK中由以下类来实现java反射机制,这些类都为与:
下面是利用java反射机制API的一个简单示例:
import java.lang.reflect.Method;
public class DumpMethods
{
//功能:打印指定类名的所有方法
public static void main(String args[]) throws Exception
{
// 加载并初始化指定的类,获取与指定的类对应的Class类(Class是一个java类,是java反射机制的核心类)
Class classType = Class.forName("java.lang.String");
// getDeclareMethods()是获得类的所有方法,getMethods()是获得所有public的方法
Method methods[] = classType.getDeclaredMethods();
for (int i = 0; i < methods.length; i++)
{
System.out.println(methods[i].toString());//打印方法名
}
}
}//看效果自己运行。。。。
下面的示例进一步演示了Reflection API的基本使用方法。ReflectTester类有一个copy(Object object)方法,这个方法能够创建一个和参数object 同样类型的对象,然后把object对象中的所有属性值拷贝到新建的对象中,并将它返回
这个例子只能复制简单的JavaBean,假定JavaBean 的每个属性都有public 类型的getXXX()和setXXX()方法。其实实现上述功能很简单,这里只是为了理解java反射机制API的应用所以复杂化了。
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectTester
{
public Object copy(Object object) throws Exception
{
// 获得对象的类型
Class classType = object.getClass();
System.out.println("Class:" + classType.getName());//打印出Class类所表示完整的类或借口的名字(简单理解就是打印类名)
// 通过默认构造方法创建一个新的对象
Object objectCopy = classType.getConstructor(new Class[] {}).newInstance(new Object[] {});//以后内容会详细解释用法和作用
// getDeclaredFields()获得对象的所有属性,getFields()获得所有public的属性
Field fields[] = classType.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
Field field = fields[i];
String fieldName = field.getName();//获得属性的名字
String firstLetter = fieldName.substring(0, 1).toUpperCase();//属性的第一个字母转化成大写
// 获得和属性对应的getXXX()方法的名字
String getMethodName = "get" + firstLetter + fieldName.substring(1);
// 获得和属性对应的setXXX()方法的名字
String setMethodName = "set" + firstLetter + fieldName.substring(1);
// 获得和属性对应的getXXX()方法,没有参数所以传递了Class类型的空数组
Method getMethod = classType.getMethod(getMethodName, new Class[] {});
// 获得和属性对应的setXXX()方法,field.getType():field代表属性,getType()返回属性的类型所对应的Class类(java在运行时每个类都有一个对应的Class类,来实现反射机制)
Method setMethod = classType.getMethod(setMethodName, new Class[] { field.getType() });
// 调用原对象的getXXX()方法,object代表你所要调用的那个方法所属的对象(调用一个方法理所应当知道要调用那个对象得),getMethod代表调用的方法
Object value = getMethod.invoke(object, new Object[] {});//value调用方法所返回的值
System.out.println(fieldName + ":" + value);
// 调用拷贝对象的setXXX()方法
setMethod.invoke(objectCopy, new Object[] { value });
}
return objectCopy;
}
public static void main(String[] args) throws Exception
{
Customer customer = new Customer("Tom", 21);
customer.setId(new Long(1));
Customer customerCopy = (Customer) new ReflectTester().copy(customer);
System.out.println("Copy information:" + customerCopy.getId() + " " + customerCopy.getName() + " "
+ customerCopy.getAge());
}
}
class Customer
{
//一个简单的javaBean
private Long id;
private String name;
private int age;
public Customer()
{
}
public Customer(String name, int age)
{
this.name = name;
this.age = age;
}
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
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;
}
}
下面详细介绍这个Class这个核心类常用的方法:
在java.lang.Object 类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API 中的核心类,它是java反射机制的一个起源,你想对java的任何类勘探都要先获取
其对应的Class类才能进行相关的一系列操作,才能使用反射的数十个API。它有以下常用方法
getName():获得类的完整名字。getFields():获得类的public类型的属性。getDeclaredFields():获得类的所有属性。getMethods():获得类的public类型的方法。getDeclaredMethods():获得类的所有方法。getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。getConstructors():获得类的public类型的构造方法。getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。newInstance():通过类的不带参数的构造方法创建这个类的一个对象。上述示例中的一段代码说明了getConstructors()和newInstance()的应用Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});等价于Object objectCopy=classType.newInstance();,都是通过默认构造方法创建一个新对象。以上代码先调用Class类的getConstructor()方法获得一个Constructor 对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。
Class [] classArray = new Class[]{String.class,int.class};
Object [] objArray = new Object[]{"Tome",10};
//classArray数组下标0为String类型所对应的Class类(String.class),
//那么objInt对应位置的值的数据类型必须是String类型数值("Tome")//这两个数组中的元素按照这样的规则意义对应
Object objectCopy = classType.getConstructor(classArray).newInstance(objArray);
package com.langsin.reflection;
import java.lang.reflect.Method;
public class InvokeTester
{
public int add(int param1, int param2)
{
return param1 + param2;
}
public String echo(String msg)
{
return "echo: " + msg;
}
public static void main(String[] args) throws Exception
{
Class classType = InvokeTester.class;
Object invokeTester = classType.newInstance();
// Object invokeTester = classType.getConstructor(new
// Class[]{}).newInstance(new Object[]{});
// 调用InvokeTester对象的add()方法
Class classInt = new Class[] { int.class, int.class };//add()方法所接受参数类型对应的Class类型数组
Method addMethod = classType.getMethod("add", classInt);
//classInt1数组下标0为int类型所对应的Class类(int.class),
//那么objInt对应位置的值的数据类型必须是int类型数值(new Integer(100))
Object objInt = new Object[] { new Integer(100), new Integer(200) };//add()所接受的值
Object result = addMethod.invoke(invokeTester,objInt});
System.out.println((Integer) result);
//-------------------------------------------
// 调用InvokeTester对象的echo()方法
Class classStr = new Class[] { String.class };
Method echoMethod = classType.getMethod("echo",classStr);
Object objStr = new Object[] { "Hello" }
result = echoMethod.invoke(invokeTester,objStr);
System.out.println((String) result);
}
}
对以上示例的一段代码进行说明:
Method类的invoke(Object obj,Object args[])方法接收的参数必须为对象,invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回。