反射的功能很强大,可以在运行时检查类型,动态调用,实现代理,而且很多框架都是基于反射的,发射带来了很大的灵活性,前面一篇我介绍了反射的一些基本运用,下面来看看反射的性能等问题吧。
其实查资料最头疼了,好多书都只是片面的介绍了一下,深入分析的书还真不多(或者说我没找到。。。),在网上查资料,千篇一律,这里要郑重的批斗一下那些复制粘贴的人,鄙视你们。拿别人的东西也要修改一下然后加上自己的理解和别人没说到的再发出去,这也算是自己曾今研究过的东西,对自己有帮助,而且对别人也有帮助。
1.反射的性能 :
我们能拿到代码,直接运行,直接调用方法,调用属性,这样不是很快捷,很方便吗,那么用反射来调用方法或者访问属性,他的效率怎么样呢?下面来看一下简单的测试:
public class Test4 { public static void main(String [] args) throws Exception{ int a = 0; int testTime = 10000000;//循环testTime次 Test4 t = new Test4(); long start = System.currentTimeMillis(); for(int i = 0;i<testTime;i++){ t.test(a); } long end = System.currentTimeMillis(); System.out.println("不用反射的时间:"+(end-start)); //运用反射 Method method = t.getClass().getMethod("test", int.class); start = System.currentTimeMillis(); for(int i = 0;i<testTime;i++){ method.invoke(t, a); } end = System.currentTimeMillis(); System.out.println("运用反射的时间:"+(end-start)); } //测试方法 public void test(int a){ a += 1; } }
结果:
不用反射的时间:15
运用反射的时间:1516
当然这个数据和电脑的配置有一定的关系,我的电脑有一定的历史了,测出来是10被的关系,说明性能是反射的一种不足,但是反射的功能很强大,这点性能的不足完全可以在外部改进电脑的硬件来弥补,以牺牲部分运行效率来提升开发效率是很值得的。
2.反射的安全
面向对象有一个特性是封装,就是将一些不用给外部知道属性定义为private,然后提供公有的方法让外部操作,而且private定义的属性就连子类都不能继承,那么用反射可以绕过权限,对其非公有的属性乃至方法进行操作,这样不是破坏了java的封装性么?这样不是使java不安全了吗?
我对封装的理解是这样的,不是说不让外部知道,而是外部知道这些根本没用,外部只要用其公有方法就可以了。我们不是经常说写程序要模块化的设计,这样才能达到高内聚低耦合吗,面向接口编程不就是这样么。
java运行时通过靠一种安全管理器来验证调用代码对某一特定的访问是否具有权限,安全管理器就是java.lang.SecurityManager类或者其子类。所有对象在执行自身逻辑之前都要委派给安全管理器,当访问收到安全管理器的控制,应用程序就只能执行相关策略允许的操作。但是默认情况下,安全管理器是没有被设置的,运行时访问控制不起作用,所以我们可以绕过安全管理器对非公有属性或方法进行调用。还记得前面写了一个调用私有属性的操作,调用AccessibleObject类的setAccessible()方法,设置参数为true,然后对私有成员进行操作。
Person类:
public class Person { private String name = "张三"; public String getName() { return name; } }
测试类:
public class Test3 { public static void main(String [] args) throws Exception{ Person per = new Person(); System.out.println("操作前Name为:"+per.getName()); Field field = per.getClass().getDeclaredField("name"); field.setAccessible(true); field.set(per, "李四"); System.out.println("操作后Name为:"+per.getName()); } }
结果:
操作前Name为:张三
操作后Name为:李四
可以看出,虽然Person类中并没有设置name属性的方法,但是通过反射任然可以得到私有属性,并进行设置。这样不是很不安全么。正常人一般不会大费周章的来写这种危害程序安全的程序,除非是测试之类的。当然我们也可以通过一些手段设置程序不拥有此权限,目前正在学习中。
动态代理在后面介绍代理模式的时候再一起介绍。