java 从1.1就开始支持反射机制了,c++不支持反射机制。通过反射机制能够获取对象的类型和这个对象能做什么(有什么属性,什么方法),能够动态调用对象的方法,设置属性,以及创建新的实例(因此除了利用new关键字创建实例,还可以通过反射机制创建实例,其实还有两种方法,即反序列化和clone)。利用java的反射机制可以实现一些疯狂的事,做一些貌似无法实现的事。本文主要参照了2009年JavaZone会议上Heinz Kabutz发表的关于反射技术的疯狂演说 ,写得不错!
我们知道java的private属性是不允许外部直接访问修改的,而只能通过调用对象的外部接口访问和修改,但这不是绝对的,利用反射机制可以不调用对象的公共方法而修改对象属性,甚至修改final属性的值。
java String中字符存储是使用了private final char[] value,从这里我们也可以看出为什么java 字符串是不允许修改的,因为value是final的,但这仅意味着你无法通过调用它的公有方法来改变它的值,利用反射机制可以绕过这些限制而修改它,如代码:(想想这段代码的输出会是什么呢?)
import java.lang.reflect.*; public class Test { public static void main(String[] args) throws Exception { Field field = String.class.getDeclaredField("value"); field.setAccessible(true); field.set("hello!", "cheers".toCharArray()); System.out.println("hello!"); } }
这里还有一个问题是字符串池,当使用多个字面字符串时(不使用new String("...")),如果已经存在这个字符串,则不会创建一个新的对象,而仅仅指向已存在字符串的引用,即
String s1 = "hello"; String s2 = "hello"; System.out.println(s1 == s2);
s1 和s2是同一个对象的引用,即s1 == s2返回true。
回到上一段代码,field.set("hello!", "cheers".toCharArray()) 和 System.out.println("hello!")中字符串"hello!"其实是同一个对象,利用反射机制改变这个对象的value值,因此此时字符串"hello!"对应的value其实已经变成了"cheers",因此上段代码输出为cheers而不是hello!。
还有更神奇的,猜猜下面这段代码的输出结果是什么?
import java.lang.reflect.*; public class Test { public static void main(String[] args) throws Exception { Field field = null; field = Integer.class.getDeclaredField("value"); field.setAccessible(true); field.set(42, 43); System.out.printf("6 * 7 = %d\n", 6 * 7); } }
利用反射机制还可以做很多奇妙的事,比如获取方法调用者,获取类中的方法,获取对象的内存大小等等,具体参照原文!