forName、new和ClassLoader方法的比较

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字节码的方法。

再者,类的加载:

1、装载

2、连接

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

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

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

3、初始化

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

你可能感兴趣的:(概念)