1、类加载器双亲委托模型的好处
- 1、可以确保java核心库的类型安全:所有的java应用都至少会引用java.lang.Object类,也就是说在运行期,这个类会被加载到虚拟机中;如果这个加载过程是由自定义类加载器所完成的,那么很可能就会在jvm中存在多个版本的Object类,而且这些类之间还是不兼容的,相互不可见的(是因为命名空间)。借助于双亲委托机制,java核心类库中的加载动作都是由启动类加载器来统一完成加载工作,从而保证了java应用所使用的都是同一个版本的java核心类,他们之间是相互兼容的。
- 2、可以确保java核心类库所提供的类不会被自定义的类所替代。
- 3、不同的类加载器可以为相同名称的类创建额外的命名空间。相同名称的类可以并存在java虚拟机中,只需要用不同的类加载器来加载他们即可。不同类加载器所加载的类是不见兼容的。这就相当于在java虚拟机内部创建了一个又一个相互隔离的java类空间,这类技术在很多框架中都得到了实际应用。
2、扩展类加载器的加载
扩展类加载器只能加载jar包中的class文件,不能直接去加载class文件。也就是说class文件必须打成jar包。
测试,建包:C:\Windows\Sun\Java\lib\ext
,这是十六当中的一个扩展类加载器加载的包,将com\jvm\classloader
包以及里面的User.class文件打成jar包,放入新建的包中。
public class MyTest22 {
static {
System.out.println("MyTest22 initializer");
}
public static void main(String[] args) {
System.out.println(MyTest22.class.getClassLoader());
System.out.println(User.class.getClassLoader());
}
}
运行结果:
MyTest22 initializer
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2
如果不以jar包的形式放进去的话,只是单纯的把com\jvm\classloader
包结构以及User.class文件放进去,则结果为:
MyTest22 initializer
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2
3、根类加载器的加载
如果把根类加载器的加载路径换了,则直接报错,因为肯定找不到Object类的class文件。
4、类加载器是由谁来加载的呢
当jvm启动时,一块特殊的机器码会运行,他会加载扩展类加载器和系统类加载器,这块特殊的机器码叫做启动类加载器(BootStrap)。
启动类加载器不是java类,其他加载器都是java类。启动类加载器是特定于平台的及其指令,他负责开启整个的加载过程。
所有的类加载器(除了启动类加载器)都被实现为java类。不过,总归有一个组件来加载第一个java类加载器,从而让整个加载过程能够顺利进进行下去,加载第一个纯java类加载器就是启动类加载器的职责。
启动类加载器还会负责加载供JRE正常运行所需要你的基本组件,这包括java.util与java.lang包中的类等等。
public class MyTest22 {
public static void main(String[] args) {
System.out.println(ClassLoader.class.getClassLoader());
System.out.println(Launcher.class.getClassLoader());
}
}
appclassloader和extclassloader都是定义在Launcher中的内部类,所以可以观察Launcher的加载器来确定那两个类的加载器。
可以看到,确实是由根加载器加载的。
5、可以设置系统类加载器
ClassLoader.getSystemClassLoader()
的文档:
Returns the system class loader for delegation. This is the default delegation parent for new ClassLoader instances, and is typically the class loader used to start the application.
This method is first invoked early in the runtime’s startup sequence, at which point it creates the system class loader and sets it as the context class loader of the invoking Thread.
The default system class loader is an implementation-dependent instance of this class.
If the system property “java.system.class.loader” is defined when this method is first invoked then the value of that property is taken to be the name of a class that will be returned as the system class loader. The class is loaded using the default system class loader and must define a public constructor that takes a single parameter of type ClassLoader which is used as the delegation parent. An instance is then created using this constructor with the default system class loader as the parameter. The resulting class loader is defined to be the system class loader.
If a security manager is present, and the invoker’s class loader is not null and the invoker’s class loader is not the same as or an ancestor of the system class loader, then this method invokes the security manager’s checkPermission method with a RuntimePermission(“getClassLoader”) permission to verify access to the system class loader. If not, a SecurityException will be thrown.