我正在尝试用Java编写脚本系统,并且我设法让我的脚本进行编译和实例化,但当我尝试将脚本转换为“DeftScript”时,它会抛出一个ClassCastError
甚至被认为脚本本身扩展了“DeftScript”类
错误(至少是重要部分):
java.lang.ClassCastException: scripts.Compass cannot be cast to com.deft.core.scripts.DeftScript
at com.deft.core.scripts.DeftScriptManager.instantiate(DeftScriptManager.java:52) ~[?:?]
错误是由此
引起的deftScript = (DeftScript)obj;
编译和实例化:
public static DeftScript instantiate(String java) {
File file = new File("./plugins/Deft-Core/scripts/" + java);
DeftScript deftScript = null;
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
List<String> optionList = new ArrayList<String>();
optionList.addAll(Arrays.asList("-classpath", System.getProperty("java.class.path") + ";./plugins/Deft-Core.jar"));
Iterable<? extends JavaFileObject> compilationUnit = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(file));
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, optionList, null, compilationUnit);
if (task.call()) {
Object obj = null;
try {
String jarFile = "./plugins/Deft-Core.jar";
URLClassLoader classLoader = new URLClassLoader (new URL[] {new File(jarFile).toURI().toURL(), new File("./plugins/Deft-Core/").toURI().toURL()}, Thread.currentThread().getContextClassLoader());
Class<?> loadedClass;
loadedClass = Class.forName("scripts.Compass", false, classLoader);
obj = loadedClass.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | MalformedURLException e) {
e.printStackTrace();
}
deftScript = (DeftScript)obj;
deftScript.onEnable();
} else {
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
System.out.format("Error on line %d in %s%n", diagnostic.getLineNumber(), diagnostic.getSource().toUri());
}
}
return deftScript;
}
调用实例化方法:
String script = "Compass.java";
DeftScriptManager.instantiate(script);
DeftScript.java
package com.deft.core.scripts;
public abstract class DeftScript {
public abstract void onEnable();
}
Compass.java
package scripts;
import com.deft.core.scripts.DeftScript;
public class Compass extends DeftScript {
@Override
public void onEnable() {}
}
答案 0 :(得分:1)
如果你的默认类加载器加载类DeftScript,你加载的.jar也包含类DeftScript,那么Java会认为这是两个不同的类,它们具有相同的二进制名称,但是由不同的类加载器加载,你将获得该异常因为Java看到你试图混合两个不同的类,就像它们是同一个东西。
Java中类的唯一标识包括二进制类名和用于加载类的类加载器。
如果您像这样创建URLClassloader:
URLClassLoader classLoader =
new URLClassLoader (new URL[] {new File(jarFile).toURI().toURL(),
new File("./plugins/Deft-Core/").toURI().toURL()},
Thread.currentThread().getContextClassLoader());
第二个参数告诉java首先使用当前线程的类加载器加载类,如果它们未在父类中定义,则只从URLClassLoader中的jar加载它们。
现在类加载器将首先引用它的父类,而类DeftScript只会由父类加载器加载,即使你的.jar文件定义了相同的类(按名称)。
这是一篇非常好的文章,描述了它的工作方式:
http://www2.sys-con.com/ITSG/virtualcd/java/archives/0808/chaudhri/index.html
这也很有帮助