我正在尝试为Java创建一个GUI库,并计划使用Java 8 lambda表达式使其高度可扩展,从而使其成为事件驱动。
目前我有两种类型的事件。第一种是GuiEvent,它不是泛型的。然而,第二种指定了一个泛型参数:
"onEvent" 看起来像下面这样:
它是
如预期所示,它不会对
现在我尝试了几种方法来参数化
这使情况变得更糟,因为它现在显示了编译警告:
由于某种奇怪的原因,将类变量更改为
按钮,带参数化的。
示例图形用户界面
组件和动作事件:
目前我有两种类型的事件。第一种是GuiEvent,它不是泛型的。然而,第二种指定了一个泛型参数:
ComponentEvent<T extends GuiComponent<?, ?>>
,以便以后可以使用以下lambda捕获事件:button.onEvent((event) -> {
// event.component is supposed to be of the type ComponentEvent<Button>
System.out.println("Test button pressed! " + ((Button) event.component).getText());
}, ActionEvent.class);
"onEvent" 看起来像下面这样:
public <EVENT extends ComponentEvent<?>> O onEvent(EventListener<EVENT> listener, Class<EVENT> clazz) {
return onEvent(listener, clazz, Side.CLIENT);
}
它是
GuiComponent<O extends GuiComponent<O, T>, T extends NativeGuiComponent>
的一部分...在我们的情况下,由于我们监听的组件是按钮,因此可以简化为 Button<Button, NativeButton>
,因此派生类型 O
是 Button
。如预期所示,它不会对
ComponentEvent<?>
进行参数化,因此 event.component
的类型正确地是 GuiComponent<?, ?>
,这使得强制转换成为必需。现在我尝试了几种方法来参数化
ComponentEvent
,从以下方式开始:public <EVENT extends ComponentEvent<O>> O onEvent(EventListener<EVENT> listener, Class<EVENT> clazz) {
return onEvent(listener, clazz, Side.CLIENT);
}
这使情况变得更糟,因为它现在显示了编译警告:
Type safety: Unchecked invocation onEvent(EventListener<ComponentEvent.ActionEvent>,
Class<ComponentEvent.ActionEvent>) of the generic method
onEvent(EventListener<EVENT>, Class<EVENT>) of type
GuiComponent<Button,NativeButton>
由于某种奇怪的原因,将类变量更改为
ActionEvent.class.asSubclass(Button.class)
可以编译,给我event.component
的正确类型,但是当然后来由于ClassCastException而崩溃......
编辑:以下是涉及到的所有类定义的列表:
基类GuiComponent:
public abstract class GuiComponent<O extends GuiComponent<O, T>,
T extends NativeGuiComponent> implements Identifiable,
EventListener<GuiEvent>, PacketHandler {
private SidedEventBus<ComponentEvent<?>> eventListenerList = new SidedEventBus<ComponentEvent<?>>(this::dispatchNetworkEvent);
...
public <EVENT extends ComponentEvent<?>> O onEvent(EventListener<EVENT> listener, Class<EVENT> clazz, Side side) {
eventListenerList.add(listener, clazz, side);
return (O) this;
}
public <EVENT extends ComponentEvent<?>> O onEvent(EventListener<EVENT> listener, Class<EVENT> clazz) {
return onEvent(listener, clazz, Side.CLIENT);
}
...
按钮,带参数化的。
public class Button extends GuiComponent<Button, NativeButton> {
示例图形用户界面
Gui testGUI = new Gui("testgui")
.add(new Button("testbutton2", "I'm EAST")
.setMaximumSize(Integer.MAX_VALUE, 120)
.onEvent((event) -> {
System.out.println("Test button pressed! " + Side.get());
}, ActionEvent.class), Anchor.EAST)
.add(new Button("testbutton3", "I'm CENTER"))
.add(new Button("testbutton4", "I'm SOUTH"), Anchor.SOUTH)
.add(new GuiContainer("container").setLayout(new FlowLayout())
.add(new Button("testbutton5", "I'm the FIRST Button and need lots of space"))
.add(new Label("testlabel1", "I'm some label hanging around").setBackground(new Background(Color.white)))
.add(new Button("testbutton7", "I'm THIRD"))
.add(new Button("testbutton8", "I'm FOURTH"))
, Anchor.NORTH)
.onGuiEvent((event) -> {
System.out.println("Test GUI initialized! " + event.player.getDisplayName() + " " + event.position);
}, BindEvent.class)
.onGuiEvent((event) -> {
System.out.println("Test GUI closed!");
}, UnBindEvent.class);
guiFactory.registerGui(testGUI, id);
组件和动作事件:
public abstract class ComponentEvent<T extends GuiComponent<?, ?>> extends CancelableEvent implements SidedEvent {
public final T component;
public ComponentEvent(T component) {
this.component = component;
}
public static class ActionEvent<T extends GuiComponent<?, ?>> extends ComponentEvent<T> {
public ActionEvent(T component) {
super(component);
}
}
...
ClassCastException
吗?我对这个问题很感兴趣(我喜欢泛型!),但我并不完全明白为什么<EVENT extends ComponentEvent<O>>
会失败。您是否理解了“未经检查的调用”警告,并且即使它发出警告,它是否仍然有效?虽然上次类似的事情发生在我身上时,我在模板方法中失去了我的泛型(http://stackoverflow.com/questions/28234960/java-generics-and-enum-loss-of-template-parameters this)。 - EpicPandaForceO
应该可以工作...完整的代码可以在这里找到:https://github.com/NOVAAPI/NovaCore/tree/master/src/main/java/nova/core/gui,但是可能很难阅读所有内容。 - VicActionEvent
是从哪里来的?它的类型声明是什么?为什么ComponentEvent
的类型参数是T extends GuiComponent<?, ?>
?难道你不能根据 T 缩小 GuiComponent 的类型参数,而不是使用<?, ?>
吗? - fps