ClassCastException无缘无故?

时间:2016-04-30 12:50:37

标签: java class casting

我因为看似没有理由而得到ClassCastException。让我解释一下我的代码结构: AbilityModifier是一个抽象类 ProjectileModifier是一个扩展AbilityModifier的抽象类 NoGravity是一个扩展ProjectileModifier

的类

AbilityModifier有一个自定义的ClassLoader,我用它来查找所有的能力修饰符。这样我就不会手动注册它们。但是,要自动注册它们,我需要转换它们并将它们添加到List中。当我转换它时,它抛出一个ClassCastException,说不能将redempt.divinity.ability.modifier.modifiers.NoGravity强制转换为redempt.divinity.ability。我做过测试,一切都没有例外:

package redempt.test;

public class Main {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Class<?> clazz = C.class;
        Object o = clazz.newInstance();
        A a = A.class.cast(o);
        System.out.println("Finished!");
    }
}
class A {
    public A() {

    }
}
class B extends A {
    public B() {

    }
}
class C extends B {
    public C() {

    }
}

这样可行,但出于某种原因,我的其他代码却没有。让我告诉你所涉及的所有课程:

AbilityModifier:

package redempt.divinity.ability.modifier;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import redempt.divinity.Main;
import redempt.divinity.ability.AbilityType;

public abstract class AbilityModifier {
    public static Set<AbilityModifier> modifiers = new HashSet<AbilityModifier>();
    public abstract void onUse(Player player);
    public abstract String getName();
    public abstract Material getRepresentation();
    public abstract AbilityType getType();
    public static void registerAll() throws IOException, ClassNotFoundException, URISyntaxException, InstantiationException, IllegalAccessException {
        File file = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI());
        JarFile jar = new JarFile(file);
        file.toURI().toURL();
        URL[] urls = {file.toURI().toURL()};
        List<String> names = new ArrayList<String>();
        URLClassLoader loader = URLClassLoader.newInstance(urls, ClassLoader.getSystemClassLoader());
        Enumeration<JarEntry> entries = jar.entries();
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            String name = entry.getName().replace("/", ".");
            if (name.endsWith(".class")) {
                try {
                    Class<?> clazz = loader.loadClass(name.replaceAll("\\.class$", ""));
                    System.out.println("Loading class: " + clazz.getSimpleName());
                    System.out.println(isSubclass(clazz));
                    if (isSubclass(clazz) && !Modifier.isAbstract(clazz.getModifiers())) {
                        names.add(clazz.getSimpleName());
                        AbilityModifier modifier = AbilityModifier.class.cast(clazz.newInstance());
                    }
                } catch (NoClassDefFoundError e) {
                    System.out.println("Unable to load class: " + name);
                }
            }
        }
        loader.close();
        jar.close();
        System.out.println(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().toURL().getPath());
        System.out.println("All ability modifiers found:");
        for (String name : names) {
            System.out.println(name);
        }
    }
    public static void register(Class<? extends AbilityModifier> clazz) {

    }
    private static boolean isSubclass(Class<?> clazz) {
        if (clazz.getSuperclass().equals(Object.class)) {
            return false;
        }
        return clazz.getSuperclass().getName().equals(AbilityModifier.class.getName()) ? true : isSubclass(clazz.getSuperclass());
    }
}

ProjectileModifier:

package redempt.divinity.ability.modifier;

import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import redempt.divinity.ability.Ability;

public abstract class ProjectileModifier extends AbilityModifier {
    public abstract void onUse(Player player, Entity projectile);
    @Override
    public void onUse(Player player) {
    }
    public abstract void onHit(Ability item, int level, EntityDamageByEntityEvent event);
    public abstract void onTick(Entity projectile);
}

NoGravity:

package redempt.divinity.ability.modifier.modifiers;

import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.util.Vector;
import redempt.divinity.ability.Ability;
import redempt.divinity.ability.AbilityType;
import redempt.divinity.ability.modifier.ProjectileModifier;

public class NoGravity extends ProjectileModifier {
    Vector vector;
    Location lastpos;
    @Override
    public void onUse(Player player, Entity projectile) {
        vector = player.getLocation().getDirection().normalize();
        lastpos = projectile.getLocation().clone();
    }
    @Override
    public String getName() {
        return "No gravity";
    }
    @Override
    public Material getRepresentation() {
        return Material.FEATHER;
    }
    @Override
    public AbilityType getType() {
        return AbilityType.PROJECTILE;
    }
    @Override
    public void onHit(Ability item, int level, EntityDamageByEntityEvent event) {
    }
    @Override
    public void onTick(Entity entity) {
        lastpos.add(vector);
        if (lastpos.getBlock().getType().equals(Material.AIR)) {
            entity.setVelocity(vector);
        }
        lastpos = entity.getLocation().clone();
    }
    public NoGravity() {
    }
}

