虚拟机加载类的途径
1 由 new 关键字创建一个类的实例
在由运行时刻用 new 方法载入
如: Dog dog = new Dog();
2 调用 Class.forName() 方法
通过反射加载类型, 并创建对象实例
如: Class clazz = Class.forName(Dog);
Object dog =clazz.newInstance();
3 调用某个 ClassLoader 实例的 loadClass() 方法
通过该 ClassLoader 实例的 loadClass() 方法载入应用程序可以通过继承 ClassLoader 实现自己的类装载器
如: Class clazz = classLoader.loadClass(Dog);
Object dog =clazz.newInstance();
三者的区别:
1 和 2 使用的类加载器是相同的, 都是当前类加载器 (即: this.getClass.getClassLoader)3 由用户指定类加载器如果需要在当前类路径以外寻找类, 则只能采用第 3 种方式第 3 种方式加载的类与当前类分属不同的命名空间另外, 1 是静态加载, 23 是动态加载
两个异常 (exception)
静态加载的时候如果在运行环境中找不到要初始化的类, 抛出的是 NoClassDefFoundError, 它在 JAVA 的异常体系中是一个 Error
动态态加载的时候如果在运行环境中找不到要初始化的类, 抛出的是 ClassNotFoundException, 它在 JAVA 的异常体系中是一个 checked 异常
Class.forName 与 ClassLoader.loadClass 区别
Class 的装载包括 3 个步骤: 加载 (loading), 连接 (link), 初始化 (initialize).
Class.forName(className) 实际上是调用 Class.forName(className, true, this.getClass().getClassLoader()) 第二个参数, 是指 Class 被 loading 后是不是必须被初始化
ClassLoader.loadClass(className) 实际上调用的是 ClassLoader.loadClass(name, false), 第二个参数指 Class 是否被 link
Class.forName(className) 装载的 class 已经被初始化, 而 ClassLoader.loadClass(className) 装载的 class 还没有被 link 一般情况下, 这两个方法效果一样, 都能装载 Class 但如果程序依赖于 Class 是否被初始化, 就必须用 Class.forName(name) 了
例如, 在 JDBC 编程中, 常看到这样的用法, Class.forName(com.mysql.jdbc.Driver).
如果换成了 getClass().getClassLoader().loadClass(com.mysql.jdbc.Driver), 就不行
com.mysql.jdbc.Driver 的源代码如下:
- // Register ourselves with the DriverManager
- static {
- try {
- java.sql.DriverManager.registerDriver(new Driver());
- } catch (SQLException E) {
- throw new RuntimeException(Cant register driver!);
- }
- }
原来, Driver 在 static 块中会注册自己到 java.sql.DriverManager 而 static 块就是在 Class 的初始化中被执行
所以这个地方就只能用 Class.forName(className)
来源: http://www.bubuko.com/infodetail-2522051.html