简体   繁体   English

Java URLClassLoader无法识别String

[英]Java URLClassLoader not recognising a String

I've got a really strange problem. 我有一个非常奇怪的问题。

I'm using a URLClassLoader to dynamically import files from a directory. 我正在使用URLClassLoader动态导入目录中的文件。 The code works fine if I use a literal string, and works fine if I use a variable to a literal string, but this isn't what I need. 如果我使用文字字符串,代码工作正常,如果我使用变量到文字字符串,工作正常,但这不是我需要的。

package test;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class Test {
    public static void main(String[] args) {

        try {
            File subfolder = new File("C:\\temp\\");
            URL classUrl = subfolder.toURI().toURL();
            URL[] classUrls = { classUrl };
            URLClassLoader ucl = new URLClassLoader(classUrls);

            for (File f : subfolder.listFiles()) {

                String name = f.getName()
                        .substring(0, f.getName().lastIndexOf(".")).trim();
                if (name.equals("TestClass"))
                        System.out.println(name);
                try {
                    MyInterface de = (MyInterface) Class.forName("TestClass", true, ucl)
                            .newInstance();
                    de.printSomething();
                } catch (ClassNotFoundException e) {
                }

                ucl.close();

            }
        } catch (MalformedURLException e) {
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

What I need is to be able to do this: 我需要的是能够做到这一点:

MyInterface de = (MyInterface) Class.forName(name, true, ucl).newInstance();

But it's not working even though "name" is a valid String and does equal "TestClass". 但即使“name”是一个有效的String并且它等于“TestClass”,它也不起作用。

EDIT: I get the error: 编辑:我收到错误:

java.lang.ClassNotFoundException: TestClass
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at test.Test.main(Test.java:25)

What's wrong? 怎么了?

It appears your issue has to do with the fact that your class being loaded has a package. 您的问题似乎与您正在加载的类具有包的事实有关。 When Java loads these classes, it expects to find the directory structure related to that package. 当Java加载这些类时,它希望找到与该包相关的目录结构。 So, the following code works: 因此,以下代码有效:

try {
        File subfolder = new File("/home/glen/TestClass");
        URL classUrl = subfolder.toURI().toURL();
        URL[] classUrls = { classUrl };
        URLClassLoader ucl = new URLClassLoader(classUrls);

        for (File f : subfolder.listFiles()[0].listFiles()) {

            System.out.println(f.getName());

            String name = f.getName()
                    .substring(0, f.getName().lastIndexOf(".")).trim();// "TestClass";
            if (name.equals("TestClass"))
                    System.out.println(name);
            try {
                MyInterface de = (MyInterface) Class.forName("test." + name, true, ucl)
                        .newInstance();
                de.printSomething();
            } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
            }

            ucl.close();

        }
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

Note how I am: 请注意我是怎样的:

  1. Specifying the fully qualified class name, test.TestClass , in the Class.forName method Class.forName方法中指定完全限定的类名test.TestClass
  2. Enumerating through the first subdirectory (in my case, the "test" directory) of the loading folder. 枚举装入文件夹的第一个子目录(在我的例子中,是“test”目录)。 The TestClass.class file is located in there. TestClass.class文件位于那里。 If I attempt to load directly through there, with or without specifying the package name, it fails. 如果我尝试直接通过那里加载,无论是否指定包名称,它都会失败。

In essence, the URLClassLoader requires a JAR-like directory structure, like test/TestClass.class , while having a URL root which contains the directory structure. 本质上,URLClassLoader需要类似JAR的目录结构,如test/TestClass.class ,同时具有包含目录结构的URL根。

My working theory is that you are not just changing the name variable to a string literal, as when I do that it still works fine. 我的工作理论是你不只是将name变量更改为字符串文字,因为当我这样做时它仍然可以正常工作。 Double check you're not changing anything else. 仔细检查你没有改变任何其他东西。 Either way, I hope this points you in the right direction. 无论哪种方式,我希望这能指出你正确的方向。

I guess this is because of the ucl.close() inside the for loop. 我想这是因为for循环中的ucl.close()。 I added some test if there are directories: the following class works and instanciate itself if declared in the root package, and if eclipse is configure to generate .class file in "bin" directory: 如果有目录,我添加了一些测试:如果在根包中声明,则以下类工作并且实例化自己,如果eclipse配置为在“bin”目录中生成.class文件:

public class Toto {

    public Toto(){
        // this writes "Toto" in the console if the class is well instanciated
        System.out.println("Toto");
    }

    public static void main(String[] args) {
        try {
            File subfolder = new File("bin");
            URL classUrl = subfolder.toURI().toURL();
            URL[] classUrls = { classUrl };
            URLClassLoader ucl = new URLClassLoader(classUrls);

            for (File f : subfolder.listFiles()) {
                String fileName= f.getName();
                int suffix = fileName.lastIndexOf('.');
                if(f.isDirectory() || suffix==-1){
                    continue;
                }
                String name = fileName.substring(0, suffix);
                try {
                    Class.forName(name, true, ucl).newInstance();

                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
            ucl.close();
        } catch (MalformedURLException e) {
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

What's wrong? 怎么了?

The first thing that's wrong is that this isn't the real code. 首先,错误的是这不是真正的代码。 This code catches and ignores ClassNotFoundException : 此代码捕获并忽略 ClassNotFoundException

} catch (ClassNotFoundException e) {
}

So it cannot possibly produce the output shown. 所以它不可能产生显示的输出。

The second thing that's wrong is that when this is corrected, the code works as expected. 第二件事是错误的,当纠正时,代码按预期工作。

Cannot reproduce. 无法重现。

Clearly you weren't running the code you thought you were running. 很明显,您没有运行您认为正在运行的代码。 Java simply does not behave as claimed. Java根本不像声称的那样行事。

Instead of 代替

MyInterface de = (MyInterface) Class.forName(name, true, ucl).newInstance();

use 采用

MyInterface de = (MyInterface) Class.forName(name + "Class", true, ucl).newInstance();

works for me. 适合我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM