我们连续写了两小节的教师-学生的例子,必然觉得无聊死了,这样的例子我们就是玩上100遍,还是不知道该怎么写真实的代码。那从本节开始,我们开始往真实代码上面去靠拢。

事件最容易理解的例子是鼠标事件:我们点击鼠标,鼠标发送指令,执行代码。

一:鼠标点击事件处理模型基础版

这个时候,我们必须去查看下JDK中相关类型。对照着上一节《从零开始理解JAVA事件处理机制(2)》中的UML图,我们很快发现,对应HomeworkListener,JDK中有MouseListener,其实我们靠分析也能得知,MouseListener继承自EventListener。现在既然有了接口MouseListener了,那我们必定会有一个实现类,这个类假设叫做:ConcreteMouseListener。不妨先实现之:

package com.zuikc.events;

import java.awt.event.MouseEvent;

import java.awt.event.MouseListener;

public class ConcreteMouseListener implements MouseListener {

public ConcreteMouseListener(){

}

@Override

public void mouseClicked(MouseEvent e) {

System.out.printf("我被{%s}点了一下,MD痒死了~~", e.getSource().toString());

}

@Override

public void mousePressed(MouseEvent e) {

// TODO Auto-generated method stub

}

@Override

public void mouseReleased(MouseEvent e) {

// TODO Auto-generated method stub

}

@Override

public void mouseEntered(MouseEvent e) {

// TODO Auto-generated method stub

}

@Override

public void mouseExited(MouseEvent e) {

// TODO Auto-generated method stub

}

}

我们为单击的事件处理器添加业务代码。

事件处理器:监听器的具体实现类的实现方法,就叫事件处理器。

接下来要看什么,当然是MouseEvent。MouseEvent,这个JDK中的类相对来说,就稍微有点大了,起构造方法的参数有点多,不过没有关系呀,我们慢慢看,我先说这个类要怎么用,即怎么new出来。

/*

* 这里的new Component() {} 就是 event.getSource() 得到的事件源 source

*/

MouseEvent event = new MouseEvent(new Component() {}, 1, 1, 1,2,3,4,false);

在实际且正常的情况下,MouseEvent是没有必要自己new的,JAVA运行时会捕获硬件鼠标的点击动作,由虚拟机底层为我们生成该实例对象(下文会为我们分析这一点),但是我们此时此刻我们是先模拟呀,所以不妨碍我们自己胡乱new一个出来。注意,new不是问题,问题的关键我们必须知道其构造器参数的意义,而其中核心关键参数就是第一个参数,new Component(),这是什么?这就是那个事件源!回头看看我们的教师学生版本是在哪里生产事件的:

public void setHomework(String homework) {

System.out.printf("%s布置了作业%s \n", this.name, homework);

homeworks.add(homework);

HomeworkEventObject event = new HomeworkEventObject(this);

/*

* 在观察者模式中,我们直接调用Observable的notifyObservers来通知被观察者

* 现在我们只能自己通知了~~

*/

for (HomeworkListener listener : homeworkListenerList) {

listener.update(event, homework);

}

}

是在Teacher的业务代码setHomework中。所以,在当前的我们要写的这个例子中,new MouseEvent要在哪里呢?我们在Button的业务代码中,Button是谁,Button就类似Teacher,但又不完全等同Teacher,在Teacher中,Teacher本身就是事件源,所以它这个this作为参数传入进了HomeworkEventObject,而Button不能作为参数传入进MouseEvent,因为我不打算让Button继承自Component,所以我们先new了一个临时的Component。OK,分析到了这里,我们自己的Button代码大概就出来了,是这个样子的:

package com.zuikc.events;

import java.awt.AWTEvent;

import java.awt.AWTEventMulticaster;

import java.awt.Component;

import java.awt.event.MouseEvent;

import java.awt.event.MouseListener;

import java.awt.peer.LightweightPeer;

public class Button {

private MouseListener mouseListener;

public void addMouseListener(MouseListener l) {

mouseListener = l;

}

public void doClick(){

/*

* 这里的new Component() {} 就是 event.getSource() 得到的事件源 source

*/

MouseEvent event = new MouseEvent(new Component() {}, 1, 1, 1,2,3,4,false);

//event.getSource();

this.mouseListener.mouseClicked(event);

}

}

至此,我们可以画出清晰的类图了,来看:

顺便我们看一下Client端的代码:

public static void main(String[] args) {

ConcreteMouseListener listener = new ConcreteMouseListener();

Button button = new Button();

button.addMouseListener(listener);

button.doClick();

}

运行一下吧,你应该得到一句类似这样的输出:

