java 类加载器加载顺序 经典例子

来源:互联网 发布:编程用什么cpu 编辑:程序博客网 时间:2024/06/05 15:01

  写了一个string 类,和api中包名,类名都是一样的,然后去加载: 

1 package java.lang;2 public class String{3     public static void main(String[] args ){    4     }5 }

 大家发现什么不同了吗?对了,我们写了一个与JDK中String一模一样的类,连包java.lang都一样,唯一不同的是我们自定义的String类有一个main函数。我们来运行一下:

 java.lang.NoSuchMethodError: main
 Exception in thread "main"

这是为什么? 我们的String类不是明明有main方法吗?

其实联系到jvm类加载的双亲委托模型,我们就能解释这个问题了。

      运行这段代码,AppClassLoader会尝试加载java.lang.String这个类,但是根据双亲委托模型AppClassLoader会将加载java.lang.String的请求委托给ExtClassLoader,而 ExtClassLoader又会委托给最后的启动类加载器BootstrapLoader。

      启动类加载器BootstrapLoader只能加载JAVA_HOME\jre\lib中的class类(即J2SE API),问题是标准API中确实有一个java.lang.String(注意,这个类和我们自定义的类是完全两个类)。BootstrapLoader以为找到了这个类,毫不犹豫的加载了j2se api中的java.lang.String。

      最后出现上面的加载错误(注意不是异常,是错误,JVM退出),因为API中的String类是没有main方法的。

结论:我们当然可以自定义一个和API完全一样的类,但是由于双亲委托模型,使得我们不可能加载上我们自定义的这样一个类。所以J2SE规范中希望我们自定义的包有自己唯一的特色(网络域名)。还有一点,这种加载器原理使得JVM更加安全的运行程序,因为黑客很难随意的替代掉API中的代码了。


Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader
类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是不是java类,这正是BootStrap。

jvm三级类加载器 类加载采用委托模型,就是顶层类加载器先是启动,然后将加载类动作传给(委托)上一层父类加载器,依次到bootstrap classloader,当根加载器没有加载到,那么又会返回给其下一级子类加载器,依次又传给当前的子类加载器。如果还没有找到,那么就是class not found.说白了无论加载什么类,都是从根加载起来的,根类库没有依次往后找。
为什么要有这种委托机制?
这样的好处,不让你修改Java原生的类库和本地类库,如果你想自己定义,可以应该是修改了包名或者类名,这样也能防止网络传过来的类取代本地类库或者api,防止入侵。


原创粉丝点击