讲师中心 微信公众号
AI工具推荐 视频效率加速

Java中如何实现事件监听 掌握观察者模式

冬丽吖_9047

冬丽吖_9047

发布时间:2025-06-24 19:23:01

|

1008人浏览过

|

来源于php中文网

原创

java中实现事件监听的核心是观察者模式,具体步骤包括:1.定义事件类封装事件信息;2.定义监听器接口声明响应方法;3.定义事件源维护监听器列表并触发通知;4.实现具体监听器处理事件;5.通过注册与移除监听器控制事件响应。为避免内存泄漏,可采用弱引用、手动移除监听器、谨慎使用匿名内部类或lambda表达式以及检查循环引用等方式。事件监听器基于观察者模式,允许多个监听器被动接收事件通知,适用于界面交互和系统事件;而回调函数由调用者传递给被调用者,主动被调用,常用于异步操作结果处理,通常一对一。观察者模式广泛应用于用户界面框架、消息队列、mvc架构、分布式系统、状态管理、日志系统及监控系统等实际项目场景中。

Java中如何实现事件监听 掌握观察者模式

Java中实现事件监听,核心在于观察者模式的应用。简单来说,就是让一个对象(Subject,被观察者)的状态改变时,自动通知其他对象(Observers,观察者),让他们做出相应的响应。

Java中如何实现事件监听 掌握观察者模式

解决方案 Java实现事件监听主要涉及以下几个关键点:

Java中如何实现事件监听 掌握观察者模式
  1. 定义事件(Event)类: 事件类封装了事件发生时的相关信息。例如,一个按钮点击事件,可以包含按钮的引用、点击时间等。

    public class MyEvent {
        private Object source; // 事件源,通常是触发事件的对象
        private String message; // 事件携带的信息
    
        public MyEvent(Object source, String message) {
            this.source = source;
            this.message = message;
        }
    
        public Object getSource() {
            return source;
        }
    
        public String getMessage() {
            return message;
        }
    }
  2. 定义监听器接口(Listener): 监听器接口定义了观察者需要实现的响应方法。 例如,一个按钮点击监听器,可以包含一个 onClick 方法。

    立即学习“Java免费学习笔记(深入)”;

    Java中如何实现事件监听 掌握观察者模式
    public interface MyEventListener {
        void onEvent(MyEvent event);
    }
  3. 定义事件源(Source): 事件源是事件的触发者,它维护一个监听器列表,并在事件发生时通知这些监听器。

    import java.util.ArrayList;
    import java.util.List;
    
    public class MyEventSource {
        private List<MyEventListener> listeners = new ArrayList<>();
    
        public void addEventListener(MyEventListener listener) {
            listeners.add(listener);
        }
    
        public void removeEventListener(MyEventListener listener) {
            listeners.remove(listener);
        }
    
        // 触发事件的方法
        public void fireEvent(MyEvent event) {
            for (MyEventListener listener : listeners) {
                listener.onEvent(event);
            }
        }
    
        // 模拟事件发生
        public void doSomething() {
            System.out.println("事件源:正在执行某些操作...");
            MyEvent event = new MyEvent(this, "操作已完成!");
            fireEvent(event);
        }
    }
  4. 实现具体的监听器(Concrete Listener): 具体的监听器实现监听器接口,并实现相应的响应方法。

    public class MyConcreteListener implements MyEventListener {
        @Override
        public void onEvent(MyEvent event) {
            System.out.println("监听器收到事件: " + event.getMessage() + ",事件源是:" + event.getSource());
        }
    }
  5. 使用示例:

    public class Main {
        public static void main(String[] args) {
            MyEventSource source = new MyEventSource();
            MyConcreteListener listener = new MyConcreteListener();
    
            source.addEventListener(listener);
            source.doSomething(); // 触发事件
            source.removeEventListener(listener); // 移除监听器
            source.doSomething(); // 不会触发事件,因为没有监听器
        }
    }

Java Swing和JavaFX中的事件监听机制,实际上也是基于这种观察者模式的。

如何避免事件监听器中的内存泄漏?

事件监听器中的内存泄漏通常发生在事件源持有监听器对象的强引用,而监听器对象又持有事件源或其他对象的强引用,导致对象无法被垃圾回收。解决方法如下:

  1. 使用弱引用(WeakReference): 事件源可以使用 WeakReference 来持有监听器对象。这样,当监听器对象不再被其他对象引用时,垃圾回收器可以回收该对象,避免内存泄漏。

    import java.lang.ref.WeakReference;
    import java.util.ArrayList;
    import java.util.List;
    
    public class MyEventSourceWithWeakReference {
        private List<WeakReference<MyEventListener>> listeners = new ArrayList<>();
    
        public void addEventListener(MyEventListener listener) {
            listeners.add(new WeakReference<>(listener));
        }
    
        public void removeEventListener(MyEventListener listener) {
            listeners.removeIf(ref -> ref.get() == listener);
        }
    
        public void fireEvent(MyEvent event) {
            // 使用迭代器,因为在迭代过程中可能会移除失效的弱引用
            for (int i = 0; i < listeners.size(); i++) {
                WeakReference<MyEventListener> ref = listeners.get(i);
                MyEventListener listener = ref.get();
                if (listener != null) {
                    listener.onEvent(event);
                } else {
                    listeners.remove(i); // 移除失效的弱引用
                    i--; // 调整索引,避免跳过元素
                }
            }
        }
    
        public void doSomething() {
            System.out.println("事件源(使用弱引用):正在执行某些操作...");
            MyEvent event = new MyEvent(this, "操作已完成!");
            fireEvent(event);
        }
    }
  2. 手动移除监听器: 当监听器对象不再需要监听事件时,手动从事件源中移除该监听器。例如,在组件销毁时,移除所有注册的监听器。

  3. 使用匿名内部类或Lambda表达式时要谨慎: 如果使用匿名内部类或Lambda表达式作为监听器,要注意它们可能持有外部类的引用,导致外部类无法被垃圾回收。尽量避免在匿名内部类或Lambda表达式中访问外部类的成员变量,或者使用静态内部类来避免持有外部类的引用。

    Java Api Extractor
    Java Api Extractor

    从 Java 项目中提取 Controller 层接口定义为 JSON 数据。

    下载
  4. 检查代码,避免循环引用: 仔细检查代码,确保不存在循环引用。例如,A 对象持有 B 对象的引用,B 对象又持有 A 对象的引用。

