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

    -------------------------------------
    吾生也有涯,而知也无涯。
  • 相关阅读:
    致远OA-A8协同管理软件无需登录getshell漏洞
    WordPress插件NextGEN Gallery <= 3.2.2 RCE漏洞利用(需要登录)
    Coremail邮件系统配置文件泄露漏洞
    CVE-2019-12735 VIM命令执行漏洞利用
    分享一个乌云Drops文章在线浏览的网站
    Ubuntu、Debian安装Docker CE
    一些好用的网络渗透工具和查询平台
    CVE-2017-11882 Office内存损坏漏洞利用
    Cobalt Strike入门教程-通过exe木马实现远控
    Jfinal cms前台评论XSS漏洞分析
  • 原文地址:https://www.cnblogs.com/SanjiApollo/p/12838757.html
Copyright © 2011-2022 走看看