很多人都会说statci块的执行是在第一次调用newInstance的时候调用,但是这是并不全是正确的,我们可以用以下方法来测试:[code=java]public class TestA{
static{
System.out.println("Static block executed!");;
}
}
public class Test{
public static void main(String args[]);{
Test test = new Test();;
Class.forName("TestA",true,test.getClass();.getClassLoader(););;
}
} [/code][code=java]这时没有初始话TestA的实例,打印结果为:Static block executed![/code]通过控制Class.forName中的true属性可以发现,当改变为false时,就不会执行输出语句。
------------------------------------------------------------
一个类的运行,JVM做会以下几件事情 1、类装载 2、链接 3、初始化 4、实例化;而初始化阶段做的事情是初始化静态变量和执行静态方法等的工作。所以,当Class.forName(args[0],true,off.getClass().getClassLoader());中的true变为false的时候,就是告诉JVM不需再load class之后进行initial的工作。这样,将initial的工作推迟到了newInstance的时候进行。所以,static块的绝对不是什么“只是在类被第一次实体化的时候才会被仅仅调用一次”,而应该是在类被初始化的时候,仅仅调用一次。
想也应该想到,如果是第一实例化才调用,那么JDBC Driver就没法加载了,JDBC Driver的加载就是利用了这个原理在静态块中向DriverManager注册自己的.
在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又可以分成校验、准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下:
装载:查找和导入类或接口的二进制数据;
链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;
校验:检查导入类或接口的二进制数据的正确性;
准备:给类的静态变量分配并初始化存储空间;
解析:将符号引用转成直接引用;
初始化:激活类的静态变量的初始化Java代码和静态Java代码块。
------------------------------------------------------------
以下可以参考对Class.forName()的解释:
首先java里面任何类都要加载到虚拟机上才能运行,class.forName()这句话就是装载用的(和new不一样)。JVM会执行静态代码段,要记住静态代码段是和class绑定的,class装载成功了,就代表静态代码段执行了,以后就不会再走这段代码了。
在初始化一个类,生成一个实例时,class.newInstance()和new class()除了一个是方法,一个是关键字外还有什么区别,它们的区别在于,前者是使用类加载机制,后者是创建一个新类。为什么会有两种创建方式?这主要考虑到软件的可伸缩,扩展和重用等软件设计思想。
java工厂模式中经常用到newInstance方法来创建对象,因此可以从为什么使用工厂模式中找到答案。[code=java]class c=Class.forName("Example");
factory =(ExampleInterface)c.newInstance();(其中ExampleInterface是Example的接口)[/code]也可以写成如下形式:[code=java]String className="Example";
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();[/code]进一步可以写成如下形式:[code=java]String className= readingfromXmlConfig;(从xml配置文件中获得字符串)
class c =Class.forName(className);
factory = (ExampleInterface)c.newInstance();[/code]上面代码已经存在Example类名字,它的优点是无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example1,Example2等等,只要他们继承ExampleInterface接口就可以。JVM的角度看,使用关键字new创建一个新类时,该类可以没被加载,使用newInstance方法的时候就必须保证该类已经被加载且这个类已经连接了。类加载是通过class的静态加载方法forName()实现的。
最后简单区分new关键字和newInstance()方法的区别:
newInstance:弱类型,低效率,只能用无参构造。
new:强类型,能调用任何public构造方法。
[ 本帖最后由 詹季春 于 2011-07-25 00:56 编辑 ] |