加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

Java 类加载机制详解

发布时间:2020-12-14 06:38:11 所属栏目:Java 来源:网络整理
导读:转自: blockquote style="border-width:1px 1px 1px 3px;border-style:solid;border-color:rgb(214,214,214);color:rgb(68,68,68);font-family:'microsoft yahei';" 类加载机制是 Java 语言的一大亮点,使得 Java 类可以被动态加载到 Java 虚拟机中。 这次

转自:

<blockquote style="border-width:1px 1px 1px 3px;border-style:solid;border-color:rgb(214,214,214);color:rgb(68,68,68);font-family:'microsoft yahei';">

类加载机制是 Java 语言的一大亮点,使得 Java 类可以被动态加载到 Java 虚拟机中。

这次我们抛开术语和概念,从例子入手,由浅入深地讲解 Java 的类加载机制。

本文涉及知识点:双亲委托机制、ClassLoader、ExtClassLoader、AppClassLoader、自定义网络类加载器等

文章涉及代码:

<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
Java 虚拟机一般使用 Java 类的流程为:首先将开发者编写的 Java 源代码(.java文件)编译成 Java 字节码(.class文件),然后类加载器会读取这个 .class 文件,并转换成 java.lang.Class 的实例。有了该 Class 实例后,Java 虚拟机可以利用 newInstance 之类的方法创建其真正对象了。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
ClassLoader 是 Java 提供的类加载器,绝大多数的类加载器都继承自 ClassLoader,它们被用来加载不同来源的 Class 文件。


<h2 id="Classu6587_u4EF6_u6709_u54EA_u4E9B_u6765_u6E90_u5462_3F" style="color:rgb(34,238);border-bottom-width:1px;border-bottom-style:solid;font-size:18px;font-family:'microsoft yahei';">
Class 文件有哪些来源呢?


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
上文提到了 ClassLoader 可以去加载多种来源的 Class,那么具体有哪些来源呢?


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
首先,最常见的是开发者在应用程序中编写的类,这些类位于项目目录下;


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
然后,有 Java 内部自带的<code style="font-size:12px;font-family:'courier new';color:rgb(119,119,119);">核心类如?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">java.lang、<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">java.math、<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">java.io?等
package 内部的类,位于?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">$JAVA_HOME/jre/lib/?目录下,如?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">java.lang.String?类就是定义在?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">$JAVA_HOME/jre/lib/rt.jar?文件里;


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
另外,还有 Java?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">核心扩展类,位于?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">$JAVA_HOME/jre/lib/ext?目录下。开发者也可以把自己编写的类打包成
jar 文件放入该目录下;


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
最后还有一种,是动态加载远程的 .class 文件。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
既然有这么多种类的来源,那么在 Java 里,是由某一个具体的 ClassLoader 来统一加载呢?还是由多个 ClassLoader 来协作加载呢?


<h2 id="u54EA_u4E9B_ClassLoader__u8D1F_u8D23_u52A0_u8F7D_u4E0A_u9762_u51E0_u7C7B_Class_uFF1F" style="color:rgb(34,238);border-bottom-width:1px;border-bottom-style:solid;font-size:18px;font-family:'microsoft yahei';">
哪些 ClassLoader 负责加载上面几类 Class?
<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
实际上,针对上面四种来源的类,分别有不同的加载器负责加载。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
首先,我们来看级别最高的?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">Java 核心类,即<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">$JAVA_HOME/jre/lib?里的核心
jar 文件。这些类是 Java 运行的基础类,由一个名为?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">BootstrapClassLoader?加载器负责加载,它也被称作?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">根加载器/引导加载器。注意,<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">BootstrapClassLoader?比较特殊,它不继承?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">ClassLoader,而是由
JVM 内部实现;


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
然后,需要加载?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">Java 核心扩展类,即?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">$JAVA_HOME/jre/lib/ext?目录下的
jar 文件。这些文件由?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">ExtensionClassLoader?负责加载,它也被称作?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">扩展类加载器。当然,用户如果把自己开发的
jar 文件放在这个目录,也会被?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">ExtClassLoader?加载;


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
接下来是开发者在项目中编写的类,这些文件将由?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">AppClassLoader?加载器进行加载,它也被称作?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">系统类加载器
System ClassLoader;


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
最后,如果想远程加载如(本地文件/网络下载)的方式,则必须要自己自定义一个 ClassLoader,复写其中的?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">findClass()?方法才能得以实现。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
因此能看出,Java 里提供了至少四类?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">ClassLoader?来分别加载不同来源的 Class。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
那么,这几种 ClassLoader 是如何协作来加载一个类呢?


