美文网首页
从Class.forName()说起

从Class.forName()说起

作者: 我不懂我不懂a | 来源:发表于2020-01-11 17:40 被阅读0次

首先来看看我们初学jdbc连接数据库时的demo:

        //注册mysql驱动
        Class.forName("com.mysql.jdbc.Driver");
        //建立数据库对象
        Connection conn  = DriverManager.getConnection(url, user, password);
        //建立操作对象
        Statement stmt= conn.createStatement();
        //结果集
        ResultSet rs = stmt.executeQuery("select * from test");

其中的Class.forName(driver)被我们叫做注册mysql的驱动。
问题来了,为什么这句话就是注册驱动了? 为了理解这个问题,我们需要了解一下:

  • Class.forName的作用是什么?
  • 了解com.mysql.jdbc.Driver类

了解Class.forName()

jdk8 Class
从文档上我们知道,Class.forName通过一个类的全限定名可以加载并初始化类。

继续,我们需要了解类的加载过程。


图来源:百度图片

类的加载过程包括:加载-验证-准备-解析-初始化。

《深入理解Java虚拟机 2》中第七章 虚拟机加载机制 中介绍到有且只有5种情况必须对类进行“初始化”,称为主动引用。除此之外,都不会触发初始化,称为被动引用。

详细的内容后面会介绍,看了书就知道,Class.forName()属于主动引用的场景,所以会触发类的初始化。
那么,类的初始化做了什么?
ps:有一点要注意,类的初始化并不是Test test = new Test();。new Test()执行了实例构造器<init>()方法,类的实例化是执行了类的构造器<clinit>()方法
从定义上看:<clinit>() 方法是由编译器自动收集所有类变量的赋值动作和静态语句块(static{})中的语句合并产生的。
所以类的初始化会执行static变量以及static{}中的语句,初始化子类前必须先初始化父类。
看个实例:

public class ClassForNameExp1 {
    //静态代码块
    static {
        System.out.println("执行了静态代码块");
    }
    //静态变量
    private static String staticFiled = staticMethod();

    //赋值静态变量的静态方法
    public static String staticMethod(){
        System.out.println("执行了静态方法");
        return "给静态字段赋值了";
    }

    public ClassForNameExp1(){
        System.out.println("执行了构造函数");
    }
}


public class ClassForName {
    public static void main(String[] args) throws ClassNotFoundException {
        Class.forName("reflect.ClassForNameExp1");
    }
}

>执行结果:

执行了静态代码块
执行了静态方法

可以看出来只执行了静态变量和静态代码块。

了解com.mysql.jdbc.Driver类

看源代码:

package com.mysql.jdbc;

import java.sql.DriverManager;
import java.sql.SQLException;

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());  //重点
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}


public class DriverManager {
    // List of registered JDBC drivers
    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();

    public static synchronized void registerDriver(java.sql.Driver driver)
        throws SQLException {

        registerDriver(driver, null);  
    }

    public static synchronized void registerDriver(java.sql.Driver driver,
            DriverAction da)
        throws SQLException {

        /* Register the driver if it has not already been added to our list */
        if(driver != null) {
            registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
        } else {
            // This is for compatibility with the original DriverManager
            throw new NullPointerException();
        }

        println("registerDriver: " + driver);

    }
}

Dirver类的static{}方法的作用 是将自己实例化后添加进DriverManager的注册驱动队列里。
真相大白了。

附:类的主动引用及被动引用

暂未编写,阅读《深入理解Java虚拟机 2》中第七章-虚拟机加载机制章节。

相关文章

网友评论

      本文标题:从Class.forName()说起

      本文链接:https://www.haomeiwen.com/subject/bhqbactx.html