引言

如果熟悉使用JDBC来连接数据库的同学一定很清楚连接数据库的代码中一定会有依据Class.forName

("com.mysql.jdbc.Driver");  public static Connection getConnection() throws ClassNotFoundException, SQLException {    if(connection == null){      Class.forName("com.mysql.jdbc.Driver");      connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx?serverTimezone=UTC", "root", "xxxxxx");    }    return connection;  }

类加载机制

在这之前我们先来说下Java中的类加载机制。

在Java中如果想要使用一个类,则必须要求该类已经被加载到Jvm中,加载的过程实际上就是通过类的全限定名来获取定义该类二进制字节流,然后将这个字节流所表示的静态存储结构转换为方法去的动态运行时数据结构。同时在在内存中实例化一个java.lang.Class对象,作为方法区中该类的数据访问入口(供我们使用)。

而会触发类加载的会有如下几种情况(引用自<<深入理解Java虚拟机>>):

1.遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令的最常见的Java代码场景是:使用new关键字实例化对象的时候、读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。

2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。

3.当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

4.当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。

Class.forName

在Java官方文档中对Class.forName的解释为在运行时动态的加载一个类,返回值为生成的Class对象。

那么很明显在jdbc中使用Class.forName("com.mysql.jdbc.Driver");仅仅就是将com.mysql.jdbc.Driver类加载到Jvm中了,这个原因大多数人应该都知道。

但是我们要知道Class.forName貌似只是对类进行了加载,我们甚至都没有对返回的Class对象做任何操作,那么我们为什么后面就可以直接用了呢?

首先看Class.forName调用了native方法forName0(...);

@CallerSensitivepublic static Class<?> forName(String className)      throws ClassNotFoundException {  Class<?> caller = Reflection.getCallerClass();  return forName0(className, true, ClassLoader.getClassLoader(caller), caller);}private static native Class<?> forName0(String name, boolean initialize,ClassLoader loader,Class<?> caller);

初始化过程实际上就是对变量赋值(不是赋初值,不会调用构造函数)的过程。包含所有类变量的赋值以及静态代码语句块的执行代码,包括对父类的初始化。

再看com.mysql.jdbc.Driver驱动类:

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!");    }  }}

其他加载类方法

我们需要明白的是在Java中并不是只有通过Class.forName()才能显示的加载类。那么为什么不使用其他的加载方法而偏偏选择Class.forName()呢?

ClassLoader.getSystemClassLoader().loadClass()

通过类加载器也可以将一个类加载到Jvm中。通过ClassLoader.getSystemClassLoader().loadClass("com.mysql.jdbc.Driver");也可以加载驱动类。

但是如果我们深入看下loadClass的实现:

public Class<?> loadClass(String name) throws ClassNotFoundException {  return loadClass(name, false);}protected Class<?> loadClass(String name, boolean resolve);

所以如果使用这种加载类方式的话理论上来说是没发使用该驱动类的。

new关键字

也可以使用new关键字进行加载操作,在使用new关键字时会查看该类是否已经被加载,如果没有被加载的话则会进行加载操作。所以我们的类中也可以这样写:

public static Connection getConnection() throws ClassNotFoundException, SQLException {  if(connection == null){    new Driver();//会自动调用静态代码块    connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx?serverTimezone=UTC", "root", "xxxx");  }  return connection;}

可以不使用Class.forName("com.mysql.jdbc.Driver")

在测试的过程中发现即使不显示的使用Class.forName("com.mysql.jdbc.Driver")也能够连接到数据库,一时间觉得很奇怪。

深入跟踪代码后发现实际上只要我们引入了mysql的驱动包,那么在使用时会根据驱动包下提供的配置文件默认的创建一个类。

所以实际上只要引入了该驱动包,那么使用jdbc是可以直接通过DriverManage来获取连接。

public static Connection getConnection() SQLException {  return DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx?serverTimezone=UTC", "root", "xxxxxx");}

更多相关文章

  1. Android下Excel的操作
  2. 【Android】文件读写操作(含SDCard的读写)
  3. android 百度地图3.0+常用操作
  4. 转:Android下文件操作模式(含SDCard的读写)
  5. android音频、视频、拍照基础操作
  6. Android之再谈文件操作和SDcard读写
  7. android的文件操作。(未整理完成)
  8. Android中Activity之间访问互传参数
  9. 转:Android之通信录中的联系人操作

随机推荐

  1. 5、frida进阶-Android逆向之旅---Hook神
  2. 常用知识篇 一 Selector state状态对应说
  3. 二十四、Android文件的读写
  4. Android开发之获取手机网络状态及网络是
  5. [Android] TextView只显示一行,多余显示
  6. android 绘图时抗锯齿方法两种
  7. android开发经典网站
  8. J2ME游戏只移植到Android平台(一)
  9. EventBus 《二》 Android EventBus的简单
  10. Android之SQLite 学习一