提到这个问题就不得不说一下类加载器和双亲委派机制。

类加载器: 从Java虚拟机的角度来看,只存在两种不同的类加载器:一种是启动类加载器,一种是继承抽象类java.lang.ClassLoader的。

启动类加载器(引导类加载器)Bootstrap ClassLoader: 由C/C++语言实现,该类加载器用于加载Java的核心库,用于提供JVM自身需要的类(加载包名为java、javax、sun等开头的)。 并不继承java.lana.ClassLoader,没有父加载器。为扩展类加载器和应用程序类加载器的父类加载器(这里的父类不指继承,请不要混淆)。

扩展类加载器Extension ClassLoader: 由Java语言编写,派生于ClassLoader类,父类加载器为启动类加载器(再次强调,此处的父类不指继承)。从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建发JAR放在此目录下,也会自动由扩展类加载器加载。

应用程序类加载器(系统类加载器)Application ClassLoader: 由Java语言编写,派生于ClassLoader类,父类加载器为启动类加载器。它负责加载环境变量classpath或系统属性java.class.path指定路径下的类库。

双亲委派机制: 如果一个类加载器收到了类加载的请求,它不会自己加载,而是向上委托,让父类加载器去加载,每一层都如此,直到达到顶层。只有当父类加载器反馈自己无法完成加载请求,子类加载器才会尝试自己去加载,如果子类也加载不到,将报ClassNotFoundException异常。

image.png

到此,回归正题,为什么自定义的String不会被加载?

当自己定义了一个 String类,且包名也是java.lang,为什么不会被加载,因为双亲委派机制,当加载String类时,会一层一层的往上委托,直到在启动类加载器Bootstrap ClassLoader,而启动类加载器能够加载String类,因为在java包下有,所以加载的是Java中的String,而不是自定义的。

同理为什么自定义java.lang包下的类会报java.lang.SecurityException: Prohibited package name: java.lang,因为java包该由启动类加载器加载,但在该包下没有这个类,那就可能是有恶意行为,所以报出安全异常。

image.png