对于大部分人来说,第一次见到 class.forName(String className) 这句代码应该是在使用 JDBC 方式连接数据库的时候。
实例
import com.mysql.jdbc.Driver;
import java.sql.*;
public class JdbcDemo {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
String url = "jdbc:mysql://127.0.0.1:3306/mydb";
String username = "root";
String password = "redhat";
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection(url, username, password);
String sql = "SELECT * FROM msg";
PreparedStatement prepareStatement = connection.prepareStatement(sql);
ResultSet resultSet = prepareStatement.executeQuery();
resultSet.next();
String address = resultSet.getString("address");
System.out.println(address);
}
}
Class.forName 传入 com.mysql.jdbc.Driver 之后,就知道我连接的数据库是 mysql,这是为什么呢,看看源代码:
@CallerSensitive
public static Class<?> forName(String className) throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
发现它调用了 forName0 方法,继续跟踪再看看:
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
native 方法,源码也只能到此结束了。再看看看官方文档的描述:https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#forName(java.lang.String)
Returns the Class object associated with the class or interface with the given string name, using the given class loader. Given the fully qualified name for a class or interface (in the same format returned by getName) this method attempts to locate, load, and link the class or interface. The specified class loader is used to load the class or interface. If the parameter loader is null, the class is loaded through the bootstrap class loader. The class is initialized only if the initialize parameter is true and if it has not been initialized earlier.
大概翻译一下就是:返回一个给定类或者接口的一个 Class 对象,如果没有给定 classloader, 那么会使用根类加载器。如果 initalize 这个参数传了 true,那么给定的类如果之前没有被初始化过,那么会被初始化。我们在 JDBC 第一步的时候,传入的参数是 com.mysql.jdbc.Driver。也就是说这个类会被初始化,我们看一下这个类里面的内容:
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
public Driver() throws SQLException {
}
}
我们发现这个类也是超级简单的。一个构造函数和一个静态代码块。我们知道,类在初始化的时候,静态代码块的内容会被执行的。也就是说我们 Class.forName 和直接写 DriverManager.registerDriver(new Driver) 两者功能是等同的。我们换成这种写法,再试试看:
public class JdbcDemo {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
String url = "jdbc:mysql://127.0.0.1:3306/mydb";
String username = "root";
String password = "redhat";
DriverManager.registerDriver(new Driver());
Connection connection = DriverManager.getConnection(url, username, password);
String sql = "SELECT * FROM msg";
PreparedStatement prepareStatement = connection.prepareStatement(sql);
ResultSet resultSet = prepareStatement.executeQuery();
resultSet.next();
String address = resultSet.getString("address");
System.out.println(address);
}
}
发现代码,还是正常的执行了。
总结一下:
Class.forName 方法的作用,就是初始化给定的类。而我们给定的 MySQL 的 Driver 类中,它在静态代码块中通过 JDBC 的 DriverManager 注册了一下驱动。我们也可以直接使用 JDBC 的驱动管理器注册 mysql 驱动,从而代替使用 Class.forName。
原文地址:http://linuxsogood.org/1580.html
CTCE
112***24@qq.com
参考地址
理解 Class.forName()
Class 类概念
Class 也是一个 Java 类,保存的是与之对应 Java 类的 meta信息(元信息),用来描述这个类的结构,比如描述一个类有哪些成员,有哪些方法等,一般在反射中使用。
详细解释:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例(Class 对象)。也就是说,在 Java 中,每个 java 类都有一个相应的 Class 对象,用于表示这个 java 类的类型信息。
类加载概念
当使用一个类的时候(比如 new 一个类的实例),会检查此类是否被加载到内存,如果没有,则会执行加载操作。
读取类对应的 class 文件数据,解析此数据,构造一个此类对应的 Class 类的实例。此时JVM就可以使用该类了,比如实例化此类,或者调用此类的静态方法。
Java 也提供了手动加载类的接口,class.forName()方法就是其中之一。(说来说去,其实就是生成这个类的 Class)
类加载器的概念
顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class 类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance() 方法就可以创建出该类的一个对象。 基本上所有的类加载器都是 java.lang.ClassLoader 类的一个实例。
类初始化概念
类被加载之后,jvm 已经获得了一个描述类结构的 Class 实例。但是还需要进行类初始化操作之后才能正常使用此类,类初始化操作就是执行一遍类的静态语句,包括静态变量的声明还有静态代码块。
Class.forName() 方法
此方法含义是:加载参数指定的类,并且初始化它。
在 jdbc 连接数据库中的应用
到这里,不用解释,读者也会明白,在使用 jdbc 方式连接数据库时,为什么要执行 Class.forName('驱动类名') 方法了:将驱动类的 class 文件装载到内存中,并且形成一个描述此驱动类结构的 Class 类实例,并且初始化此驱动类,这样 jvm 就可以使用它了,这就是 Class.forName() 方法的含义。
有数据库开发经验朋友会发现,为什么在我们加载数据库驱动包的时候有的却没有调用 newInstance() 方法呢?即有的 jdbc 连接数据库的写法里是 Class.forName(xxx.xx.xx);而有一 些:Class.forName(xxx.xx.xx).newInstance(),为什么会有这两种写法呢?
刚才提到,Class.forName(""); 的作用是要求 JVM 查找并加载指定的类,如果在类中有静态初始化器的话,JVM 必然会执行该类的静态代码 段。而在 JDBC 规范中明确要求这个 Driver 类必须向 DriverManager 注册自己,即任何一个 JDBC Driver 的 Driver 类的代码都必须类似如下:
既然在静态初始化器的中已经进行了注册,所以我们在使用 JDBC 时只需要 Class.forName(XXX.XXX); 就可以了。
CTCE
112***24@qq.com
参考地址
方子
465***234@qq.com
参考地址
Class.forName() 与 xxx.class的区别
所有的类都是在对其第一次使用时,动态加载到 JVM。当程序创建第一个对类的静态成员的引用时,就会加载这个类。这也证明了构造器也是类的静态方法,即使在构造器之前并没有 static 关键字。因此,使用 new 操作符创建类的对象也会被当作对类的静态成员的引用。
因此 Java 程序在他开始运行之前并非被完全加载,其各个部分是在需要时才加载的。
类加载器首先槛车这个类的 Class 对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名称查找 .class 文件。在这个类的字节码被加载时,它们会接收验证,以确保其没有被破坏。
Class 对象尽在需要的时候才被加载。static 初始化是在类加载时进行的。
对于 Class.forName(),这个方法是 Class 类的一个 static 成员。Class 对象就和其他对象一样,我们可以获取并操作他的引用。forName() 是取得 Class 对象引用的一种方法。他是用一个包含目标类的文本名的 String 作为输入参数,返回一个 Class 对象的引用。forName() 方法发现某个累还没被加载,就会主动去加载这个类,在加载过程中,该类的是 static 子句将会被执行。Java 还提供了另一种方法来生成对 Class 对象的引用,即使用类字面常量。形如:xxx.class 的形式。但是这种形式创建 Class 对象引用时,不会自动初始化 Class 对象。初始化被延迟到了对静态方法或者非常数静态域首次引用时才执行。
执行输出结果:
从对 initable 引用的创建中可以看到,仅使用 .class 语法来获取对类的引用不会发生初始化。但是 Class.forName() 立即就进行了初始化。如果一个 static final 值是“编译期常量”,就像 Initable.staticFinal 那样,那么这个值不需要对 Initable 类进行初始化就可以被读取。但是如果只是将一个域设置为 static 和 final 的,还不足以确保这种行为,例如 Initable.staticFianl2 的访问将强制进行类型的初始化,因为他不是一个编译器常量。
方子
465***234@qq.com
参考地址