繁体   English   中英

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

[英]How can I make something be compatible with both an array and a collection?

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

我都有两者的API,但是除了创建单独的插件外,我目前不知道如何执行此操作。

我目前只是将集合转换为数组。 那么,如果版本小于1.7.9,有什么方法(我已经可以获取版本)了,不要使用.toArray() ,因为它已经返回了数组?

您可以通过反射来实现。 像这样:

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);
    }
}

实际上有两种方法可以做到这一点。 @immibis的答案给出了第一种方法。 第二种方法涉及为不同版本的Bukkit(在这种情况下)创建具有多个插件实现的“版本适配器” API。 例如

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方法调用。

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

如果类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();
}

恐怕唯一的方法就是像其他人推荐的那样使用反射。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM