java - 如何使用 Java 泛型以便为返回类型为 List<Interface> 的方法返回 List<InterfaceImpl>

标签 java generics enums

我正在尝试建模一个菜单系统,该系统可以具有包含子菜单的菜单。我想要一个通用的 interface用于通过其父菜单从菜单和子菜单中检索选项,但我在设计它时遇到了麻烦,同时保持它的类型安全、灵活且没有编译时“不兼容类型”错误。我试图通过使用 Java 泛型来指定 Menu interface 来实现我的目标。用于简单的菜单和 ParentMenu interface对于使用泛型类型参数作为方法参数和返回类型的父菜单。

我有第三个Enumerable interface用于表示特定菜单上可用的选项。 implement 的类(class)Enumerable interface都是enum classes枚举菜单上的选项。父菜单可以包含许多子菜单,我想要一种通用的单一方法,允许父菜单类的客户端获取其任何一个子菜单的选项。

父菜单具体class有一个方法,其签名指定返回值 List<Enumerable> 。我希望能够返回 List<MenuOption>哪里MenuOption implements Enumerable interface 。但是,我收到一个错误,指出 List<MenuOption>我想返回与List<Enumerable>不兼容。

基本Menu interface :

package example;

import java.util.List;

public interface Menu<T> {
    public List<T> getOptions();
}

ParentMenu interface :

package example;

import java.util.List;

public interface ParentMenu<T,U> {
    public List<T> getSubMenuOptions(U subMenu);
}

`可枚举接口(interface):

package example;

public interface Enumerable {
    public String getName();
}

这是 Menu interface 的实现:

package example;

import java.util.*;

public class SimpleMenu implements Menu<MenuOption> {

    private final Map<MenuOption, String> menuLinks;

    public SimpleMenu() {
        menuLinks = new HashMap<>();
        for(MenuOption option : MenuOption.values()) {
            //Totally arbitrary mapping to avoid adding extra classes and Selenium stuff that is not actually part of
            //the question I'm asking.
            menuLinks.put(option, option.getName());
        }
    }

    public final List<MenuOption> getOptions() {
        Set keys = menuLinks.keySet();
        List<MenuOption> options = new ArrayList<MenuOption>(keys);

        return options;
    }
}

这是 enum class枚举 SimpleMenu 上的选项:

package example;

import java.util.HashMap;
import java.util.Map;

public enum MenuOption implements Enumerable {

    OPTION_ONE("Option One"),
    OPTION_TWO("Option Two");

    private static final Map<String, MenuOption> lookup = new HashMap<>();

    private final String name;

    static {
        for (MenuOption option : MenuOption.values()) {
            lookup.put(option.toString(), option);
        }
    }

    private MenuOption(final String name) {
        this.name = name;
    }

    public final static MenuOption getByName(final String name) {
        return lookup.get(name);
    }

    public final String getName() {
        return name;
    }
}

这是 ParentMenu interface 的实现其中包含 SimpleMenu作为子菜单。下面的 return 语句是我仍然收到“不兼容类型”错误的地方,因为 List<Enumerable>List<MenuOption> 不兼容.

package example;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class ConfigureMenu implements ParentMenu<Enumerable,ConfigureMenu.ConfigureSubMenu> {

    public static enum ConfigureSubMenu implements Enumerable {

        SIMPLE_MENU("An Option");

        private final String name;

        private static final Map<String, ConfigureSubMenu> lookup = new HashMap<>();

        static {
            for (ConfigureSubMenu subMenu : ConfigureSubMenu.values()) {
                lookup.put(subMenu.toString(), subMenu);
            }
        }

        private ConfigureSubMenu(final String name) {
            this.name = name;
        }

        public final String getName() { return name; }

        public static ConfigureSubMenu getByName(String name) {
            return lookup.get(name);
        }
    }

    public final List<Enumerable> getSubMenuOptions(final ConfigureSubMenu subMenu) {
        switch(subMenu) {
            case SIMPLE_MENU:
                List<MenuOption> options = new SimpleMenu().getOptions();
                //This line causes the incompatible types error (List<Enumerable> is not compatible with List<MenuOption>)
                return options;
            default:
                return new ArrayList<>();
        }
    }
}

如何更改我的通用 interfaces 的签名或者我的具体实现的签名,以便我可以摆脱这个错误,并且仍然有一个灵活的通用方法,可以返回父菜单包含的任何子菜单的选项?

注意:自从提出并回答这个问题以来,我已对其进行了多次编辑,以提高质量并明确我的问题和我想要的目标是什么。

最佳答案

Java 泛型可能有点棘手。您的方法返回 List<Enumerable>这意味着“一个恰好保存 Enumerable 类型的列表”。您正在返回 List<MenuOption> ,这是同一类型。相反,您应该定义 getSubMenuOptions在父菜单中为 public List<? extends T> getSubMenuOptions(U subMenu); ,其中List<? extends T>表示“包含实现 T 的某种类型的列表(在本例中为 Enumerable)”。在 ConfigureMenu ,方法实现应定义为 public final List<? extends Enumerable> getSubMenuOptions .

关于使用泛型的更多有用的详细信息是 available here .

关于java - 如何使用 Java 泛型以便为返回类型为 List<Interface> 的方法返回 List<InterfaceImpl>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26315916/

相关文章:

java - 如何对读取属性文件的类进行单元测试

java - LibraryMS 的 Java 条形码阅读器逻辑

c++ - 模板被另一个模块使用时如何工作

java - 如何在枚举上重新实现 valueof

java - 三维数组以错误的顺序到达串行端口

java - Bash 脚本——使用expect 从标准输出读取

java - 无法将 List<SomeClass<SomeClass 的边界类型的子级>> 添加到 List<SomeClass<?>>

java - 如何在kotlin中查看java.util.Collections#copy方法?

java - 要存储在数据库中的枚举

typescript - TS2536 : Type cannot be used to index type ENUM - TS MAPPED TYPES