您的位置:首页 > 其它

forName、new和ClassLoader方法的比较

2012-10-26 10:49 253 查看
fornName()和new方法
Class.forName是用来获取Class的类类型,作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段。

Class.forName('XXX')返回的是一个类,newInstance() 后才创建一个对象。

A a = (A)Class.forName("pacage.A").newInstance(); 和 A a = new A(); 是一样的效果。

但是:

forName("ss.bb.bean"), JVM会在classapth中去找对应的类,设定在classpath的类,在java启动的时候最先被加载,并将Class对象保存起来,这样forName创建对象时就不需要通过classloader再去读取该类的文件了。

而new 一个对象,一般不需要该类在classpath中设定,但可能需要通过classlaoder来加载。

当你确定此时内存中没有这个对象的时候,你就可以用class.forName();来创建一个对象,而假如new是不管你内存中是否有这个对象都会创建一个新的对象,也是说会在内存中开辟一个新的内存空间!

Java中工厂模式经常使用newInstance()方法来创建对象,因此从为什么要使用工厂模式上可以找到具体答案。 例如:

class c = Class.forName(“Example”);

factory = (ExampleInterface)c.newInstance();

其中ExampleInterface是Example的接口,可以写成如下形式:

String className = "Example";

class c = Class.forName(className);

factory = (ExampleInterface)c.newInstance();

进一步可以写成如下形式:

String className = readfromXMlConfig;//从xml 配置文件中获得字符串

class c = Class.forName(className);

factory = (ExampleInterface)c.newInstance();

上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,只要他们继承ExampleInterface就可以。

从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:1、这个类已经加载;2、这个类已经连接了。而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。

现在可以看出,它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。

newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。 这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。

最后用最简单的描述来区分new关键字和newInstance()方法的区别:

newInstance: 弱类型。低效率。只能调用无参构造。

new: 强类型。相对高效。能调用任何public构造。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

fornName()和ClassLoader的loadClass方法
forName()是会执行 static 语句,因为默认情况它总是初始化这个被装载的类。

关于forName()方法:

这个方法总是返回要加载的类的Class类的实例

1、forName(String className)单参数时,initialize = true

(a).总是使用当前类的加载器(也就是装载执行forName()请求的类 的类的装载器);

(b).总数初始化这个被装载的类(当然也包括:装载、连接、初始化)。

2、forName(String className, boolean initialize,ClassLoader loader)

(a).loader指定装载参数类所用的类的装载器,如果null则用bootstrp装载器;

(b).initialize = true时,肯定连接,而且初始化了;

initialize = false时,绝对不会初始化,但是可能被连接了,但是这里有个例外,如果在调用这个forName()前,已经被初始化了(当然,这里也暗含着:className是被同一个loader所装载的,即被参数中的loader所装载的,而且这个类被初始化了),那么返回的类型也肯定是被初始化的。

关于用户自定义的类装载器的loadClass()方法:

1、loadClass(String name)单参数时,resolve = false

(a).如果这个类已经被这个类装载器所装载,那么,返回这个已经被装载的类型的Class的实例,否则,就用这个自定义的类装载器来装载这个class,这时不知道是否被连接,绝对不会被初始化;

(b).这时唯一可以保证的是,这个类被装载了。但是,不知道这个类是否被连接和初始化了。

2、loadClaa(String name, boolean resolve)

(a).resolve = true时,则保证已经装载,而且已经连接了。

resolve = false时,则仅仅是去装载这个类,不关心是否连接了,所以此时可能被连接了,也可能没有被连接。

另外:这里所谓的“初始化”是指类的初始化,即执行了className字节码的<clinit>方法。

再者,类的加载:

1、装载

2、连接

(a)验证 --> 检查类的格式等

(b)准备 --> 给类变量分配内存,并根据类的类型设置默认值(即内存中置0)

(c)解析 --> 常量池解析

3、初始化

即执行Java代码的字节码的<clinit>方法,给类变量赋予程序员需要的值

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: