简体   繁体   English

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

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

It sounds a stupid question. 这听起来是个愚蠢的问题。 However, in the API that I am using, version 1.7.2 has got the method Bukkit.getServer().getOnlinePlayers() returning a Player[] , and version 1.7.10 has got Bukkit.getServer().getOnlinePlayers() returning a Collection<Player> . 但是,在我使用的API中,版本1.7.2的方法Bukkit.getServer().getOnlinePlayers()返回一个Player[] ,而版本1.7.10的方法将Bukkit.getServer().getOnlinePlayers()返回一个Collection<Player> I need to make my plugin compatible with both. 我需要使我的插件与两者兼容。

I have got the API's for both, but aside from creating separate plugins, I currently have got no idea how to do this. 我都有两者的API,但是除了创建单独的插件外,我目前不知道如何执行此操作。

I currently just convert the collection into an array anyway. 我目前只是将集合转换为数组。 So, is there any way to (i can already get the version) if the version is less than 1.7.9, not use the .toArray() but since it already returns an array? 那么,如果版本小于1.7.9,有什么方法(我已经可以获取版本)了,不要使用.toArray() ,因为它已经返回了数组?

You could do it with reflection. 您可以通过反射来实现。 Something like this: 像这样:

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

There are actually two ways to do this. 实际上有两种方法可以做到这一点。 @immibis's answer gives the first way. @immibis的答案给出了第一种方法。 The second way involves creating a "version adapter" API with multiple plugin implementations for different versions of (in this case) Bukkit; 第二种方法涉及为不同版本的Bukkit(在这种情况下)创建具有多个插件实现的“版本适配器” API。 eg 例如

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

The version-specific adapter classes then need to be compiled against the Bukkit API jars for the respective Bukkit versions. 然后,需要针对各个Bukkit版本的Bukkit API jar编译特定于版本的适配器类。

Then when you start your main application (or Bukkit plugin I guess), you do something like this: 然后,当您启动主应用程序(我猜是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();

This is all rather cumbersome, but it has two benefits compared with the approach of using reflection to make the calls: 这都很麻烦,但是与使用反射进行调用的方法相比,它有两个好处:

  1. The logic that is specific to different Bukkit versions is now isolated to one part of the codebase ... rather than being scattered (potentially) all over the place. 现在,针对不同Bukkit版本的特定逻辑已隔离到代码库的一部分...而不是分散(潜在地)散布在整个地方。

  2. The overheads of reflection are only incurred at startup. 反射的开销仅在启动时发生。 After that, all of the method calls to Bukkit made via the adapter API are regular Java method calls. 之后,通过适配器API对Bukkit进行的所有方法调用都是常规的Java方法调用。

Depending on the context, these may make the adapter approach more appropriate. 根据上下文,这些可能会使适配器方法更合适。

If the class org.bukkit.Server just changed the return type of the method getOnlinePlayers() rather than making it deprecated and introducing a new method (yack!!!!! who dares to change the already published interface in such a way?), you have no decent way how to call the method in one single code. 如果类org.bukkit.Server只是更改了方法getOnlinePlayers()的返回类型,而不是不赞成使用它,而是引入了一个新方法(yack !!!!!谁敢以这种方式更改已发布的接口?) ,您没有如何在一个代码中调用该方法的体面方法。 You simply cannot write something like 你根本不能写像

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

I'm afraid the only way is to use reflection like in the meantime others recommended. 恐怕唯一的方法就是像其他人推荐的那样使用反射。

You are doing well. 你过得很好 Unfortunately there is no way to create strongly typed method that can deal with both collection and array. 不幸的是,没有办法创建可以处理集合和数组的强类型方法。

(You can create method that accepts Object and then examine it using instanceof , cast and deal with both collection and arrays but this solution is ugly.) (您可以创建一个接受Object方法,然后使用instanceof进行检查,强制转换并处理集合和数组,但是这种解决方案很难看。)

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

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