我们可以自定义一个Java.lang.String吗?

我们可以自定义一个Java.lang.String吗?

笔者在面试阿里java开发的时候,面试官问到了我可以自定义一个java.lang.String吗?但是没反应过来,实际考察的是类加载机制-双亲委派机制。
在JDK中内置了很多类,我们能否自己写一个类去“覆盖”这些内置的类呢?
(正常手段下)不能!

Talk is cheap. Show me the code,以下我们尝试自己在src中编写一个java.lang.String,用于“覆盖”JDK中的String。

自己在src中编写的java.lang.String源码如下所示(包名和类名都与jdk中的String一致)
我们可以自定义一个Java.lang.String吗?_第1张图片但在运行时,会报以下异常:
我们可以自定义一个Java.lang.String吗?_第2张图片异常提示:在类 java.lang.String 中找不到 main 方法。

why?

why?

why?

因为我们的JVM设计者早就想到了这种情况,担心哪个核心类不小心被你碰巧给重名了,造成运行时的诡异错误。为此(当然还有其他原因),JVM内部存在着一个名为“双亲委派”的机制。

双亲委派是JVM在加载类时所遵循的一个机制。简单的说,就是当一个加载器要加载类的时候,自己先不加载,而是逐层向上交由双亲(类似于父亲)去加载;当双亲中的某一个加载器 加载成功后,再向下返回成功。如果所有的双亲和自己都无法加载,则报异常。一句话总结:加载器的层次越高,执行的优先级就越高。
双亲委托中各个加载器的层级关系如下所示。
我们可以自定义一个Java.lang.String吗?_第3张图片其中,各个加载类的分类及作用如下所示:

JVM自带的加载器
根加载器,Bootstrap :
加载 jre\lib\rt.jar (包含了Object、String、Math等平时编写代码时 大部分的jdk API);也可以通过JVM参数-Xbootclasspath指定加载某一个jar扩展类加载器,Extension:加载jre中lib\ext*.jar中的类 ;也可以通过JVM参数-Djava.ext.dirs指定加载某一个jarAppClassLoader/SystemClassLoader,系统加载器(也称为应用加载器):加载classpath(本题中的src);也可以通过JVM参数-Djava.class.path指定加载某一个类/jar用户自定义的加载器
都是抽象类java.lang.ClassLoader的子类,用于自定义加载

本题,程序在执行时识别的是src中的java.lang.String,src就是classpath,因此会调用系统加载器。但根据双亲委派机制,系统加载器会逐层委派双亲来加载此类,在委派的时候,最上层的加载器是根加载器,即根加载器优先级最高。而根加载器能够在jre\lib\rt.jar包中找到一个重名的java.lang.String(即jdk自带的String),因此根据双亲委派最终会由最顶层的根加载器来执行jdk自带的java.lang.String。显然,jdk中的String并没有main()方法,因此报错找不到main()!!!

你可能感兴趣的:(java基础,java类加载机制,双亲委派机制)