java中类加载器有三种:
- Bootstrap类加载器 负责加载java的核心类包,比如rt.jar
- 拓展类加载器 负责加载java的拓展类包
- 应用类加载器 负责加载我们项目classpath下的类
假如我们自定义了一个java.lang.Test的类,尝试查看哪个类加载器会加载这个类?
public static void main(String[] args) {
Test test = new Test();
ClassLoader classLoader = test.getClass().getClassLoader();
System.out.println(classLoader);
}
Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:662)
at java.lang.ClassLoader.defineClass(ClassLoader.java:761)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at TestClazz.main(TestClazz.java:11)
可见这种自定义的用java开头的包名是不能被类加载器加载的。
问题,那为什么java的核心类包里的类可以被加载呢?java.lang.String怎么就不报异常呢?原因很简单,因为java.lang.String类使用到的类加载器是BootStrap类加载器,不会有这个校验,我们自定义的类java.lang.Test即使要去被加载,也由于处于我们classpath下,最后尝试去加载它的是我们的应用类加载器,而应用类加载器加载类的时候会有下面的一个校验方法
private ProtectionDomain preDefineClass(String name,ProtectionDomain pd){
if (!checkName(name))
throw new NoClassDefFoundError("IllegalName: " + name);
// 这里会校验类名不能是java.开头的
if ((name != null) && name.startsWith("java.")) {
throw new SecurityException
("Prohibited package name: " +
name.substring(0, name.lastIndexOf('.')));
}
if (pd == null) {
pd = defaultDomain;
}
if (name != null) checkCerts(name, pd.getCodeSource());
return pd;
}
可见应用类加载器在加载类时候,不能加载java.开头的类,所以尝试加载上述自定义的类会抛出异常。
***************************************分割线************************************
那假如我们定义一个java.lang.String类,会有什么后果呢,这个类是核心类包中已经有的类了。
public static void main(String[] args) {
java.lang.String test = new String();
ClassLoader classLoader = test.getClass().getClassLoader();
System.out.println(classLoader);
}
运行结果时null,表名是bootstrap类加载器,并且加载的是核心类包里的String类,并不是自己定义的这个,可见即使自己定义了核心类包里的同名类,最后的结果是类加载器会加载核心类包里的,自己定义的不会被加载。
网友评论