自定义一个java.lang.String类,这个类是否可以被类加载器加载?为什么。
1.、双亲委派模型
类加载器可分为两类:一是启动类加载器(Bootstrap ClassLoader),是C++完成的,是JVM的一局部;另一种是其它的类加载器,是Java完成的,独立于JVM,全部都继承自抽象类java.lang.ClassLoader。jdk自带了三种类加载器,分别是启动类加载器〔Bootstrap ClassLoader〕,扩展类加载器〔Extension ClassLoader〕,应用程序类加载器〔Application ClassLoader〕。后两种加载器是继承自抽象类java.lang.ClassLoader。
一般是: 自定义类加载器 >> 应用程序类加载器 >> 扩展类加载器 >> 启动类加载器
上面的层次关系被称为双亲委派模型(Parents Delegation Model)。除了最顶层的启动类加载器外,其余的类加载器都有对应的父类加载器。
再简单说下双亲托付机制:如果一个类加载器收到了类加载的请求,它首先不会自己尝试去加载这个类,而是把这个请求委派给父类加载器,每一个层次的类加载器都是加此,因此全部的加载请求最终到达顶层的启动类加载器,只有当父类加载器反应自己无法完成加载请求时〔指
它的搜索范围没有到所需的类〕,子类加载器才会尝试自己去加载。
各个类加载器之间是组合关系,并非继承关系。
当一个类加载器收到类加载的请求,它将这个加载请求委派给父类加载器进行加载,每一层加载器都是如此,最终,全部的请求都会传送到启动类加载器中。只有当父类加载器自己无法完成加载请求时,子类加载器才会尝试自己加载。
双亲委派模型可以确保平安性,可以保证全部的Java类库都是由启动类加载器加载。如用户编写的java.lang.Object,加载请求传递到启动类加载器,启动类加载的是系统中的Object对象,而用户编写的java.lang.Object不会被加载。如用户编写的java.lang.virus类,加载请求传递到启动类加载器,启动类加载器发觉virus类并不是核心Java类,无法进行加载,将会由具体的子类加载器进行加载,而经过不同加载器进行加载的类是无法访问彼此的。由不同加载器加载的类处于不同的运行时包。全部的访问权限都是基于同一个运行时包而言的。
二、为什么要使用这种双亲托付模式呢?
因为这样可以防止重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再
加载一次。
考虑到平安因素,我们试想一下,如果不使用这种托付模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义类型,这样会存在非常大的平安隐患,而双亲托付的方法,就可以防止这种情况,因为String已经在启动时被加载,所以用户自定义类是无法加载一个自定义的ClassLoader。
思考:假设我们自己写了一个java.lang.String的类,我们是否可以替换调JDK本身的类?
答案是否认的。我们不能完成。为什么呢?我看很多网上解释是说双亲托付机制解决这个问题,其实不是非常的精确。因为双亲托付机制是可以打破的,你完全可以自己写一个classLoader来加载自己写的java.lang.String类,但是你会发觉也不会加载成功,具体就是因为针对java.x开头的类,jvm的完成中已经保证了必须由bootstrp来加载。
因加载某个类时,优先使用父类加载器加载需要使用的类。如果我们自定义了java.lang.String这个类, 加载该自定义的String类,该自定义String类使用的加载器是AppClassLoader,依据优先使用父类加载器原理, AppClassLoader加载器的父类为ExtClassLoader,所以这时加载String使用的类加载器是ExtClassLoader, 但是类加载器Ex
tClassLoader在jre/lib/ext目录下没有到String.class字符串常量需要new吗类。然后使用ExtClassLoader父类的加载器BootStrap, 父类加载器BootStrap在JRE/lib目录的rt.jar到了String.class,将其加载到内存中。这就是类加载器的托付机制。
三、定义自已的ClassLoader
既然JVM已经提供了默认的类加载器,为什么还要定义自已的类加载器呢?
因为Java中提供的默认ClassLoader,只加载指定目录下的jar和class,如果我们想加载其它位置的类或jar时,比方:我要加载网络上的一个class文件,通过动态加载到内存之后,要调用这个类中的方法完成我的业务逻辑。在这样的情况下,默认的ClassLoader就不能满足我们的需求了,所以需要定义自己的ClassLoader。
定义自已的类加载器分为两步:
2、重写父类的findClass方法
读者可能在这里有疑问,父类有那么多方法,为什么偏偏只重写findClass方法?
因为JDK已经在loadClass方法中帮我们完成了ClassLoader搜索类的算法,当在loadClass方法中搜索不到类时,loadClass方法就会调用findClass方法来搜索类,所以我们只需重写该方法即可。如没有特别的要求,一般不建议重写loadClass搜索类的算法。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。