1. 反射的应用场景
Java的反射机制在平时的业务开发过程中很少使用到,但是在一些基础框架的搭建上应用非常广泛。Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。《java反射的运用场景》此文章举例了反射的一个使用场景。《反射机制及其应用场景》此文章中举例说明了更复杂的反射使用场景。
2. 反射可提供的功能
Class类与java.lang.reflect类库一起对反射进行了支持,该类库包含Field、Method和Constructor类,这些类的对象由JVM在启动时创建,用以表示未知类里对应的成员。这样的话就可以使用Contructor创建新的对象,用get()和set()方法获取和修改类中与Field对象关联的字段,用invoke()方法调用与Method对象关联的方法。另外,还可以调用getFields()、getMethods()和getConstructors()等许多便利的方法,以返回表示字段、方法、以及构造器对象的数组,这样,对象信息可以在运行时被完全确定下来,而在编译时不需要知道关于类的任何事情。
反射机制并没有什么神奇之处,当通过反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,看它属于哪个特定的类。因此,那个类的.class
对于JVM来说必须是可获取的,要么在本地机器上,要么从网络获取。所以对于RTTI,即我们通常使用类的方式,和反射之间的真正区别只在于:
- RTTI,编译器在编译时打开和检查.class文件
- 反射,运行时打开和检查.class文件
3. 反射的缺点
- 性能问题。使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此Java反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。
- 使用反射会模糊程序内部逻辑。程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂。
4. 以下是反射使用方法的举例:
import java.util.ArrayList; public class TestClass { public String testVar1; private ArrayList arr; public TestClass(String testVar1, ArrayList arr){ this.testVar1 = testVar1; this.arr = arr; } public TestClass(){} public void test1(String var1, int var2){ System.out.println("TestClass.test1(String, int) " + var1 + " " + var2); } public void test1(String var1){ System.out.println("TestClass.test1(String)"); } private void test2(String var1){ System.out.println("TestClass.test2(String) "); } private void test2(){ System.out.println("TestClass.test2()"); } }
import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Constructor; public class Main { public static void main(String[] args){ //得到反射类方法1 TestClass tc = new TestClass(); Class c = tc.getClass(); //得到反射类方法2 Class c1 = TestClass.class; try { //得到反射类方法3 Class<?> clazz = Class.forName("xxx.xxx.xxx.TestClass"); //class的路径要写全 //得到类名 System.out.println("得到类名"); System.out.println(clazz.getName()); //得到构造器 Constructor[] constructors = clazz.getConstructors(); System.out.println("得到构造器名"); for(Constructor con : constructors) System.out.println(con.getName()); //得到成员方法 Method[] methods = clazz.getDeclaredMethods(); System.out.println("得到所有被声明成员方法"); for(Method m : methods) System.out.println(m.getName()); methods = clazz.getMethods(); System.out.println("得到public的成员方法"); for(Method m : methods) System.out.println(m.getName()); Method method = clazz.getMethod("test1", String.class); System.out.println("得到特定的成员方法"); System.out.println(method.getName()); method = clazz.getDeclaredMethod("test2"); System.out.println(method.getName()); //得到public成员变量方法 Field[] fields = clazz.getFields(); System.out.println("得到public的成员变量"); for(Field f : fields) System.out.println(f.getName()); Field[] fields1 = clazz.getDeclaredFields(); System.out.println("得到所有成员变量,包括私有成员变量"); for(Field f : fields1) System.out.println(f.getName()); System.out.println("使用反射方法获得类实例并访问域成员testVar1"); Field field = clazz.getField("testVar1"); Object object = clazz.getConstructor().newInstance(); field.set(object, "haha"); TestClass newTc = (TestClass)object; System.out.println(newTc.testVar1); //结果为haha System.out.println("使用反射方法获得类实例并调用成员方法test1(String, int)"); object = clazz.getConstructor().newInstance(); method = clazz.getDeclaredMethod("test1", String.class, int.class); Object invoke = method.invoke(object, "hehe", 1); }catch (Exception e){ e.printStackTrace(); } } }