我被{com.zuikc.events.Button$1[,0,0,0x0,invalid]}点了一下,MD痒死了~~

二,一个正常的窗体程序的样子

上面,我们尽量偏向于教师学生的例子,写出了鼠标事件的基础版本,但是说好的程序本来的样子呢?来,我们接下来写个正常的程序,99.9%在人在写窗体程序的时候就是如下这么写的。我知道你们又会有人上来骂了,什么,java,窗体程序?我TMD学JAVA是为了EE开发的,企业开发的。现在,我们先说好不好互相伤害,要知道,即便是NB如JAVA,最先也是先从窗体发迹的,并且,JAVA的窗体框架推倒重写了还不止一次。所以,窗体的事件你明白了,EE中那些框架的事件碰到了简直跟切白菜一样。

言归正传,看代码:

package com.zuikc.events;

import java.awt.event.MouseEvent;

import java.awt.event.MouseListener;

import javax.swing.JButton;

import javax.swing.JFrame;

public class Client {

public static void main(String[] args) {

new DemoFrame();

}

}

class DemoFrame extends JFrame implements MouseListener {

public DemoFrame() {

super("demo");

this.setSize(500, 400);

this.setLocationRelativeTo(null);

this.getContentPane().setLayout(null);

this.setVisible(true);

JButton button1 = new JButton("ok");

button1.setBounds(8, 8, 80, 80);

button1.addMouseListener(this);

this.getContentPane().add(button1);

}

@Override

public void mouseClicked(MouseEvent e) {

System.out.printf("我被{%s}点了一下,MD痒死了~~", e.getSource().toString());

}

@Override

public void mousePressed(MouseEvent e) {

}

@Override

public void mouseReleased(MouseEvent e) {

}

@Override

public void mouseEntered(MouseEvent e) {

}

@Override

public void mouseExited(MouseEvent e) {

}

}

这段代码什么意思?最简单了,就是创建了一个窗体,窗体上放置了一个按钮,点击了之后,执行了一行代码。这简简单单的一个文件,没多少行代码,实际上就实现了我们上文中一堆类中实现的功能。来吧,我们分析吧,把监听器、事件处理器、事件、事件源都指出来。

监听器:DemoFrame就是监听器,对应ConcreteMouseListener;

事件处理器:MouseClicked方法就是监听器,ConcreteMouseListener里面也有这个方法;

事件:看不到了,怎么办?

事件源:看不到了,怎么办?

注意,窗体本身就监听器,所以上文代码中为button添加监听器怎么做?button1.addMouseListener(this);没错,就是把自身添加进去。

然后,事件和事件源都看不到了,这个时候怎么办?我们如果看输出的话,上文代码的输出为:

我被{javax.swing.JButton[,8,8,80x80,invalid,alignmentX=0.0,alignmentY=0.5,border=javax.swing.plaf.BorderUIResource$CompoundBorderUIResource@7fda7dfe,flags=296,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=2,left=14,bottom=2,right=14],paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=true,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=ok,defaultCapable=true]}点了一下,MD痒死了~~

看上去,类似我们上文第一部分代码的输出,也是JButton业务代码运行过程中生成的一个变量,但它是在哪里生成的,在哪里产生的,我们并不知道。不过没关系,我们看调试堆栈!

一步步的往上追,我们终于追到了这里:

由此可见,MouseEvent也是在业务代码里new出来了,大家可能要为,那这个重要的第一个参数target呢?target可是事件源也很重要,道理很简单,往上继续追,限于篇幅,这里不在展开,它在某个你愿意看到它的地方被new出来了。

现在我们补齐回答,

事件:JAVA运行时捕获到硬件鼠标触发,从而调用了事件处理器,在事件处理器内部生成的这个MouseEvent,就是事件;

事件源:JAVA运行时捕获到硬件鼠标触发,从而调用了事件处理器,在事件处理器内部生成的这个target,就是事件源;

三:正常版的上文第一部分的代码

按照二中的代码来写,我们第一部分的代码应该是什么样子的呢?

一和二放在一起比较,其实只要改两个地方,一中的代码就和二中完全一致了,

1:将ConcreteMouseListener命名为DemoFrame;

2:将Button实例由客户端放置到ConcreteMouseListener内部;

OK,事件就是这么简单。

该系列的第一部分和第二部分分别在:

java事件处理模型_从零开始理解JAVA事件处理机制(3)相关推荐

  1. 全面理解java内存模型_深入理解Java内存模型(八)——总结

    处理器内存模型 顺序一致性内存模型是一个理论参考模型,JVM和处理器内存模型在设计时通常会把顺序一致性内存模型作为参照.JVM和处理器内存模型在设计时会对顺序一致性模型做一些放松,因为如果完全按照顺序 ...

  2. java 线程 原子性_深入理解Java多线程与并发框架——Java内存模型与原子性、可见性、有序性...

    欢迎关注专栏<Java架构筑基>--专注于Java技术的研究与分享!Java架构筑基​zhuanlan.zhihu.comJava架构筑基--专注于Java技术的研究与分享! 后续文章将首 ...

  3. java stringbuffer原理_深入理解Java:String

    在讲解String之前,我们先了解一下Java的内存结构. 一.Java内存模型 按照官方的说法:Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配. JVM主要管理两 ...

  4. java 内存模型6_深入理解Java内存模型(六)——final

    与前面介绍的锁和volatile相比较,对final域的读和写更像是普通的变量访问.对于final域,编译器和处理器要遵守两个重排序规则: 在构造函数内对一个final域的写入,与随后把这个被构造对象 ...

  5. java对象实例_深入理解Java对象实例生成的例子!(转)

    深入理解Java对象实例生成的例子!(转)[@more@]代码如下: class A { public int Avar; public A() { System.out.println(" ...

  6. java 常量折叠_深入理解Java虚拟机之早期编译器优化

    Javac编译器 Javac编译器是一个由Java语言编写的程序 Javac的源码与调试 从Sun Javac的代码来看,编译器大致分为3个过程: 解析与填充符号表的过程 插入式注解处理器的注解处理过 ...

  7. sas java 虚拟机异常_深入理解JAVA虚拟机之异常诊断

    常见的JAVA虚拟机HotSpot虚拟机运行时数据库由5部分构成:方法区,堆,虚拟机栈,本地方法栈,程序计数器.下面列举各个部分可能出现的异常及其出现原因. 1.方法区存放的已被虚拟机加载的类型信息, ...

  8. java class教程_深入理解Java Class文件格式(七)

    本专栏列前面的一系列博客, 对Class文件中的一部分数据项进行了介绍. 本文将会继续介绍class文件中未讲解的信息. 先回顾一下上面一篇文章. 在上一篇博客中, 我们介绍了: this_class ...

  9. java 准备 解析_深入理解JAVA虚拟机学习笔记24——类加载的准备和解析

    每天进步一点点! 今天我们一起看一下类加载的准备阶段和解析阶段. 先看一下准备阶段:主要任务是在方法区中为类变量(仅static修饰变量,不包含实例变量)分配内存并设置类变量初始化的阶段. 这里面的区 ...

最新文章

  1. python 同时打乱多个列表
  2. 模态框之Uncaught Error: Syntax error, unrecognized expression:
  3. java RSA加密解密--转载
  4. 02_混淆矩阵、准确率(Accuracy)、精确率(Precision)、召回率(Recall)、F值(F-Measure) +Roc曲线和PR曲线+sklearn中分类模型评估API+ 自己补充整理
  5. C语言 va_arg 宏 - C语言零基础入门教程
  6. Sql中对大数据量的判断
  7. 查看驱动安装错误日志
  8. iOS开发 - 获取手机总空间、剩余空间,文件夹占用空间大小
  9. 《sort命令的k选项大讨论》-linux命令五分钟系列之二十七
  10. 卡巴斯基:揭开“火焰”病毒(Flame)的神秘面纱
  11. Android EditText 不得不说的InputFilter、TextWatcher、ActionMode.Callback、OnEditorActionListener
  12. 最齐全的日用电商设计模板素材,速来收藏
  13. 补全缺失的64位dll,0xc000007b
  14. 家用简单电线路图_6种简单电路图
  15. [4G5G专题-27]:架构-UE终端的4G+5G双连接详解
  16. auc评测指标如何计算?其他的评测指标有吗?假设阙值为0.5,如何计算这个点?
  17. 量子近似优化算法QAOA——解读与代码实现
  18. word无法验证服务器,Win8系统打开office文件提示“无法验证此产品的许可证”如何解决...
  19. JS之数组 创建数组 访问数组和数组的长度 数组的相关方法
  20. Supervisor的使用

热门文章

  1. 左神讲算法——二分法及其拓展
  2. 将Tensor核心引入标准Fortran
  3. h265webplayer
  4. KITTI数据集上MaskRCNN检测效果示例
  5. Android App的启动过程
  6. 2021年大数据ELK(十七):Elasticsearch SQL 订单统计分析案例
  7. 2021年大数据Spark(八):环境搭建集群模式 Standalone HA
  8. Python:XPath与lxml类库
  9. DCN-2655 ssh 远程登陆配置
  10. Android TextView textAppearance