<h2 id="u8FD9_u4E9B_ClassLoader
u4EE5_u4F55_u79CD_u65B9_u5F0F_u6765_u534F_u4F5C_u52A0_u8F7D_String__u7C7B_u5462_uFF1F" style="color:rgb(34,238);border-bottom-width:1px;border-bottom-style:solid;font-size:18px;font-family:'microsoft yahei';">
这些 ClassLoader 以何种方式来协作加载 String 类呢?
<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
String 类是 Java 自带的最常用的一个类,现在的问题是,JVM 将以何种方式把 String class 加载进来呢?


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
我们来猜想下。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
首先,String 类属于 Java 核心类,位于?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">$JAVA_HOME/jre/lib?目录下。有的朋友会马上反应过来,上文中提过了,该目录下的类会由?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">BootstrapClassLoader?进行加载。没错,它确实是由?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">BootstrapClassLoader?进行加载。但,这种回答的前提是你已经知道了
String 在?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">$JAVA_HOME/jre/lib?目录下。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
那么,如果你并不知道 String 类究竟位于哪呢?或者我希望你去加载一个?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">unknown?的类呢?


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
有的朋友这时会说,那很简单,只要去遍历一遍所有的类,看看这个?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">unknown?的类位于哪里,然后再用对应的加载器去加载。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
是的,思路很正确。那应该如何去遍历呢?


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
比如,可以先遍历用户自己写的类,如果找到了就用?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">AppClassLoader?去加载;否则去遍历 Java 核心类目录,找到了就用?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">BootstrapClassLoader?去加载,否则就去遍历
Java 扩展类库,依次类推。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
这种思路方向是正确的,不过存在一个漏洞。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
假如开发者自己伪造了一个?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">java.lang.String?类,即在项目中创建一个包<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">java.lang,包内创建一个名为?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">String?的类,这完全可以做到。那如果利用上面的遍历方法,是不是这个项目中用到的
String 不是都变成了这个伪造的?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">java.lang.String?类吗?如何解决这个问题呢?


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
解决方法很简单,当查找一个类时,优先遍历最高级别的 Java 核心类,然后再去遍历 Java 核心扩展类,最后再遍历用户自定义类,而且这个遍历过程是一旦找到就立即停止遍历。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
在 Java 中,这种实现方式也称作?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">双亲委托。其实很简单,把?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">BootstrapClassLoader?想象为核心高层领导人,?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">ExtClassLoader?想象为中层干部,?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">AppClassLoader?想象为普通公务员。每次需要加载一个类,先获取一个系统加载器?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">AppClassLoader?的实例(ClassLoader.getSystemClassLoader()),然后向上级层层请求,由最上级优先去加载,如果上级觉得这些类不属于核心类,就可以下放到各子级负责人去自行加载。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
如下图所示:


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">

双亲委托

方式进行类加载吗?

?加载吗?

?的类文件,内容如下:

 classloader;

