最近在开发一个小型的j2ee项目,沿用以前公司成熟的struts + spring + hibernate三层架构,只是做些修改,加一些新的业务规则进去(这也让我这个新手体验到了面向对象的可重用性的优点),在开发的过程中我无意中发现以前公司的项目中spring托管的中间层的类里面都用的是private的默认构造方法,我感到奇怪,难道具有私有的构造方法的类也能new一个对象出来?我立马在msn上请教了我的师傅--公司的前辈,回答说是用java的反射机制,于是我上网搜索了有关java反射的资料,对java的反射机制也有了些了解,但是这些毕竟都是别人说的,我自己还需亲自验证一下,于是有了下面的代码:
- package com.ref;
- public class A {
- private A() {
- System.out.println("This is a private Constructor");
- }
- /**
- private A(String str, int i) {
- System.out.println("str = " + str);
- System.out.println("i = " + i);
- }
- */
- }
- package com.ref;
- import java.lang.reflect.Method;
- import java.lang.reflect.Constructor;
- public class TestReflect {
- public static void main(String args[]) throws Exception {
- //产生class
- Class a = Class.forName("com.ref.A");
- //返回 Constructor 对象的一个数组,这些对象反映此 Class
- //对象表示的类声明的所有构造方法。它们是公共、保护、默认
- //(包)访问和私有构造方法。返回数组中的元素没有排序,
- //也没有任何特定的顺序。如果该类存在一个默认构造方法,
- //则它包含在返回的数组中。如果此 Class 对象表示一个接口、
- //一个基本类型、一个数组类或 void,则此方法返回一个长度为 0 的数组。
- Constructor [] constructs = a.getDeclaredConstructors();
- for(int i = 0; i < constructs.length; i++) {
- System.out.println(constructs[i].getName());
- //将Constructor对象的 accessible 标志设置为true
- constructs[i].setAccessible(true);
- constructs[i].newInstance(null);
- }
- }
- }
该程序运行后在控制台打印如下信息:
com.ref.A
This is a private Constructor
事实胜于雄辩,看来java的反射机制确实能new出一个带有private构造方法的对象来,类似的,像getDeclaredMethods() 和getDeclaredFields()都可以得到private的元素。这个也说明了单例模式在语法角度是不能保证的。完全可以调用private的构造方法生成一个对象。访问级别(access level)仅仅是编译期检查的项目,在运行期没有限制作用。
我没有看过spring框架的源码,但我估计spring就是靠java 的反射机制来得到对象的,现在我们不妨来玩一玩,我们来把上面第一段代码中关于A.java的另一个带有参数的私有构造方法前面的注释去掉,编译运行,这时候控制台抛出了异常:
Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
那我们再来看看spring在这个问题上是不是够健壮,考验下spring的动态反射到底有多强大,到底是不是“nothing is impossible”,我把正在做的那个项目的中间层的代码稍微做了修改,把spring托管的类的私有默认构造方法加了一个参数,然后保存,编译,并重起了tomcat服务器,察看后台日志stdout.log,发现抛了异常:
org.springframework.beans.FatalBeanException: Could not instantiate class [com.ss.watch.serv.SysService]: no default constructor found;
看来spring虽然反射运用的出神入化,但是还是有其局限性的啊,有待后续版本进一步完善,呵呵