例外:

java.lang.ClassCastException: redempt.divinity.ability.modifier.modifiers.NoGravity cannot be cast to redempt.divinity.ability.modifier.AbilityModifier
        at redempt.divinity.ability.modifier.AbilityModifier.registerAll(AbilityModifier.java:47) ~[?:?]
        at redempt.divinity.Main.onEnable(Main.java:30) ~[?:?]
        at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:292) ~[spigot-1.9.jar:git-Spigot-f04e043-52c7fc0]
        at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:340) [spigot-1.9.jar:git-Spigot-f04e043-52c7fc0]
        at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:405) [spigot-1.9.jar:git-Spigot-f04e043-52c7fc0]
        at org.bukkit.craftbukkit.v1_9_R1.CraftServer.loadPlugin(CraftServer.java:361) [spigot-1.9.jar:git-Spigot-f04e043-52c7fc0]
        at org.bukkit.craftbukkit.v1_9_R1.CraftServer.enablePlugins(CraftServer.java:321) [spigot-1.9.jar:git-Spigot-f04e043-52c7fc0]
        at net.minecraft.server.v1_9_R1.MinecraftServer.t(MinecraftServer.java:411) [spigot-1.9.jar:git-Spigot-f04e043-52c7fc0]
        at net.minecraft.server.v1_9_R1.MinecraftServer.l(MinecraftServer.java:376) [spigot-1.9.jar:git-Spigot-f04e043-52c7fc0]
        at net.minecraft.server.v1_9_R1.MinecraftServer.a(MinecraftServer.java:331) [spigot-1.9.jar:git-Spigot-f04e043-52c7fc0]
        at net.minecraft.server.v1_9_R1.DedicatedServer.init(DedicatedServer.java:269) [spigot-1.9.jar:git-Spigot-f04e043-52c7fc0]
        at net.minecraft.server.v1_9_R1.MinecraftServer.run(MinecraftServer.java:527) [spigot-1.9.jar:git-Spigot-f04e043-52c7fc0]
        at java.lang.Thread.run(Unknown Source) [?:1.8.0_65]

3 个答案:

答案 0 :(得分:1)

问题是,类NoGravity是通过与您在代码中引用的AbilityModifier类不同的类加载器加载的。因此,NoGravity有一个不同的AbilityModifier类实例作为其祖父母,因此投射不会起作用。

要解决此问题,您需要使用与在代码中加载AbilityModifier的类加载器相同的类加载器。

您需要更改:

URLClassLoader loader = URLClassLoader.newInstance(urls,
    ClassLoader.getSystemClassLoader());

URLClassLoader loader = URLClassLoader.newInstance(urls,
    AbilityModifier.class.getClassLoader());

有关详细信息,请参阅Understanding Java class loading

  

在运行时,Java类由该对唯一标识 - 类的完全限定名称和加载它的定义加载器。如果两个不同的加载器定义了相同的命名(即相同的完全限定名称)类,则这些类是不同的 - 即使.class字节相同并从同一位置(URL)加载。

答案 1 :(得分:0)

由于C是A的间接子类,在本例中是AbilityModifier的NoGravity,NoGravity的每个实例都是AbilityModifier的一个实例。但是,clazz.newInstance()方法返回必须进行转换的Object。我建议您在将此对象转换为NoGravity之后尝试为此对象分配,如下所示:

$(function(){ $('.fadeIn img:gt(0)').hide(); // assign this to a variable, since we're going to check it often var total = $('.fadeIn img').length; // initialize the counter // You can adjust this number as desired. // For example, set it to 0 if you want the show to end on the first slide var count = 1; // assign the interval to a variable so we can clear it var slideInterval = setInterval(function() { // if the current slide count is equal to or greater than the total slides, clear the interval if (++count >= total) { // stops the slideInterval (and therefore the slideshow) clearInterval(slideInterval); // You could do other things here if desired.... } $('.fadeIn :first-child').fadeOut() .next('img').fadeIn() .end().appendTo('.fadeIn');}, 2000); });

编辑,你可以尝试的另一件事是:

AbilityModifier a = (NoGravity) clazz.newInstance();

希望这有帮助!

答案 2 :(得分:-4)

Just Build-&gt;清理你的项目。