1

Java 版本:6

我已经构建了一个 aotuloader,它从 JAR 中加载类并实例化它们。所以我得到一个与特定路径和抽象类匹配的所有实例的 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] 加载 ShopCommands:[com.geNAZt.RegionShop.Command.Shop.ShopAdd@3b39c41d, com.geNAZt.RegionShop.Command.Shop.ShopBuy@4d7a6a4b, com.geNAZt.RegionS 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 at com.geNAZt.RegionShop.Command.ShopExecutor.(ShopExecutor.java:40) at com.geNAZt.RegionShop.RegionShopPlugin.onEnable(RegionShopPlugin.java:80) at 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。 org.bukkit.craftbukkit.v1_5_R3.CraftServer.enablePlugins(CraftServer.java:287) 上的craftbukkit.v1_5_R3.CraftServer.loadPlugin(CraftServer.java:305)。minecraft.server.v1_5_R3.MinecraftServer.j(MinecraftServer.java:310) 在 net.minecraft.server.v1_5_R3.MinecraftServer.e(MinecraftServer.java:289) 在 net.minecraft.server.v1_5_R3.MinecraftServer.a(MinecraftServer. java:249) 在 net.minecraft.server.v1_5_R3.DedicatedServer.init(DedicatedServer.java:152) 在 net.minecraft.server.v1_5_R3.MinecraftServer.run(MinecraftServer.java:388) 在 net.minecraft.server.v1_5_R3 .ThreadServerApplication.run(源文件:573)server.v1_5_R3.MinecraftServer.run(MinecraftServer.java:388) 在 net.minecraft.server.v1_5_R3.ThreadServerApplication.run(SourceFile:573)server.v1_5_R3.MinecraftServer.run(MinecraftServer.java:388) 在 net.minecraft.server.v1_5_R3.ThreadServerApplication.run(SourceFile:573)

是否可以将对象转换为抽象类,以便我从类中获取 api?还是有另一种方法可以从 Class 获取 API?

4

1 回答 1

2

这个例外是阶级认同危机的结果。您不能在类加载器之间进行转换。如本网站所述:

当使用多个类加载器时,其他类型的混淆也是可能的。图 2 显示了一个类标识危机的示例,当接口和相关实现分别由两个单独的类加载器加载时,就会导致该危机。即使接口和类的名称和二进制实现相同,来自一个加载器的类的实例也不能被识别为实现来自另一个加载器的接口

编辑
虽然 OP 找到了解决方案,但我想给我两分钱如果将该类移到 System 类加载器的空间中,则可以轻松解决导致无法识别
其他类的实例的混乱。并成为新创建的 s 的父级。这将导致不同的 s 共享同一个类。这可以通过以下方式实现:ClassLoaderSystem Class LoaderClassLoaderClassLoaderURLClassLoader(URL[] urls,ClassLoader parent)

URL[] urls = { new URL("jar:file:" + pathToJar +"!/") };
ClassLoader cl = new URLClassLoader(urls,ClassLoader.getSystemClassLoader());
于 2013-06-16T10:51:18.380 回答