zoukankan      html  css  js  c++  java
  • 自定义一个类加载器打印“Hello World!”

    现有两个类DemoHelloWorld,其源代码如下:

    Demo.java:

    package com.xxx;
    
    public class Demo {
        public void print() {
            HelloWorld.foo();
            // System.out.println(HelloWorld.class.getClassLoader());
        }   
    }
    

    HelloWorld.java:

    package com.xxx;
    
    class HelloWorld {
        public static void foo() {
            System.out.println("Hello World!");
        }   
    }
    

    可以看到DemoHelloWorld隶属于同一个包,Demoprint()方法中调用了HelloWorld.foo()从而打印出"Hello World!"。

    现有一个Main类,其结构如下:

    // 没有包名
    
    public class Main {
        public static void main(String[] args) {
              ...
        }
    }
    

    现在,我们的任务是Main类的main()方法中打印"Hello World!"。

    一般而言,我们只需要new Demo(),然后调用print()方法即可完成打印。

    然而,使用new操作符的前提是我们已经提前导入了com.xxx.Demo,但是,对于我们的Main程序而言,com.xxx.Demo一开始并不存在,它很有可能是在程序运行期间从网络上的某处下载下来,又或者是愚蠢的人类拷贝过来的。因而它并没有参与Main.java的编译,所以我们写Main的源代码时并不能导入com.xxx.Demo

    对于Main类而言,我们只知道会有一个com.xxx.Demoprint()方法帮助完成打印任务,却并不知晓它的具体位置。

    某一时刻,一股神秘力量将DemoHelloWorld传送到了我们的电脑上,现在它们与Main.class的位置如下:

    .
    |-- app
    |   `-- com
    |       `-- xxx
    |           |-- Demo.class
    |           `-- HelloWorld.class
    `-- Main.class
    

    但是此时,Main已经在运行了,启动它时使用了java -cp "." Main命令,其中的-cp "."选项明确指定了:对于开发者编写的类,只会从当前(与Main.class同级)目录下查找。DemoHelloWorld却在app路径下,因此,Main程序的类加载器无法对它们加载。

    怎么办呢?

    我们可以将Main.java写成下面的样子:

    import java.io.File;
    import java.lang.reflect.Method;
    import java.net.URL;
    import java.net.URLClassLoader;
    
    public class Main {
        public static void main(String[] args) throws Exception {
            URLClassLoader urlClassLoader =
                    new URLClassLoader(new URL[]{new File("./app").toURI().toURL()});
    
            Class<?> clazz = urlClassLoader.loadClass("com.xxx.Demo");
            Object obj = clazz.newInstance();
            Method print = clazz.getMethod("print");
            print.invoke(obj);
        }   
    }
    

    Main.java中,我们自定义了类加载器urlClassLoader,它将会从./app目录下查找class文件。

    因此,当使用urlClassLoader.loadClass("com.xxx.Demo")时能够加载到Demo.class并创建Class对象。

    接着,因为无法创建com.xxx.Demo的引用,我们只能使用反射来调用print()方法。

    这样一来,我们便可以愉快输出“Hello World!”了。如果把Demo.java中的注释去掉,还可以打印出HelloWorld类的类加载器,如下所示:

    [root@VM_0_6_centos]# java -cp "." Main
    Hello World!
    java.net.URLClassLoader@2a139a55
    

    可以看到,HelloWorld的类加载器已经不是AppClassLoader了,而是java.net.URLClassLoader

    -------------------------------------
    吾生也有涯,而知也无涯。
  • 相关阅读:
    Nodejs exec和spawn的区别
    VC++每个版本对应的库
    在cmd启动一个win32程序,printf把信息输出到启运它的那个CMD窗口
    window 控制台解决中文乱码
    NW.js 桌面应用程序
    C++ Addon Async 异步机制
    Node bak
    nodejs electron 创建桌面应用
    跨平台桌面程序框架Electron
    js post 下载文件
  • 原文地址:https://www.cnblogs.com/SanjiApollo/p/12838757.html
Copyright © 2011-2022 走看看