Java版本:6
我已经构建了一个aotuloader,它从JAR中加载Classes并实例化它们。因此,我获得了与特定路径和抽象类匹配的所有实例的ArrayList。
package com.geNAZt.RegionShop.Util;
import com.geNAZt.RegionShop.RegionShopPlugin;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class Loader {
public static <T> ArrayList<T> loadFromJAR(RegionShopPlugin plugin, String path, Class interf) {
ArrayList<T> returnObjects = new ArrayList<T>();
try {
String pathToJar = Loader.class.getProtectionDomain().getCodeSource().getLocation().getPath();
JarFile jarFile = new JarFile(pathToJar);
Enumeration e = jarFile.entries();
URL[] urls = { new URL("jar:file:" + pathToJar +"!/") };
ClassLoader cl = URLClassLoader.newInstance(urls);
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
if(je.isDirectory() || !je.getName().endsWith(".class") || !je.getName().substring(0,je.getName().length()-6).replace("/", ".").contains(path +".")){
continue;
}
try {
String className = je.getName().substring(0,je.getName().length()-6);
className = className.replace('/', '.');
Class<?> c = cl.loadClass(className);
if(!c.getSuperclass().getName().equals(interf.getName())) {
continue;
}
Constructor[] cons = c.getDeclaredConstructors();
for(Constructor con : cons) {
try {
returnObjects.add((T)con.newInstance(plugin));
break;
} catch (InvocationTargetException e1) {
e1.printStackTrace();
continue;
} catch (InstantiationException e1) {
e1.printStackTrace();
continue;
} catch (IllegalAccessException e1) {
e1.printStackTrace();
continue;
} catch (IllegalArgumentException e1) {
e1.printStackTrace();
continue;
}
}
} catch(ClassNotFoundException er) {
er.printStackTrace();
continue;
}
}
} catch(IOException e) {
e.printStackTrace();
return null;
}
return returnObjects;
}
}
它工作正常我得到了正确的对象:
private ArrayList<ShopCommand> loadedCommands = new ArrayList<ShopCommand>();
loadedCommands = loadFromJAR(pl, "com.geNAZt.RegionShop.Command.Shop", ShopCommand.class);
如果我做一个日志,所有对象似乎都没问题:
12:24:40 [INFO] [RegionShop] Loaded ShopCommands:[com.geNAZt.RegionShop.Command.Shop.ShopAdd@3b39c41d,com.geNAZt.RegionShop.Command.Shop.ShopBuy@4d7a6a4b,com.geNAZt。地区 hop.Command.Shop.ShopDetail@1fd889aa,com.geNAZt.RegionShop.Command.Shop.ShopEquip@4136083b,com.geNAZt.RegionShop.Command.Shop.ShopList@42567aef,com.geNAZt.RegionShop.Comman d.Shop.ShopName@3ba102ef]
但后来我想用它们。如果要使用它们,我想将它们转换为ShopCommand类。但后来我得到了这个错误:
12:24:40 [SCHWERWIEGEND]启用RegionShop v1.1.0b3时出错(它是最新的吗?) java.lang.ClassCastException:com.geNAZt.RegionShop.Command.Shop.ShopAdd无法强制转换为com.geNAZt.RegionShop.Command.ShopCommand 在com.geNAZt.RegionShop.Command.ShopExecutor。(ShopExecutor.java:40) 在com.geNAZt.RegionShop.RegionShopPlugin.onEnable(RegionShopPlugin.java:80) 在org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:217) 在org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:457) 在org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:383) 在org.bukkit.craftbukkit.v1_5_R3.CraftServer.loadPlugin(CraftServer.java:305) 在org.bukkit.craftbukkit.v1_5_R3.CraftServer.enablePlugins(CraftServer.java:287) at net.minecraft.server.v1_5_R3.MinecraftServer.j(MinecraftServer.java:310) at net.minecraft.server.v1_5_R3.MinecraftServer.e(MinecraftServer.java:289) at net.minecraft.server.v1_5_R3.MinecraftServer.a(MinecraftServer.java:249) at net.minecraft.server.v1_5_R3.DedicatedServer.init(DedicatedServer.java:152) at net.minecraft.server.v1_5_R3.MinecraftServer.run(MinecraftServer.java:388) at net.minecraft.server.v1_5_R3.ThreadServerApplication.run(SourceFile:573)
是否可以将Objects转换为抽象类,以便从类中获取api?或者是否有其他方法可以从类中获取API?
答案 0 :(得分:2)
此异常是类标识危机的结果。你不能在类加载器之间进行转换。如上所述this site:
使用多个类时,也可能存在其他类型的混淆 装载机。图2显示了一个类身份危机的例子 每个接口和相关实现时的结果 由两个单独的类加载器加载。 即使名称和二进制文件 接口和类的实现是相同的,a 来自一个加载器的类的实例无法识别为 从其他加载器实现接口。
修改强>
尽管解决方案是由OP发现的,但我想提供two cents
如果该类被移动到System类加载器的空间,则可以很容易地解决导致从其他ClassLoader
无法识别该类实例的混淆。并使System Class Loader
成为新创建的ClassLoader
的父级。这将导致不同的ClassLoader
共享同一个类。这可以通过URLClassLoader(URL[] urls,ClassLoader parent)
以下列方式实现:
URL[] urls = { new URL("jar:file:" + pathToJar +"!/") };
ClassLoader cl = new URLClassLoader(urls,ClassLoader.getSystemClassLoader());