开篇必然要先说一说,什么是java反射了。标准的来说,反射是指程序可以访问、检测和修改自身状态和行为的一种能力。简单的来说,java反射机制其实就是在运行时获取类的信息,属性或方法等,并利用这些信息做一些我们想做的事情。
大家有注意到上面一个非常重要的词--“运行时”。顾名思义,就是当程序运行的时候。这个词也就说明了我们为什么要使用反射机制。java语言本身不是一种动态语言,它在编译时确定类型,创建对象。但是它却有一个非常突出的动态相关机制:Reflection(反射)。使得java程序可以在运行时加载、使用编译时完全未知的classes,实现动态创建对象和编译,体现出很大的灵活性。
java反射机制主要有以下几个用途:
理解了反射机制的概念和用途,接下来看看如何使用它吧。一般需要遵循三步:
一、 获取类的class对象
在运行程序时,一个类会生成多个对象,但是我们需要注意的是,无论多少个对象,他们都对应着一个class对象。获取这个class对象主要有三种方式:
1. Class的静态方法forName
Class> cls = Class.forName(com.tgb.j2se.service.Student);
2.类的.class
Class> cls = Student.class;
3.对象的getClass方法
Student student = new Student();
Class> cls = student.getClass();
二、获取类的方法和属性
1.获取类的方法
// 通过Class获得Student类的show方法
Method method = cls.getMethod("show", String.class);
通过反射的方式调用show方法,需要先获得该方法的Method对象,其中getMethod方法中第一个参数是指方法名;第二个参数是指方法的参数类型,如果有多个参数,直接添加参数类型就可以。
2.获取类的属性
// 通过Class获得Student类的属性列表
Field[]fromFields = cls.getDeclaredFields();
三、操作类的方法和属性
1.操作类的方法
通过Class获得Student类的show方法后也就获取待调用方法的Method对象,接下来我们就可以反过来调用待调用方法了。
// 获取show方法后,可以执行该方法
method.invoke(student, "SunLiDuan");
invoke方法中第一个参数,是Student类的一个对象,也就是调用Student类哪个对象的show方法;第二个参数是给sow方法传递的参数。这里的类型个数和getMethod方法中一致。
2.操作类的属性
通过Class获得Student类的属性后即可对属性进行操作。下面是一段完整的代码:
package com.sld.j2se.service;
import java.lang.reflect.Field;
import com.sld.j2se.serviceImpl.Student;
public class test {
public static void main(String[] args) throws Exception {
// 建立学生对象
Student student = new Student();
// 为学生对象赋值
student.setStuName("孙丽端");
student.setStuAge(25);
// 建立拷贝目标对象
Student destStudent = new Student();
// 拷贝学生对象
copyBean(student, destStudent);
// 输出拷贝结果
System.out.println(destStudent.getStuName() + ":"
+ destStudent.getStuAge());
}
/**
* 拷贝学生对象信息。
*
* @param from
* 拷贝源对象
* @param dest
* 拷贝目标对象
* @throws Exception
* 例外
*/
private static void copyBean(Object from, Object dest) throws Exception {
// 取得拷贝源对象的Class对象
Class> fromClass = from.getClass();
// 取得拷贝源对象的属性列表
Field[] fromFields = fromClass.getDeclaredFields();
// 取得拷贝目标对象的Class对象
Class> destClass = dest.getClass();
Field destField = null;
for (Field fromField : fromFields) {
// 取得拷贝源对象的属性名字
String name = fromField.getName();
// 取得拷贝目标对象的相同名称的属性
destField = destClass.getDeclaredField(name);
// 设置属性的可访问性
fromField.setAccessible(true);
destField.setAccessible(true);
// 将拷贝源对象的属性的值赋给拷贝目标对象相应的属性
destField.set(dest, fromField.get(from));
System.err.println(destField.getName());
}
}
}
宏观的说,在JDK中主要有以下类来实现java反射机制,这些类都位于java.lang.reflect包中,时用时查吧~~
下面是一些常用的方法:
上面已经提到了有三种方式
Object obj=cls.newInstance();
Constructor getConstructor(Class[] params)//根据指定参数获得public构造器
Constructor[] getConstructors()//获得public的所有构造器
Constructor getDeclaredConstructor(Class[] params)//根据指定参数获得public和非public的构造器
Constructor[] getDeclaredConstructors()//获得public的所有构造器
Method getMethod(String name, Class[] params),根据方法名,参数类型获得方法
Method[] getMethods()//获得所有的public方法
Method getDeclaredMethod(String name, Class[] params)//根据方法名和参数类型,获得public和非public的方法
Method[] getDeclaredMethods()//获得所以的public和非public方法
Field getField(String name)//根据变量名得到相应的public变量
Field[] getFields()//获得类中所以public的方法
Field getDeclaredField(String name)//根据方法名获得public和非public变量
Field[] getDeclaredFields()//获得类中所有的public和非public方法
这就是java的反射机制了,它实现了动态创建对象和编译,体现出很大的灵活性,但是它的缺点也是不容忽视的:
首先是性能方面,因为反射包括了一些动态类型,所以JVM无法对这些代码进行优化,因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。其次在安全限制方面,使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如Applet,那么这就是个问题了;最后就是内部暴露了,由于反射代码允许代码执行一些在正常情况下不被允许的操作(例如访问私有属性或方法),所以使用反射可能会造成代码有功能上的错误。
因此,java反射有利有弊,何时用,怎么用,还需仔细斟酌!