0

0

Java程序中持久化ArrayList数据:文件序列化实践

霞舞

霞舞

发布时间:2025-10-30 18:21:34

|

1032人浏览过

|

来源于php中文网

原创

Java程序中持久化ArrayList数据:文件序列化实践

java程序中,`arraylist`等内存数据在程序关闭后会丢失。本教程将介绍如何利用java的对象序列化机制,通过`objectoutputstream`和`objectinputstream`将`arraylist`中的数据保存到本地文件,并在程序启动时重新加载,从而实现数据的持久化,确保用户输入等信息能够跨多次程序运行而保留。

了解数据持久化的必要性

当我们在Java程序中使用ArrayList来存储用户输入或其他动态数据时,这些数据默认只存在于程序的运行时内存中。一旦程序执行完毕或被关闭,内存中的所有数据都会被清除,导致之前输入的信息丢失。例如,一个收集用户姓名和ID的程序,如果每次运行都重新初始化ArrayList,那么之前输入的所有用户数据都会消失。为了解决这个问题,我们需要一种机制来将内存中的数据“保存”到非易失性存储(如硬盘文件或数据库),并在程序再次启动时“加载”这些数据。

Java对象序列化实现数据持久化

Java提供了一种内置的机制,称为“对象序列化”(Object Serialization),允许我们将一个对象的完整状态(包括其内部字段的值)转换为字节流,然后可以将这个字节流保存到文件、传输到网络等。反之,通过“反序列化”(Deserialization),我们可以从字节流中重建出原始对象。这正是解决ArrayList数据持久化问题的理想方案。

核心类:ObjectOutputStream与ObjectInputStream

  • ObjectOutputStream: 用于将Java对象写入到输出流。它能将实现了Serializable接口的对象转换为字节流。
  • ObjectInputStream: 用于从输入流中读取Java对象。它能将之前由ObjectOutputStream写入的字节流反序列化为Java对象。

实现数据保存与加载功能

为了方便地保存和加载ArrayList,我们可以编写两个通用的静态方法:

  1. saveArrayList(ArrayList> arr, String filename): 将ArrayList保存到指定文件。
  2. loadArrayList(String filename): 从指定文件加载ArrayList。
import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class DataPersistenceUtil {

    /**
     * 将ArrayList对象保存到指定文件
     * @param arr 要保存的ArrayList实例
     * @param filename 保存数据的文件名
     */
    public static <T> void saveArrayList(ArrayList<T> arr, String filename) {
        ObjectOutputStream oos = null;
        try {
            // 创建文件输出流
            FileOutputStream fos = new FileOutputStream(filename);
            // 创建对象输出流
            oos = new ObjectOutputStream(fos);
            // 将ArrayList对象写入流
            oos.writeObject(arr);
            System.out.println("数据已成功保存到文件:" + filename);
        } catch (IOException e) {
            System.err.println("保存数据时发生IO错误:" + e.getMessage());
            e.printStackTrace();
        } finally {
            // 确保流被关闭
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    System.err.println("关闭ObjectOutputStream时发生错误:" + e.getMessage());
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 从指定文件加载ArrayList对象
     * @param filename 包含ArrayList数据的文件名
     * @return 加载的ArrayList对象,如果加载失败则返回null
     */
    @SuppressWarnings("unchecked") // 抑制未经检查的类型转换警告
    public static <T> ArrayList<T> loadArrayList(String filename) {
        ObjectInputStream ois = null;
        try {
            // 创建文件输入流
            FileInputStream fis = new FileInputStream(filename);
            // 创建对象输入流
            ois = new ObjectInputStream(fis);
            // 从流中读取对象并进行类型转换
            ArrayList<T> arr = (ArrayList<T>) ois.readObject();
            System.out.println("数据已成功从文件加载:" + filename);
            return arr;
        } catch (FileNotFoundException e) {
            System.out.println("数据文件未找到,将创建新的ArrayList。");
            return new ArrayList<>(); // 文件不存在时,返回一个新的空列表
        } catch (IOException e) {
            System.err.println("加载数据时发生IO错误:" + e.getMessage());
            e.printStackTrace();
            return null;
        } catch (ClassNotFoundException e) {
            System.err.println("加载数据时类未找到:" + e.getMessage());
            e.printStackTrace();
            return null;
        } finally {
            // 确保流被关闭
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    System.err.println("关闭ObjectInputStream时发生错误:" + e.getMessage());
                    e.printStackTrace();
                }
            }
        }
    }
}

重要提示:

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

  • 泛型支持: 上述代码使用了泛型,使其可以用于保存和加载任何类型的ArrayList。
  • Serializable接口: 任何要通过ObjectOutputStream写入的对象(包括ArrayList中的元素),都必须实现java.io.Serializable接口。ArrayList本身已经实现了Serializable接口,但如果ArrayList中存储的是自定义对象(例如User对象),那么User类也必须实现Serializable接口。
  • 异常处理: 良好的异常处理是必不可少的,包括IOException、FileNotFoundException和ClassNotFoundException。finally块确保流总能被关闭,防止资源泄露。

整合到实际应用中

现在,我们将上述持久化方法整合到原始的User管理程序中。

云网OA
云网OA