<span class="hljs-keyword" style="font-weight:bold;">public <span class="hljs-class"><span class="hljs-keyword" style="font-weight:bold;">class <span class="hljs-title" style="color:rgb(68,85,136);font-weight:bold;">MusicPlayer {
<span class="hljs-function"><span class="hljs-keyword" style="font-weight:bold;">public <span class="hljs-keyword" style="font-weight:bold;">void <span class="hljs-title" style="color:rgb(153,0);font-weight:bold;">print<span class="hljs-params">() {
System.out.printf(<span class="hljs-string" style="color:rgb(221,17,68);">"Hi I'm MusicPlayer");
}
}


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
然后来加载?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">MusicPlayer。

     ClassNotFoundException {
    Class clazz = Class.forName();
    ClassLoader classLoader = clazz.getClassLoader();
    System.out.printf(,classLoader.getClass().getSimpleName());
}

  

?是由??进行的加载。

?的双亲真的是 ExtClassLoader 和 BootstrapClassLoader 吗?

?提供了一个??的方法,来打印看看都是什么。

   () throws ClassNotFoundException {
        Class clazz = Class.forName();
        ClassLoader classLoader = clazz.getClassLoader();
        System..printf(,classLoader.getClass().getSimpleName());
    <span class="hljs-keyword" style="font-weight:bold;"&gt;while</span> (classLoader.getParent() != <span class="hljs-literal" style="color:rgb(0,128,128);"&gt;null</span>) {
        classLoader = classLoader.getParent();
        System.<span class="hljs-keyword" style="font-weight:bold;"&gt;out</span>.printf(<span class="hljs-string" style="color:rgb(221,68);"&gt;"Parent is %sn"</span>,classLoader.getClass().getSimpleName());
    }

}


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
打印结果为:

 
  

?确实是??的双亲,不过却没有看到?。事实上,上文就提过,?比较特殊,它是由 JVM 内部实现的,所以?

?目录下会发生什么?

?会加载?目录下所有的 jar 文件。那来尝试下直接把??这个类放到??目录下吧。


mv MusicPlayer.jar $JAVA_HOME/jre/lib/ext/

