Java中的动态类型转换

丰斯坦

我正在为Minecraft服务器实现CraftBukkit编写插件,遇到一个问题,需要转换为通过反射找到的类。

这是交易。我写的原始代码看起来像这样,删除了不相关的部分:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import net.minecraft.server.v1_7_R3.EntityAnimal;
import net.minecraft.server.v1_7_R3.EntityHuman;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftAnimals;
import org.bukkit.craftbukkit.v1_7_R3.entity.CrafteEntity;

import org.bukkit.World;
import org.bukkit.entity.Animals;
import org.bukkit.entity.Entity;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;

public class Task extends BukkitRunnable {
    private static final int MATING_DISTANCE = 14;
    private final JavaPlugin plugin;
    private final Random randomizer;
    private boolean mateMode;
    private double chance;

    public Task(JavaPlugin plugin, double chance, boolean mateMode) {
        this.plugin = plugin;
        this.randomizer = new Random();
        this.chance = chance;
        this.mateMode = mateMode;
        this.theTaskListener = listener;
    }

    public void run() {
        List<World> worlds = plugin.getServer().getWorlds();
        Iterator<World> worldIterator = worlds.iterator();

        while (worldIterator.hasNext()) {
            World world = worldIterator.next();
            Collection<Animals> animals = world.getEntitiesByClass(Animals.class);

            Iterator<Animals> animalIterator = animals.iterator();
            while (animalIterator.hasNext()) {
                Animals animal = (Animals) animalIterator.next();
                EntityAnimal entity = (EntityAnimal) ((CraftEntity) ((CraftAnimals) animal)).getHandle();
                EntityHuman feeder = null;
                entity.f(feeder);
            }
        }
    }
}

但是,如您在导入中所见,此代码仅从Minecraft服务器软件包的一个版本-v1_7_R3中导入了类。现在的问题是,我想添加更多的支持,并且我希望能够为每个Minecraft版本创建单独的插件版本而无需添加支持。尽管包中的大多数类都是相同的(至少我需要的所有类),但包名称却不同,因此无法使用静态导入来完成(或至少我认为是这样)。

因此,我决定使用反射来获得所需的正确类(此代码在另一个类中):

private static final String[] requiredClasses = {
    "net.minecraft.server.%s.EntityAnimal",
    "net.minecraft.server.%s.EntityHuman",
    "org.bukkit.craftbukkit.%s.entity.CraftAnimals",
    "org.bukkit.craftbukkit.%s.entity.CraftEntity"
};
public static final String[] supportedVersions = {
    "v1_7_R3",
    "v1_7_R4"
};

public Class<?>[] initializeClasses() {
    String correctVersion = null;
    for (int i = 0; i < supportedVersions.length; i++) {
        String version = supportedVersions[i];
        boolean hadIssues = false;
        for (int j = 0; j < requiredClasses.length; j++) {
            String className = requiredClasses[j];
            try {
                Class.forName(String.format(className, version));
            } catch (ClassNotFoundException e) {
                getLogger().log(Level.INFO, String.format("The correct version isn't %s.", version));
                hadIssues = true;
                break;
            }
        }

        if (!hadIssues) {
            correctVersion = version;
            break;
        }
    }

    Class[] classes = new Class[requiredClasses.length];

    if (correctVersion != null) {
        getLogger().log(Level.INFO, String.format("The correct version is %s.", correctVersion));
        for (int i = 0; i < requiredClasses.length; i++) {
            String className = requiredClasses[i];
            try {
                classes[i] = Class.forName(String.format(className, correctVersion));
            } catch (ClassNotFoundException e) {}
        }
    } else {
        getLogger().log(Level.WARNING, "The version of Minecraft on this server is not supported.");
        getLogger().log(Level.WARNING, "Due to this, the plugin will self-disable.");
        getLogger().log(Level.WARNING, "To fix this issue, get  build that supports your version.");
        this.setEnabled(false);
    }

    return classes;
}

现在,此方法可以成功检索当前支持的两个版本中的必需类。我使用实例变量和经过编辑的构造函数将它们传递给重写的Task类,然后删除了特定于版本的导入:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import org.bukkit.World;
import org.bukkit.entity.Animals;
import org.bukkit.entity.Entity;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;

public class Task extends BukkitRunnable {

    private static final int MATING_DISTANCE = 14;
    private final JavaPlugin plugin;
    private final Random randomizer;
    private boolean mateMode;
    private double chance;

    private Class entityAnimal;
    private Class entityHuman;
    private Class craftAnimals;
    private Class craftEntity;

    public Task(JavaPlugin plugin, Class[] classes, double chance, boolean mateMode) {
        this.plugin = plugin;
        this.randomizer = new Random();
        this.chance = chance;
        this.mateMode = mateMode;

        this.entityAnimal = classes[0];
        this.entityHuman = classes[1];
        this.craftAnimals = classes[2];
        this.craftEntity = classes[3];
    }

现在,如何重写Task.run()方法,以便它将使用反射类?涉及到很多类型转换,不幸的是,由于Minecraft代码中大量的重载,这都是必需的。例如,entity.f(EntityHuman human)方法不能简单地通过执行object.f(null)来调用,因为还有其他重载的object.f(Object object)方法。

当我在这里遇到死胡同时,我乐于接受所有建议。如果有更好的方法来解决该问题,我也可以更改为该方法。

谢谢!

丰斯坦

阅读了Gerold Broser的回答后,我意识到我必须以某种方式修改我的方法,以便创建某种类型的处理程序类来执行特定于版本的操作-当然,这将是一个接口,该接口将由每个版本一个类。

但是,当我意识到Maven不允许我调用同一groupid.artifactid对象的两个版本时,这成为一个问题。

我很快进行了一些研究,发现了mbaxter的Multiple Versions Tutorial以及AbstractionExamplePlugin实现,完美地演示了这种方法。

该方法非常有效,这是每个Bukkit开发人员都应该使用的方法。是我完成的插件,如有必要,可作进一步参考。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章