Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaFX-8:为什么EventType是通用的?_Java_Events_Generics_Javafx 8 - Fatal编程技术网

JavaFX-8:为什么EventType是通用的?

JavaFX-8:为什么EventType是通用的?,java,events,generics,javafx-8,Java,Events,Generics,Javafx 8,EventType系统在JavaFX中非常容易混淆。 我认为这是因为设计师们决定 EventType类本身是泛型的 这有什么实际用途吗?或者这只是一些 确保类型安全的模糊形式 我可以想象,只有当泛型类型返回给调用类的某个地方时,类才会成为泛型的。否则有什么意义呢?有事件类,即事件的子类,它们定义了该类的特定方法。例如,MouseEvent定义了事件发生时可用于查询鼠标坐标的各种方法(getX(),getY(),getSceneX(),getScreenX()等)ScrollEvent定义查询滚动

EventType系统在JavaFX中非常容易混淆。 我认为这是因为设计师们决定 EventType类本身是泛型的

这有什么实际用途吗?或者这只是一些 确保类型安全的模糊形式


我可以想象,只有当泛型类型返回给调用类的某个地方时,类才会成为泛型的。否则有什么意义呢?

事件
类,即
事件
的子类,它们定义了该类的特定方法。例如,
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表达式附带的增强类型推断使它更明显有用。请参阅答案的更新。