《Java深度历险》读书笔记一
1.类加载器(ClassLoader)
Class.forName()有两种用法,一个是:public static Class<?> forName(String className) throws ClassNotFoundException
他等同于Class.forName(className,true,currentClassLoader);
另一种为:public static Class<?> forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException
下面分别说说这三种参数的意义:
name,要加载的类名
initialize,是否必须初始化类
loader,类加载器。手动调用时可以使用this.getClass().getClassLoader();
下面用代码说明:
注意红字部分,如果initialize为false,执行java -verbose Main Word
日志输出为:
如果initialize为true
看出区别来了吧,如果为true,当Word第一被加载的时候,Word就被初始化了(静态块中的内容被调用了),否则加载时不被初始化,只有等到实例化的时候再初始化,注意静态块是先于构造函数调用的。
2.类加载器加载顺序
如果再命令行输入:java xxx,执行顺序为:
a.找到JRE
b.找到jvm.dll
c.启动JVM,并进行初始化
d.产生BootstrapLoader
e.由BootstrapLoader载入ExtClassLoader
f.由BootstrapLoader载入AppClassLoader
g.由AppClassLoader载入xxx
这里比较有意思的是:AppClassLoader由BootstrapLoader载入,但是当调用他的getParent()方法时,却指向ExtClassLoader
因为ExtClassLoader和AppClassLoader都由BootstrapLoader(由C++编写)载入,所以调用他们的getLoader()方法时,返回null,BootstrapLoader不是Java内在类
3.AppClassLoader和ExtClassLoader都是由URLClassLoader继承而来的,所以要设定他们的URL。
AppClassLoader的URL是从系统属性“java.class.path”得到的。而java.class.path则是由执行java.exe是-cp或者-classpath(优先级高)或由CLASSPATH环境变量决定的。
所以默认他们都是从“.”,即当前目录开始查找。
ExtClassLoader是从“java.ext.dirs”系统属性中查找,即JRE所在位置下的"lib"ext子目录
我用System.out.println(System.getProperty("java.ext.dirs"))输出为:
C:"Java"jdk1.6.0_02"jre"lib"ext;C:"WINDOWS"Sun"Java"lib"ext
可以通过java -Djava.ext.dirs=c:"winnit Test来改变
而BootstrapLoader的搜索路径由"sun.boot.class.path"来确,却不能用java -D来改变。
Class.forName()有两种用法,一个是:public static Class<?> forName(String className) throws ClassNotFoundException
他等同于Class.forName(className,true,currentClassLoader);
另一种为:public static Class<?> forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException
下面分别说说这三种参数的意义:
name,要加载的类名
initialize,是否必须初始化类
loader,类加载器。手动调用时可以使用this.getClass().getClassLoader();
下面用代码说明:
public class Word implements Office { static { System.out.println("Word's Static Initialize"); } public void start() { System.out.println("Word"); } } |
interface Office { public void start(); } |
public class Main { public static void main(String[] args) throws Exception { if (args[0] != null) { Outlook off = new Outlook(); System.out.println("类别准备载入"); Class c = Class.forName(args[0],false,off.getClass().getClassLoader()); System.out.println("类别准备实例化"); Object o = c.newInstance(); Office office = (Office)o; office.start(); } } } |
注意红字部分,如果initialize为false,执行java -verbose Main Word
日志输出为:
[Loaded Office from file:/E:/MyJava/] [Loaded Outlook from file:/E:/MyJava/] 类别准备载入 [Loaded Word from file:/E:/MyJava/] 类别准备实例化 Word's Static Initialize Word |
如果initialize为true
[Loaded Main from file:/E:/MyJava/] [Loaded Office from file:/E:/MyJava/] [Loaded Outlook from file:/E:/MyJava/] 类别准备载入 [Loaded Word from file:/E:/MyJava/] Word's Static Initialize 类别准备实例化 Word |
看出区别来了吧,如果为true,当Word第一被加载的时候,Word就被初始化了(静态块中的内容被调用了),否则加载时不被初始化,只有等到实例化的时候再初始化,注意静态块是先于构造函数调用的。
2.类加载器加载顺序
如果再命令行输入:java xxx,执行顺序为:
a.找到JRE
b.找到jvm.dll
c.启动JVM,并进行初始化
d.产生BootstrapLoader
e.由BootstrapLoader载入ExtClassLoader
f.由BootstrapLoader载入AppClassLoader
g.由AppClassLoader载入xxx
这里比较有意思的是:AppClassLoader由BootstrapLoader载入,但是当调用他的getParent()方法时,却指向ExtClassLoader
因为ExtClassLoader和AppClassLoader都由BootstrapLoader(由C++编写)载入,所以调用他们的getLoader()方法时,返回null,BootstrapLoader不是Java内在类
3.AppClassLoader和ExtClassLoader都是由URLClassLoader继承而来的,所以要设定他们的URL。
AppClassLoader的URL是从系统属性“java.class.path”得到的。而java.class.path则是由执行java.exe是-cp或者-classpath(优先级高)或由CLASSPATH环境变量决定的。
所以默认他们都是从“.”,即当前目录开始查找。
ExtClassLoader是从“java.ext.dirs”系统属性中查找,即JRE所在位置下的"lib"ext子目录
我用System.out.println(System.getProperty("java.ext.dirs"))输出为:
C:"Java"jdk1.6.0_02"jre"lib"ext;C:"WINDOWS"Sun"Java"lib"ext
可以通过java -Djava.ext.dirs=c:"winnit Test来改变
而BootstrapLoader的搜索路径由"sun.boot.class.path"来确,却不能用java -D来改变。