JavaFX-8:为什么EventType是通用的?
EventType系统在JavaFX中非常容易混淆。 我认为这是因为设计师们决定 EventType类本身是泛型的 这有什么实际用途吗?或者这只是一些 确保类型安全的模糊形式JavaFX-8:为什么EventType是通用的?,java,events,generics,javafx-8,Java,Events,Generics,Javafx 8,EventType系统在JavaFX中非常容易混淆。 我认为这是因为设计师们决定 EventType类本身是泛型的 这有什么实际用途吗?或者这只是一些 确保类型安全的模糊形式 我可以想象,只有当泛型类型返回给调用类的某个地方时,类才会成为泛型的。否则有什么意义呢?有事件类,即事件的子类,它们定义了该类的特定方法。例如,MouseEvent定义了事件发生时可用于查询鼠标坐标的各种方法(getX(),getY(),getSceneX(),getScreenX()等)ScrollEvent定义查询滚动
我可以想象,只有当泛型类型返回给调用类的某个地方时,类才会成为泛型的。否则有什么意义呢?有
事件
类,即事件
的子类,它们定义了该类的特定方法。例如,MouseEvent
定义了事件发生时可用于查询鼠标坐标的各种方法(getX()
,getY()
,getSceneX()
,getScreenX()
等)ScrollEvent
定义查询滚动金额和方向的方法:getDeltaX()
,getDeltaY()
,等等)
EventType
是一个更细粒度的对象,用于指定发生了什么。因此,EventType
类的常量包括单击的鼠标
,按下的鼠标
,键入的键
,滚动
,等等。这些值中的每一个都与特定的事件
子类相关联
事件注册方法是addEventHandler(…)
。此方法采用两个参数:一个是EventType
(要侦听的事件类型),另一个是EventHandler
。EventHandler
是通用的,原因很明显:通过定义EventHandler
,您可以定义一个handle(T event)
方法,该方法采用适当的事件对象,然后您可以以特定于类型的方式进行查询。(例如,EventHandler
有一个句柄(MouseEvent事件)
方法,可以查询鼠标的坐标等)
现在,显然只有为与事件子类T
关联的EventType
注册EventHandler
才有意义。此外,最好允许编译器强制执行这一点。通过使EventType
类成为泛型:EventType
,我们可以让编译器强制执行此规则鼠标单击的
不仅仅是事件类型
的一个实例,它还是事件类型
的一个实例。由于addEventHandler(…)
方法的签名是addEventHandler(EventType,EventHandler)
,因此编译器强制处理程序与事件类型为“同一类事件”
当您将此功能与使用lambdas(或者我认为是与类型推断结合使用)相结合时,它会变得非常强大:
node.addEventHandler(MOUSE_CLICKED, e -> {...});
因为单击的鼠标
是一个事件类型
,编译器能够推断lambda定义的事件处理程序是一个事件处理程序
,因此e
是一个MouseEvent
。所以编译器现在可以推断
node.addEventHandler(MOUSE_CLICKED, e -> System.out.println(e.getX()));
node.addEventHandler(KEY_TYPED, e -> System.out.println(e.getText()));
是合法的,但是
node.addEventHandler(MOUSE_CLICKED, e -> System.out.println(e.getText()));
事实并非如此。如果EventType
不是泛型,则不可能这样做
(没有lambdas也是如此,但不那么简洁的语法也不能让人理解这一点。但是如果EventType
不是泛型的,编译器就没有办法拒绝
node.addEventHandler(MOUSE_CLICKED, new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) { }
});
node.addEventHandler(单击鼠标,新建EventHandler()){
@凌驾
公共无效句柄(KeyEvent事件){}
});
同样,点击的鼠标具有类型EventType
,这意味着它将无法编译。)
从技术上讲,EventType
用作“运行时类型令牌”。它不仅用于说明我们感兴趣的事件,还用于说明应该使用哪种类型的事件处理程序来处理事件。泛型用法的其他示例包括Class
:有关简要讨论,请参阅。,这样您就不必每次访问子类的方法时都强制转换子类。我还假设这对。请参阅:“当lambda表达式只有一个参数且其类型被推断时,括号不是必需的”。我的问题是为什么类EventType是泛型的。这篇文章提到了我完全理解的为什么EventHandler是通用的。但为什么是EventType??将EventType视为,它需要知道并强制执行它正在处理的事件类型。集合对于type是泛型的,因为它在某些方法中将T返回给调用类。EventHandler是type的泛型,因为在handle方法中(在调用类中被重写),它使程序能够获取特定的事件类型。换句话说,这两种情况都避免了调用程序必须强制转换。这是我能想象的泛型的唯一两种用途。但就我所见,这两个都不适用于EventType。那么为什么它是通用的呢?有一些解释。谢谢虽然我没有看到与运行时类型标记的并行。这里的用法似乎专门针对编译时,而不是运行时?似乎EventType被专门设置为泛型,以便在方法addEventHandler(EventType,EventHandler)中,如果使用lambda,编译器可以推断类型参数。如果EventType不是泛型的,则必须使用旧的表单:new EventHandler,或者如果使用lambda,则默认为Event作为类型。有了这个特性,我们就可以使用提供了特定类型的lambda了?据我所知,“运行时类型令牌”是指表示另一个实体的运行时类型的令牌。这可能不是一个标准(或准确)的解释。因此这里的EventType
对象是一个表示事件处理程序运行时类型的令牌。它不仅适用于使用lambdas,在使用任何EventHandler
实现时也是如此。只是lambda表达式附带的增强类型推断使它更明显有用。请参阅答案的更新。