问题描述
我有一个程序,我希望用户能够从文件系统中选择一个 .java 类文件,然后将该类加载到程序中。
我使用 JFileChooser 来允许用户选择文件。然后,我尝试将该文件转换为 URL,并使用 urlclassloader 加载类(如 these answers 所建议的那样)。
问题在于,当我想使用 loadClass()
方法时,我不知道该类的“完整类名”(例如 java.lang.String
)。所以,我不知道如何使这种方法起作用。有没有办法获得这个类名?或者有其他方法可以做到这一点?
这是我的代码示例:
// Open the file chooser
JFileChooser fileChooser = new JFileChooser();
fileChooser.showOpenDialog(null);
File obtainedFile = fileChooser.getSelectedFile();
// Create the class loader from the file
URL classpath = obtainedFile.toURI().toURL();
urlclassloader loader = new urlclassloader(new URL[] {classpath});
// Get the class from the loader
Class<?> theClassIWant = loader.loadClass("the file name"); // What do I put here??
解决方法
加载单个类文件一般是完全没用的。所述类文件并不孤单;它有更多相关的类文件。即使你认为'不,只有一个源文件,不用担心这个',注意单个java文件可以轻松生成多个类文件。
因此,有两个选择:
不要加载类文件。加载 jar 文件。
使用通常的机制(META-INF/services
或 META-INF/MANIFEST.MF
)将某种类名放入其中,以便您知道要加载什么。然后使用提供的 jar 创建一个新的类加载器,加载清单,找出主类,加载并运行它。
尝试确定加载的类文件的“根”并将其包含在类路径中。
这相当困难 - 问题是,要“加载”一个类文件,您需要在加载该类文件之前告诉加载器该类的完全限定名称是什么。但是你怎么知道全限定名呢?您可以从文件中推测出类名(并非总是如此,但通常如此),但包是一个更困难的问题。
您可以自己将类文件作为二进制流打开并编写一个基本的类文件格式解析器来获取完全限定的类名。对于有经验的 Java 程序员来说很容易。对于 Java 新手来说相当棘手(如果您认为这是个好主意,我猜您就是这样)。
您也可以使用现有工具来执行此操作,例如 bytebuddy 或 asm。
最后,您可以尝试一种在墙上做意大利面的方法:继续向上移动目录,直到它起作用为止。您知道如果发生异常,它就不起作用。
例如,要加载 C:\MyDir\Whatever\com\foo\MyApp.class
,您首先尝试使用根目录 URLClassLoader
创建一个新的类加载器(请参阅 C:\MyDir\Whatever\com\foo
的 API,它是核心 java 的一部分),然后您要求它加载类 MyApp
。
如果可行,那就太好了(但通常尝试加载无包的类只是一个非启动器,您不应该这样做,CL API 可能不支持它,有意地,没有修复那个)。
如果没有,请尝试C:\MyDir\Whatever\com
,并加载类foo.MyApp
。如果这不起作用,请尝试 C:\MyDir\Whatever
并加载类 com.foo.MyApp
,依此类推。
相当大的优势是,如果 MyApp.class
旁边有另一个类,并且 MyApp 需要它,这将正常工作。
您需要编写一个 while 循环(使用 Paths.get
和 p.getParent()
遍历路径结构),捕获正确的异常,将路径操作为类名(使用 .replace
和+
),当然,创建一个类加载器(URLClassLoader
),用它加载类(调用loadClass
),如果你打算运行它,像{{ 1}} 然后 thatClass.getConstructor().newInstance()
实际“运行”它,更多信息可以在 thatClass.getMethod("someMethod",String.class,/* all the other args here */).invoke(theInstanceYouJustMade,"param1",/*all other params */)
包中找到。