Java反射机制
反射概念:(百度百科)JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
作用:在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
反射机制在API 需要的类:
java.lang.Class;
java.lang.reflect.Constructor;
java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
下面我们通过几个实例来描述java反射机制都能做哪些事情。
利用反射机制对ReflectTester类的customer对象进行拷贝:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectTester {
// 该方法实现对 customer对象的拷贝
public Object copy(Object object) throws Exception {
Class<?> classType = object.getClass();//获得 Object类的类对象
Object objectCopy = classType.getConstructor(new Class[] {}).newInstance(new Object[] {});
// 先通过类对象对不带参数的构造方法获得其constructor对象,再通过构造方法对象
// 调用实例化方法生成对customer类的对象,并转成object类型的 所以objectCopy是object类型的引用
// ,但指向customer类,也就是多态。
// Object object2=classType.newInstance();上面两句等同于这一句
Field[] fields = classType.getDeclaredFields(); // 获得指定类(Object)的所有成员变量
for (Field field : fields) { // 增强的for循环 对存储customer成员变量的数组进行遍历 ,并打印输出
String name = field.getName();
String firstLetter = name.substring(0, 1).toUpperCase();// substring方法是获得对应字符串的在该下标范围内的字符 [0,1)
// toUpperCase方法是将属性的首字母转换成大写
String getMethodName = "get" + firstLetter + name.substring(1);// 这个1表示1到末尾的字符
String setMethodName = "set" + firstLetter + name.substring(1);//字符串拼接
Method getMethod = classType.getMethod(getMethodName, new Class[] {});// customer类里面的getName方法是无参方法,获得指定方法的方法对象,括号内的getMethodName就是我们想要获得的方法的方法名,后面的Class类的数组就是该方法的参数
Method setMethod = classType.getMethod(setMethodName, new Class[] { field.getType() });// setMethodName方法是有参方法,getType方法是返回field的类型
Object value = getMethod.invoke(object, new Object[] {});// 这里的object是一开始传入的customer,getName方法无参,也就是通过invoke方法调用指定的方法,也就是Customer类里面的所有成员变量的get方法,最后得到object对象里面的具体数值信息然后赋给value对象,
setMethod.invoke(objectCopy, new Object[] { value });// 将value里面的值传给objectCopy对象,通常情况下只要我们new一个对象,该对象里面都会包含一份对应类的成员变量,我们将面从get方法里面返回的数值重新赋给objectCopy里面的成员变量,也就完成了copy操作
}
return objectCopy;
}
public static void main(String[] args) throws Exception {
Customer customer = new Customer("Tom", 20);
customer.setId(1L);
ReflectTester test = new ReflectTester();
Customer customer2 = (Customer) test.copy(customer);
System.out.println(customer2.getId() + "," + customer2.getName() + "," + customer2.getAge());
}
}
class Customer {
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;
}
}
代码中的注释对代码解释已经很详细我就不在说了。接下来在看第二个例子,功能是实现调用某类的方法:
这里写import java.lang.reflect.Method;
public class InvokeTester
{
public int add(int param1, int param2)
{
return param1 + param2;
}
public String echo(String message)
{
return "hello: " + message;
}
public static void main(String[] args) throws Exception
{
// InvokeTester test = new InvokeTester();
// System.out.println(test.add(1, 2));
// System.out.println(test.echo("tom"));
//下面那么多行代码其实就等同于上面几行代码
Class<?> classType = InvokeTester.class;//获得对应类的类对象
Object invokeTester = classType.newInstance();//获得指定类的实例
// System.out.println(invokeTester instanceof InvokeTester);
Method addMethod = classType.getMethod("add", new Class[] { int.class,int.class });//通过括号内的限制,获得指定方法的方法对象
Object result = addMethod.invoke(invokeTester, new Object[]{1, 2});//对指定方法进行调用,
System.out.println(result);
System.out.println("---------------------");
Method echoMethod = classType.getMethod("echo", new Class[]{String.class});
Object result2 = echoMethod.invoke(invokeTester, new Object[]{"tom"});
System.out.println((String)result2);
}
}
再看第三个例子,功能是给某类的私有变量赋值:
public class Private2
{
private String name = "zhangsan";
public String getName()
{
return name;
}
}
import java.lang.reflect.Field;
public class TestPrivate2
{
public static void main(String[] args) throws Exception
{
Private2 p = new Private2();
Class<?> classType = p.getClass();//获得指定类的类对象
Field field =classType.getDeclaredField("name");//获得指定类里面的指定成员变量
field.setAccessible(true);//这里很重要,这里就使我们为什么能对私有化成员变量进行修改的主要原因,不明白得就去查看API文档
field.set(p, "lisi");//修改指定成员变量的值
System.out.println(p.getName());
}
}
下一个例子是通过反射构建数组
import java.lang.reflect.Array;
public class ArrayTester1 {
public static void main(String[] args) throws Exception {
Class<?>classTypeClass.forName("java.lang.String");//根据后面的字符串获得指定类的类对象
Object array = Array.newInstance(classType, 10);//这里的classtype是String,这句话的意思是创建一个String类型长度为10的数组
System.out.println(array instanceof String[]);
for(int i=0;i<Array.getLength(array);i++) {
String str = (String) Array.get(array, i);
System.out.println(str);
}
Array.set(array, 5, "hello");//对数组某个位置上添加元素
String str = (String) Array.get(array, 5);
System.out.println(str);
}
}
也不知道你们有没有耐心看到这里。。。。。。。
最后我就在总结一下反射机制的用法:
一般情况下 只要使用反射机制,我们都会先获得对应类的类对象,而获得类对象有三种方法:
a)使用 Class 类的静态方法 forName:Class.forName(“java.lang.String”);
b)使用类的.class 语法:String.class;
c)使用对象的 getClass()方法:String s = “aa”; Class<?> clazz = s.getClass();
若想通过类的不带参数的构造方法来生成对象,我们有两种方式:
a)先获得 Class 对象,然后通过该 Class 对象的 newInstance()方法直接生成即可:
Class<?> classType = String.class; Object obj = classType.newInstance();
b)先获得 Class 对象,然后通过该对象获得对应的 Constructor 对象,再通过该 Constructor 对象的 newInstance()方法生成:
Class<?> classType = Customer.class;
Constructor cons = classType.getConstructor(new Class[]{}); Object obj = cons.newInstance(new Object[]{});
若想通过类的带参数的构造方法生成对象,只能使用下面这一种方式:
Class<?> classType = Customer.class;
Constructor cons = classType.getConstructor(new Class[]{String.class, int.class}); Object obj = cons.newInstance(new Object[]{“hello”, 3});
至于一些其他的方法也基本都在上面代码中,我就不在一一列出来。
不正确的地方大家多多指教。