我正在尝试建模一个可以包含子菜单的菜单的菜单系统。我想要一个通用的interface
用于从菜单和子菜单中通过其父菜单检索选项,我在设计它时遇到了麻烦,同时保持其类型安全,灵活且没有编译时“不兼容类型”错误。我试图通过使用Java泛型为简单菜单指定Menu interface
和为父菜单指定ParentMenu interface
来实现我的目标,父菜单使用方法参数和返回类型的泛型类型参数。
我有第三个Enumerable interface
用于表示特定菜单上的可用选项。 implement
Enumerable interface
所有enum classes
的类都列举了菜单上的选项。父菜单可以容纳许多子菜单,我想要一个通用的单一方法,允许父菜单类的客户端获取其任何一个子菜单的选项。
父菜单具体class
有一个方法,其签名指定返回值List<Enumerable>
。我希望能够返回List<MenuOption>
MenuOption
implements
Enumerable interface
的{{1}}。但是,我收到一条错误消息,指出我要返回的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);
}
`可枚举的界面:
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
作为子菜单。以下返回语句是我仍然收到“不兼容类型”错误的原因,因为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
的签名或我的具体实现的签名,以便我可以摆脱此错误,仍然有一个灵活的通用方法,可以返回任何子菜单的选项包含在父菜单中?
注意:我已经多次编辑过这个问题,因为它被提问和回答是为了提高质量,并清楚地表明我的问题和我希望的目标是什么。
答案 0 :(得分:3)
Java泛型可能有点棘手。您的方法返回List<Enumerable>
,这意味着&#34;一个列表,其中完全符合类型Enumerable &#34;。您将返回List<MenuOption>
,不是相同的类型。相反,您应该在ParentMenu中将getSubMenuOptions
定义为public List<? extends T> getSubMenuOptions(U subMenu);
,其中List<? extends T>
表示&#34;一个List,其中包含一些实现T的类型(在本例中为Enumerable)&#34;。在ConfigureMenu
中,方法实现应定义为public final List<? extends Enumerable> getSubMenuOptions
。
有关使用泛型的更多有用详细信息是available here。
答案 1 :(得分:0)
List<MenuOption>
不是List<Enumerable>
的类型,因为您无法向其中添加任何Enumerable
。您可以改为返回List<? extends Enumerable>
:
public final List<? extends Enumerable> getSubMenuOptions
(final ConfigureSubMenu subMenu) {
switch(subMenu) {
case SIMPLE_SUB_MENU:
List<MenuOption> options = new SimpleSubMenu().getOptions();
return options;
}
}