Class.forName解析以及使用

这个类在刚学习Java连接数据库的时候见到这个这种写法,并且工作这么多年,也许是接触的东西比较少,这种用法也就只有在自己手写数据库连接代码的时候见过,在其他的时候还真是没见过。

在Class类中,对此方法有如下声明

方法重载了三次。

查看第一个forName方法的声明为:

@CallerSensitive
public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

首先在这个方法中,使用到了Reflection.getCallerClass(),返回是调用者对象

针对getCallerClass这个方法,这个方法是native的,声明如下:

@CallerSensitive
public static native Class getCallerClass();

由于是native方法,就暂时不跟进去了,这个方法的意思返回调用者 class对象),也就是说是谁调用调用了我这个类的方法。如下示例:

public class ReflectionCaller {
    public static void main(String[] args) {
        InnerClass i = new InnerClass();
        i.innerMethod();
    }
}

class InnerClass {
    public void innerMethod() {
        System.out.println(Reflection.getCallerClass());
    }
}

运行以上代码,输出的结果是:

190655_89of_2457218.png

也就是ReflectionCaller这个类对象。这个方法还是比较有趣的,如果在以后我们自己写代码的时候,想知道谁在调用我这些的这些方法,就可以跟踪出来了。

获取调用者信息以后,会调用Class.forname0方法,进行加载和初始化类。看到forname0这个方法又是一个native方法。

private static native Class<?> forName0(String name, boolean initialize,
                                        ClassLoader loader,
                                        Class<?> caller)
    throws ClassNotFoundException;

这个方法的作用是根据name加载传递过来的类,并且根据initialize来决定是否要进行初始化,所谓初始化指的是加载里面的静态块之类的。加载的时候采用caller相同的类加载器记性加载。

 

从中可以看出Class.forName和Classloader.lodeclass的区别是什么,Class.forName可以加载类并且控制是否要对类进行初始化,而ClassLoader.loadClass只对类进行加载,不进行初始化。

 

知道了Class.forName 的作用,那接下来就看一下针对连接mysql的具体问题。

根据第一节,可以看到连接字符串为:

Class.forName("com.mysql.jdbc.Driver");

也就是说会加载com.mysql.jdbc.Driver这个类,并且进行初始化。找到mysql-connector-java.jar的源码,这个类非常简单。

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    //
    // Register ourselves with the DriverManager
    //
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

    /**
     * Construct a new driver and register it with DriverManager
     * 
     * @throws SQLException
     *             if a database error occurs.
     */
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}

这个类中 就一个静态块和一个无参的构造函数,通过静态块的内容可以看出,实例了的一个Driver,然后注册到DriverManagerDriverManager把这个Driver存储到了一个CopyOnWriteArrayList中。

同时Driver还继承了AbandonedConnectionCleanupThread这个类,这个类继承Thread,启动一个守护线程,然后清理废弃的类对象。

以上就是我们在连接mysql时,Class.forName的功能。但是需要注意的是
Java 的SQL框架允许多个数据库的Driver,每一个Driver都要实现java.sql.Driver接口,针对给出来的连接数据库的请求,DriverManager尝试去load尽可能多的它找到的drivers,然后根据这些driver尝试使用给出来的数据库连接字符串去尝试连接数据库。
在mysql的NonRegisteringDriver中强烈建议,每个驱动程序类应该尽可能的小和独立,这样在加载和查询驱动类的时候,才不会引入大量的支持代码。

 

转载于:https://my.oschina.net/u/2457218/blog/818082

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值