采用JSP开发的办公自动化产品、基于B/S结构,运行环境:JDK v1.5、Tomcat v5.5、MySQL v4.1,三者均为以上版本其他相关内容:可视化流程设计: 流程支持串签、会签和分支流程,可以设置流程节点的修改、删除权限,并可指定流程中各个用户在表单中可以填写的域。智能表单所见即所得设计: 智能设计,自动在数据库中生成表格,方便优化程序 公共交流: 集论坛、博客、聊天室于一体文件柜:C

下载

首先,定义一个User类,并确保它实现Serializable接口:

import java.io.Serializable;

// User类必须实现Serializable接口才能被序列化
public class User implements Serializable {
    private static final long serialVersionUID = 1L; // 建议添加serialVersionUID

    public int ID;
    public String name;

    public User(int ID, String name) {
        this.ID = ID;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User [ID=" + ID + ", name=" + name + "]";
    }
}

然后,修改主程序UserManagementApp,使其在启动时加载数据,并在程序结束前保存数据。

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class UserManagementApp {

    // 定义用于存储用户数据的列表,使用ArrayList<User>
    private static List<User> userList = new ArrayList<>();
    // 定义保存数据的文件名
    private static final String DATA_FILE = "users.dat";

    public static void main(String[] args) {
        // 1. 程序启动时,尝试从文件加载之前保存的用户数据
        ArrayList<User> loadedUsers = DataPersistenceUtil.loadArrayList(DATA_FILE);
        if (loadedUsers != null) {
            userList = loadedUsers; // 如果成功加载,则使用加载的数据
        } else {
            System.out.println("未能加载现有用户数据,将从空列表开始。");
        }

        System.out.println("当前用户列表:" + userList);

        int tempID = 5000;
        if (args.length > 0) {
            try {
                tempID = Integer.parseInt(args[0]);
            } catch (NumberFormatException e) {
                System.err.println("无效的程序ID参数,使用默认值5000。");
            }
        }
        System.out.println("登录 ID: " + tempID);

        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入您的姓名:");
        String tempName = scanner.nextLine();

        // 创建新的User对象
        User newUser = new User(tempID, tempName);

        // 将新用户添加到列表中
        userList.add(newUser);
        System.out.println("新用户已添加:" + newUser);
        System.out.println("更新后的用户列表:" + userList);

        // 2. 程序退出前(或在适当的时机),将当前的用户列表保存到文件
        DataPersistenceUtil.saveArrayList((ArrayList<User>) userList, DATA_FILE);

        scanner.close();
        System.out.println("程序结束。");
    }
}

运行流程:

  1. 程序启动。
  2. main方法首先调用DataPersistenceUtil.loadArrayList(DATA_FILE)尝试加载数据。
    • 如果users.dat文件存在且包含有效数据,则userList会被填充为之前保存的数据。
    • 如果文件不存在或加载失败,userList将保持为空ArrayList。
  3. 程序继续执行,接收用户输入,创建新的User对象,并将其添加到userList中。
  4. 在程序结束前,调用DataPersistenceUtil.saveArrayList((ArrayList) userList, DATA_FILE)将更新后的userList保存回文件。
  5. 下次运行程序时,第2步将加载到本次保存的数据。

通过这种方式,无论程序运行多少次,userList中的数据都能够被持久化,实现跨程序运行的数据保留。

注意事项与最佳实践

  1. serialVersionUID: 在实现Serializable接口的类中,建议显式声明private static final long serialVersionUID。这有助于在类结构发生变化时,JVM能够识别不同版本的序列化对象。如果不声明,JVM会自动生成,但类结构变化可能导致反序列化失败。
  2. 安全性: 反序列化来自不受信任源的数据存在安全风险,因为恶意构造的字节流可能导致任意代码执行。对于关键应用,应避免反序列化未知来源的数据。
  3. 性能与存储: 对于非常大的数据集,文件序列化可能不是最高效的存储方式。数据库(如MySQL、PostgreSQL)或NoSQL存储(如MongoDB、Redis)提供了更强大的查询、索引和并发控制能力。
  4. 数据格式: 对象序列化生成的users.dat文件是二进制格式,不可直接阅读。如果需要人类可读的数据格式,可以考虑使用JSON(如Jackson或Gson库)、XML或其他文本格式进行数据存储。
  5. 并发访问: 如果多个程序实例或线程需要同时访问和修改同一个数据文件,简单的文件序列化可能导致数据冲突或损坏。在这种情况下,需要引入文件锁、数据库事务或其他并发控制机制。
  6. 错误处理: 始终对文件I/O操作进行充分的错误处理,以应对文件不存在、权限不足、磁盘空间不足等情况。

总结

通过Java的对象序列化机制,我们可以有效地将ArrayList中的数据持久化到本地文件,从而解决了程序运行时数据丢失的问题。这对于需要保存用户配置、历史记录或简单数据集的桌面应用程序来说是一个简单而强大的解决方案。然而,对于更复杂、大规模或需要并发访问的应用场景,可能需要考虑更专业的持久化方案,如关系型数据库或NoSQL数据库。理解并正确运用文件序列化是Java开发中一项重要的技能。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

686

2023.06.20

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

513

2023.06.21

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

287

2023.07.18

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

519

2023.07.19

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

267

2023.07.25

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

392

2023.08.08

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

542

2023.08.11

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

668

2023.08.14

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

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

相关下载

更多

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 2.5万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 848人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号