如何使某些内容与数组和集合兼容?

时间:2015-02-22 08:38:14

标签: java bukkit

这听起来是一个愚蠢的问题。但是,在我使用的API中,版本1.7.2使方法Bukkit.getServer().getOnlinePlayers()返回Player[],版本1.7.10得到Bukkit.getServer().getOnlinePlayers()返回Collection<Player> 。我需要让我的插件兼容。

我已经获得了两者的API,但除了创建单独的插件外,我目前还不知道如何做到这一点。

我目前只是将集合转换为数组。那么,如果版本低于1.7.9,有没有办法(我已经可以获得版本),不使用.toArray()但是因为它已经返回了一个数组?

4 个答案:

答案 0 :(得分:3)

你可以用反射来做。像这样:

List<Player> getPlayers() {
    try {
        Method method = getMethod(Server.class, "getOnlinePlayers");
        Object result = method.invoke(Bukkit.getServer());
        if(result instanceof Player[])
            return Arrays.asList((Player[])result);
        else
            return (List<Player>)result;

    } catch(ReflectiveOperationException e) {

        // something went wrong! If you have a better way to handle problems, do that instead
        throw new RuntimeException(e);
    }
}

答案 1 :(得分:2)

实际上有两种方法可以做到这一点。 @ immibis的回答给出了第一种方式。第二种方法涉及创建一个&#34;版本适配器&#34;具有多个插件实现的API,用于不同版本(在本例中)Bukkit; e.g。

public interface BukkitVersionAdapter {
    Collection<Player> getOnlinePlayers();
    ...
}

public class BukkitVersionAdapterV1dot7 implements BukkitVersionAdapter {
    public Collection<Player> getOnlinePlayers() {
        return Arrays.asList(Bukkit.getServer().getOnlinePlayers());
    }
    ...
}

public class BukkitVersionAdapterV1dot8 implements BukkitVersionAdapter {
    public Collection<Player> getOnlinePlayers() {
        return Bukkit.getServer().getOnlinePlayers();
    }
    ...
}

然后需要针对相应的Bukkit版本针对Bukkit API jar编译特定于版本的适配器类。

然后当你启动你的主应用程序(或我猜的Bukkit插件)时,你会做这样的事情:

String version = // get the Bukkit version
String className = // map the version to a class name; e.g.
                   // "pkg.BukkitVersionAdapterV1dot7" or
                   // "pkg.BukkitVersionAdapterV1dot8"
Class clazz = Class.forName(className);
BukkitVersionAdapter adapter = 
         (BukkitVersionAdapter) clazz.newInstance();

// Then ...
Collection<Player> players = adapter.getOnlinePlayers();

这一切都相当繁琐,但与使用反射进行调用的方法相比,它有两个好处:

  1. 特定于不同Bukkit版本的逻辑现在被隔离到代码库的一部分......而不是分散(可能)遍布整个地方。

  2. 反射的开销仅在启动时产生。之后,通过适配器API对Bukkit进行的所有方法调用都是常规的Java方法调用。

  3. 根据上下文,这些可能使适配器方法更合适。

答案 2 :(得分:0)

如果类org.bukkit.Server刚刚更改了方法getOnlinePlayers()的返回类型而不是弃用它并引入了一个新方法(yack !!!!!谁敢于更改已发布的接口)这样一种方式?),你没有办法在一个单一的代码中调用该方法。你只是不能写一些像

这样的东西
Server server = Bukkit.getServer();
// One of the branches will not be compilable
if (version <= xxxx) {
    Player[] players = server.getOnlinePlayers();
}
else {
    Collection<Player> players = server.getOnlinePlayers();
}

我担心唯一的办法就是像其他人推荐的那样使用反思。

答案 3 :(得分:-1)

你做得很好。不幸的是,没有办法创建可以处理集合和数组的强类型方法。

(您可以创建接受Object的方法,然后使用instanceof检查它,转换并处理集合和数组,但这个解决方案很难看。)