事件监听器和回调函数有什么区别?

事件监听器和回调函数都是处理异步操作的常用方式,但它们之间存在一些区别:

  • 事件监听器: 基于观察者模式,事件源在特定事件发生时通知所有注册的监听器。监听器是被动地接收事件通知。事件监听器通常用于处理用户界面交互、系统事件等。事件监听器可以有多个,一个事件可以被多个监听器同时监听。
  • 回调函数: 回调函数是由调用者传递给被调用者的一个函数,被调用者在完成特定任务后调用该函数。回调函数是主动地被调用者调用。回调函数通常用于处理异步操作的结果、定时任务等。回调函数通常只有一个,一个异步操作通常只有一个回调函数。

从实现的角度来看,事件监听器通常需要定义事件类、监听器接口和事件源,而回调函数只需要定义一个函数接口即可。

观察者模式在实际项目中的应用场景有哪些?

观察者模式在实际项目中应用非常广泛,以下是一些常见的应用场景:

  1. 用户界面框架: 例如,Java Swing 和 JavaFX 中的事件处理机制就是基于观察者模式的。按钮点击、鼠标移动等事件发生时,会通知所有注册的监听器。

  2. 消息队列: 消息队列中的生产者和消费者之间也是一种观察者模式。生产者发布消息,消费者订阅消息,当有新消息到达时,消息队列会通知所有订阅者。

  3. 模型-视图-控制器(MVC)框架: 在 MVC 框架中,模型(Model)发生变化时,会通知所有注册的视图(View),以便视图能够及时更新。

  4. 分布式系统: 在分布式系统中,可以使用观察者模式来实现服务之间的解耦和异步通信。例如,一个服务可以发布事件,其他服务可以订阅这些事件,从而实现服务之间的松耦合。

  5. 状态管理: 在某些应用程序中,需要维护一个全局的状态,当状态发生变化时,需要通知所有依赖于该状态的组件。可以使用观察者模式来实现这种状态管理。例如,Redux 和 Vuex 等状态管理库就使用了观察者模式的思想。

  6. 日志系统: 日志系统可以看作是一个事件源,当有新的日志产生时,会通知所有注册的日志处理器,以便将日志写入文件、数据库或发送到远程服务器。

  7. 监控系统: 监控系统可以监控系统的各种指标,当指标超过预设的阈值时,会通知所有注册的告警处理器,以便及时采取措施。

热门AI工具

更多
SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

Flowith
Flowith Hot

Flowith是一款基于画布和智能体工作流的 AI 协作工作空间。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

码上飞
码上飞 Hot

一款基于自然语言的AI应用开发平台,可根据用户描述自动生成应用程序,帮助个人和团队快速完成应用原型与开发。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
什么是分布式
什么是分布式

分布式是一种计算和数据处理的方式,将计算任务或数据分散到多个计算机或节点中进行处理。本专题为大家提供分布式相关的文章、下载、课程内容,供大家免费下载体验。

2133

2023.08.11

分布式和微服务的区别
分布式和微服务的区别

分布式和微服务的区别在定义和概念、设计思想、粒度和复杂性、服务边界和自治性、技术栈和部署方式等。本专题为大家提供分布式和微服务相关的文章、下载、课程内容,供大家免费下载体验。

3454

2023.10.07

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

1091

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

345

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

614

2026.01.05

C++ Lambda 表达式与函数式编程
C++ Lambda 表达式与函数式编程

深入讲解 C++ Lambda 表达式与函数式编程范式,涵盖 Lambda 基础语法与返回值推导、值捕获与引用捕获的区别与陷阱、初始化捕获(C++14 广义捕获)、泛型 Lambda(auto 参数)、mutable 关键字修改捕获变量、std::function 类型擦除与函数包装、std::bind 参数绑定(及其被 Lambda 替代的趋势)、Lambda 在 STL 算法(sort/transform/for_each/remo

769

2026.05.06

Java 函数式接口与 Lambda 进阶技巧
Java 函数式接口与 Lambda 进阶技巧

在 Java Stream 基础之上进一步深入函数式编程,涵盖 @FunctionalInterface 注解与自定义函数式接口设计、四种方法引用(静态/实例/对象/构造器)的使用场景、Lambda 中的 effectively final 变量捕获规则、函数组合(andThen/compose)与柯里化技巧、Comparator 链式比较器构建、CompletableFuture 异步函数式编排、Reactor / RxJava 响应

428

2026.05.08

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

3208

2023.10.19

Tailwind CSS 如何制作导航栏和卡片
Tailwind CSS 如何制作导航栏和卡片

用 Tailwind CSS 制作导航栏和卡片,可先搭建语义化结构,再组合 Flex、Grid、间距、圆角与阴影类。这里整理横向导航、移动端菜单、卡片网格及悬停效果的相关文章,帮助你把常见页面组件做得清晰且适配不同屏幕。

0

2026.11.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn