经典回顾Class.forName()

 

Class.forName(xxx.xx.xx) 返回的是一个类[Class], .newInstance() 后才创建一个对象[Object] Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段

 

Class aClass = Class.forName(xxx.xx.xx);
Object anInstance = aClass.newInstance();


Class.forName("").newInstance()返回的是object
but there is some limit for this method to create instance
that is your class constructor should no contain parameters, and you should cast the instance manually.

Class Driver{
protected static Driver current;
public static Driver getDriver(){
return current;
}
}

Class MyDriver extends Driver{
static{
Driver.current=new MyDriver();
}
MyDriver(){}
}

用时:
Class.forName("MyDriver");
Driver d=Driver.getDriver();

有的jdbc连接数据库的写法里是Class.forName(xxx.xx.xx);而有一些:Class.forName(xxx.xx.xx).newInstance(),为什么会有这两种写法呢?

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

Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段

在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBC Driver的Driver类的代码都必须类似如下:
public class MyJDBCDriver implements Driver {
static {
DriverManager.registerDriver(new MyJDBCDriver());
}
}

所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了

we just want to load the driver to jvm only, but not need to user the instance of driver, so call Class.forName(xxx.xx.xx) is enough, if you call Class.forName(xxx.xx.xx).newInstance(), the result will same as calling Class.forName(xxx.xx.xx), because Class.forName(xxx.xx.xx).newInstance() will load driver first, and then create instance, but the instacne you will never use in usual, so you need not to create it.

在JDBC驱动中,有一块静态代码,也叫静态初始化块,它执行的时间是当class调入到内存中就执行(你可以想像成,当类调用到内存后就执行一个方法)。所以很多人把jdbc driver调入到内存中,再实例化对象是没有意义的。

 

Class clazz = Class.forName("XXX.XXX");

ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class clazz = cl.loadClass("XXX.XXX");
都可以装载一个类那么他们的区别是什么呢?
进一步研究Class.forName()是调用
Class.forName(name, initialize, loader);也就是Class.forName("XXX.XXX"); 等同与Class.forName("XXX.XXX", true, CALLCLASS.class.getClassLoader());

第二次参数表示装载类的时候是否初始化该类, 即调用类的静态块的语句及初始化静态成员变量。

Class clazz = cl.loadClass("XXX.XXX");没有指定是否初始化的选项。只有执行clazz.newInstance();时才能够初始化类。可以说Class.forName("XXX.XXX", false, cl)执行过程是一致的。只是ClassLoader.loadClass()是更底层的操作。

看一下JDBC驱动的装载。
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbcurl");
当调用Class.forName("com.mysql.jdbc.Driver");是Driver已经被初始化并注册到DriverManager中。MySQL Driver的代码
public class Driver extends NonRegisteringDriver
     implements java.sql.Driver
{

     public Driver()
         throws SQLException
     {
     }

     static
     {
         try
         {
             DriverManager.registerDriver(new Driver());
         }
         catch(SQLException E)
         {
             throw new RuntimeException("Can't register driver!");
         }
     }
}
改修JDBC驱动的装载
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class clazz = cl.loadClass("com.mysql.jdbc.Driver");
clazz.newInstance();
Connection conn = DriverManager.getConnection("jdbcurl");
同样可以执行。但是这样就多构造了一个com.mysql.jdbc.Driver实例。同Class.forName("com.mysql.jdbc.Driver").newInstance()是一样的。是没有任何意义的。

 

类名.class是Class对象的句柄,每个被加载的类,在jvm中都会有一个Class对象与之相对应,如果要创建新的对象,直接使用Class对象的局部class.forName就可以了,不需要用new       类名。


在java中,每个class都有一个相应的Class对象,当编写好一个类,编译完成后,在生成的.class文件中,就产生一个class对象,用来表示这个类的类型信息。获得Class实例的三中方式:
1.利用对象调用getClass()方法获取该对象的Class实例
2.使用Class的静态方法forName(),用类的名字获取一个Class实例
3.运用.calss的方式获取Class实例,对基本数据类型的封装类,还可以采用.TYPE来获取对应的基本数据类型的Class实例

calss ClassTest
{
                public static void main(String[] args)
                {
                        /*
                        //利用对象调用getClass()方法获取该对象的Class实例
                        Point pt=new Point();                
                        Class c1=pt.getClass();
                        System.out.println(c1.getName());                        //结果:Point
                
                        //使用Class的静态方法forName(),用类的名字获取一个Class实例
                        try
                        {
                                Class c2=Class.forName("Point");
                                System.out.println(c2.getName());                //结果:Point
                        }
                        catch(Exception e)
                        {
                                e.printStackTrace();
                        }

                        //运用.calss的方式获取Class实例(类)
                        Class c3=Point.calss;
                        System.out.println(c3.getName());                        //结果:Point

                        //运用.calss的方式获取Class实例(基本类型)
                        Class c4=int.calss;
                        System.out.println(c4.getName());                        //结果:int

                        //运用.calss的方式获取Class实例(基本数据类型的封装类)
                        Class c5=Integer.TYPE;
                        System.out.println(c5.getName());                        //结果:int
                
                        Class c6=Integer.class;
                        System.out.println(c6.getName());                        //结果:java.lang.Integer
                        */
                
                        //以下结果是:          before new Point()
                                        loading point
                                        after new Point()
                                        loading Line        
                        //当new Point()的时候加载这个类,用forName构造实例的时候也加载该类。
                        System.out.println("before new Point()");
                        new Point();
                        System.out.println("after new Point()");

                        try
                        {
                                Class.forName("Line");
                        }catch(Exception e)
                        {
                                e.printStackTrace();
                        }
                
                }
}
class Point()
{
                static
                {
                        System.out.println("loading point");
                }
                int x,y;
}
class Line
{
                static
                {
                        System.out.println("loading Line");
                }
}

在运行期间,如果我们要产生某个类的对象,java虚拟机会检测该类型的Class对象是否已被加载。如果没有加载,java虚拟机会根据类的名称找到.class文件并加载它。一旦某个类型的Class对象已经被加载到内存,就可以用它来产生该类型的所有对象。
newInstance()调用内中缺省的构造方法。

newInstance()调用类中缺省的构造方法,如果要实例的对象中有了自己定义的构造方法(除重写的和默认构造方法相同的构造方法外)


posted @ 2009-08-31 09:14  William Zhao  阅读(148)  评论(0编辑  收藏  举报