?目录下,同时把之前的??,而且这一次使用??来加载:

     ClassNotFoundException {
    ClassLoader appClassLoader = ClassLoader.getSystemClassLoader(); 
    Class clazz = appClassLoader.loadClass(?去加载,它仍然会被??加载到。

加载机制

的一些特性了,下面来看一下它的实现代码,加深理解。

?里的??方法,便是需要分析的源码了。这个方法里做了下面几件事:

 Class loadClass(String name, resolve)
     ClassNotFoundException
{
     (getClassLoadingLock(name)) {
        
        Class c = findLoadedClass(name);
         (c == ) {
             t0 = System.nanoTime();
             {
                 (parent != ) {
                    
                    c = parent.loadClass(name,);
                }  {
                    
                    c = findBootstrapClassOrNull(name);
                }
            }  (ClassNotFoundException e) {
                
                
            }
        <span class="hljs-keyword" style="font-weight:bold;"&gt;if</span> (c == <span class="hljs-keyword" style="font-weight:bold;"&gt;null</span>) {
            <span class="hljs-comment" style="color:rgb(153,136);"&gt;// 如果 parent 均没有加载到目标class,调用自身的 findClass() 方法去搜索</span>
            <span class="hljs-keyword" style="font-weight:bold;"&gt;long</span> t1 = System.nanoTime();
            c = findClass(name);

            <span class="hljs-comment" style="color:rgb(153,136);"&gt;// this is the defining class loader; record the stats</span>
            sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
            sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
            sun.misc.PerfCounter.getFindClasses().increment();
        }
    }
    <span class="hljs-keyword" style="font-weight:bold;"&gt;if</span> (resolve) {
        resolveClass(c);
    }
    <span class="hljs-keyword" style="font-weight:bold;"&gt;return</span> c;
}

}

<span class="hljs-comment" style="color:rgb(153,136);">// BootstrapClassLoader 会调用 native 方法去 JVM 加载
<span class="hljs-keyword" style="font-weight:bold;">private <span class="hljs-keyword" style="font-weight:bold;">native Class<?> findBootstrapClass(String name);


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
看完实现源码相信能够有更完整的理解。


<h2 id="u7C7B_u52A0_u8F7D_u5668_u6700_u9177_u7684_u4E00_u9762_uFF1A_u81EA_u5B9A_u4E49_u7C7B_u52A0_u8F7D_u5668" style="color:rgb(34,238);border-bottom-width:1px;border-bottom-style:solid;font-size:18px;font-family:'microsoft yahei';">
类加载器最酷的一面:自定义类加载器
<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
前面提到了 Java 自带的加载器?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">BootstrapClassLoader
、<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">AppClassLoader
和<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">ExtClassLoader
,这些都是
Java 已经提供好的。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
而真正有意思的,是?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">自定义类加载器
,它允许我们在<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">运行时
可以从<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">本地磁盘或网络
上动态加载自定义类。这使得开发者可以动态修复某些有问题的类,热更新代码。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
下面来实现一个<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">网络类加载器
,这个加载器可以从网络上动态下载 .class 文件并加载到虚拟机中使用。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
后面我还会写作与?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">热修复/动态更新
?相关的文章,这里先学习 Java 层?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">NetworkClassLoader
?相关的原理。


<ol style="list-style:none;color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
<li style="list-style-type:decimal;">
作为一个?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">NetworkClassLoader
,它首先要继承?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">ClassLoader

<li style="list-style-type:decimal;">
然后它要实现<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">ClassLoader
内的?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">findClass()
?方法。注意,不是<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">loadClass()
方法,因为<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">ClassLoader
提供了<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">loadClass()
(如上面的源码),它会基于<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">双亲委托机制去搜索某个
class,直到搜索不到才会调用自身的<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">findClass(),如果直接复写<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">loadClass(),那还要实现<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">双亲委托机制;
<li style="list-style-type:decimal;">
在?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">findClass()?方法里,要从网络上下载一个 .class 文件,然后转化成 Class 对象供虚拟机使用。


     {
<span class="hljs-meta" style="color:rgb(153,153);font-weight:bold;"&gt;@Override</span>
<span class="hljs-keyword" style="font-weight:bold;"&gt;protected</span> Class<?> findClass(String name) <span class="hljs-keyword" style="font-weight:bold;"&gt;throws</span> ClassNotFoundException {
    <span class="hljs-keyword" style="font-weight:bold;"&gt;byte</span>[] classData = downloadClassData(name); <span class="hljs-comment" style="color:rgb(153,136);"&gt;// 从远程下载</span>
    <span class="hljs-keyword" style="font-weight:bold;"&gt;if</span> (classData == <span class="hljs-keyword" style="font-weight:bold;"&gt;null</span>) {
        <span class="hljs-keyword" style="font-weight:bold;"&gt;super</span>.findClass(name); <span class="hljs-comment" style="color:rgb(153,136);"&gt;// 未找到,抛异常</span>
    } <span class="hljs-keyword" style="font-weight:bold;"&gt;else</span> {
        <span class="hljs-keyword" style="font-weight:bold;"&gt;return</span> defineClass(name,classData,<span class="hljs-number" style="color:rgb(0,128);"&gt;0</span>,classData.length); <span class="hljs-comment" style="color:rgb(153,136);"&gt;// convert class byte data to Class<?> object</span>
    }
    <span class="hljs-keyword" style="font-weight:bold;"&gt;return</span> <span class="hljs-keyword" style="font-weight:bold;"&gt;null</span>;
}

<span class="hljs-keyword" style="font-weight:bold;"&gt;private</span> <span class="hljs-keyword" style="font-weight:bold;"&gt;byte</span>[] downloadClassData(String name) {
    <span class="hljs-comment" style="color:rgb(153,136);"&gt;// 从 localhost 下载 .class 文件</span>
    String path = <span class="hljs-string" style="color:rgb(221,68);"&gt;"http://localhost"</span> + File.separatorChar + <span class="hljs-string" style="color:rgb(221,68);"&gt;"java"</span> + File.separatorChar + name.replace(<span class="hljs-string" style="color:rgb(221,68);"&gt;'.'</span>,File.separatorChar) + <span class="hljs-string" style="color:rgb(221,68);"&gt;".class"</span>; 

    <span class="hljs-keyword" style="font-weight:bold;"&gt;try</span> {
        URL url = <span class="hljs-keyword" style="font-weight:bold;"&gt;new</span> URL(path);
        InputStream ins = url.openStream();
        ByteArrayOutputStream baos = <span class="hljs-keyword" style="font-weight:bold;"&gt;new</span> ByteArrayOutputStream();
        <span class="hljs-keyword" style="font-weight:bold;"&gt;int</span> bufferSize = <span class="hljs-number" style="color:rgb(0,128);"&gt;4096</span>;
        <span class="hljs-keyword" style="font-weight:bold;"&gt;byte</span>[] buffer = <span class="hljs-keyword" style="font-weight:bold;"&gt;new</span> <span class="hljs-keyword" style="font-weight:bold;"&gt;byte</span>[bufferSize];
        <span class="hljs-keyword" style="font-weight:bold;"&gt;int</span> bytesNumRead = <span class="hljs-number" style="color:rgb(0,128);"&gt;0</span>;
        <span class="hljs-keyword" style="font-weight:bold;"&gt;while</span> ((bytesNumRead = ins.read(buffer)) != -<span class="hljs-number" style="color:rgb(0,128);"&gt;1</span>) {
            baos.write(buffer,bytesNumRead); <span class="hljs-comment" style="color:rgb(153,136);"&gt;// 把下载的二进制数据存入 ByteArrayOutputStream</span>
        }
        <span class="hljs-keyword" style="font-weight:bold;"&gt;return</span> baos.toByteArray();
    } <span class="hljs-keyword" style="font-weight:bold;"&gt;catch</span> (Exception e) {
        e.printStackTrace();
    }
    <span class="hljs-keyword" style="font-weight:bold;"&gt;return</span> <span class="hljs-keyword" style="font-weight:bold;"&gt;null</span>;
}

<span class="hljs-function"&gt;<span class="hljs-keyword" style="font-weight:bold;"&gt;public</span> String <span class="hljs-title" style="color:rgb(153,0);font-weight:bold;"&gt;getName</span><span class="hljs-params"&gt;()</span> </span>{
    System.out.printf(<span class="hljs-string" style="color:rgb(221,68);"&gt;"Real NetworkClassLoadern"</span>);
    <span class="hljs-keyword" style="font-weight:bold;"&gt;return</span> <span class="hljs-string" style="color:rgb(221,68);"&gt;"networkClassLoader"</span>;
}

}


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
这个类的作用是从网络上(这里是本人的 local apache 服务器?http://localhost/java?上)目录里去下载对应的 .class 文件,并转换成 Class<?> 返回回去使用。


<p style="color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
下面我们来利用这个?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">NetworkClassLoader?去加载 localhost 上的?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">MusicPlayer?类:


<ol style="list-style:none;color:rgb(68,68);font-family:'microsoft yahei';font-size:14px;">
<li style="list-style-type:decimal;">
首先把?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">MusicPlayer.class?放置于?<code style="font-size:12px;font-family:'courier new';color:rgb(119,119);">/Library/WebServer/Documents/java?(MacOS)目录下,由于
MacOS 自带 apache 服务器,这里是服务器的默认目录;
<li style="list-style-type:decimal;">
执行下面一段代码:

 className = ;
NetworkClassLoader networkClassLoader =  NetworkClassLoader();
Class clazz  = networkClassLoader.loadClass(className);
  • 成功。
  • ?可以正常工作,如果读者要用的话,只要稍微修改 url 的拼接方式即可自行使用。

    等,并开发了自定义的

    (编辑:李大同)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

      推荐文章
        热点阅读