0

0

在Java里如何实现对象的深层次封装_Java封装与数据保护说明

P粉602998670

P粉602998670

发布时间:2026-01-15 08:03:41

|

260人浏览过

|

来源于php中文网

原创

深层次封装不是仅用private字段+public getter/setter,而是隐藏内部表示、只暴露行为契约,如用deposit()替代setbalance()、返回不可变副本而非原始引用、在构造器中严格校验参数。

在java里如何实现对象的深层次封装_java封装与数据保护说明

为什么直接用 private 字段 + public getter/setter 不算深层次封装

很多人以为把字段设为 private、再提供 getXXX()setXXX() 就完成了封装,其实这只是“语法层面的隔离”。真正的问题在于:这些方法往往直接暴露内部状态,调用方可以随意读写、甚至传入非法值,对象无法维持自身不变量(invariant)。比如一个 BankAccountbalance 字段,如果 setBalance(double) 允许传入负数且不校验,账户就可能进入非法状态。

深层次封装的核心是:**不让外部感知或依赖内部表示,只暴露行为契约**。这意味着:

  • 避免返回可变内部对象的引用(如 ListMap、数组)
  • 不提供“设值即生效”的 setter,而是用意图明确的行为方法(如 deposit()withdraw()
  • 构造时就完成验证,拒绝非法初始状态

如何防止内部集合被外部篡改

这是最容易被忽略的漏洞。当类持有 private List<string> tags</string> 并提供 public List<string> getTags()</string> 时,调用方拿到的是原始引用,可直接 add()clear(),破坏封装。

正确做法是返回不可变视图或副本:

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

智简简历
智简简历

免费AI简历制作工具,智能生成、可视化编辑、多格式导出。

下载
  • JDK 10+ 推荐用 List.copyOf(tags)(返回不可修改的副本)
  • 旧版本可用 Collections.unmodifiableList(new ArrayList(tags))
  • 更彻底的方式是根本不暴露集合,只提供行为方法,如 hasTag(String)addTag(String)
public class Article {
    private final List<String> tags = new ArrayList<>();

    // ❌ 危险:返回原始引用
    // public List<String> getTags() { return tags; }

    // ✅ 安全:返回不可变副本(JDK 10+)
    public List<String> getTags() {
        return List.copyOf(tags);
    }

    // ✅ 更优:只暴露行为
    public void addTag(String tag) {
        if (tag != null && !tag.trim().isEmpty()) {
            tags.add(tag.trim());
        }
    }
}

用 record + 构造验证实现不可变深层封装

Java 14+ 的 record 天然适合表达“值对象”,但默认不校验参数。要实现深层次封装,必须在构造器中主动拦截非法输入。

注意:record 的紧凑构造器(canonical constructor)是唯一可控入口,所有字段赋值都经过它——这里就是校验和转换逻辑的唯一位置。

  • 不要在字段声明处初始化(如 private final String name = Objects.requireNonNull(n);),那会绕过构造器逻辑
  • 禁止在 record 中定义 setter 或公开可变字段
  • 若需深度不可变(如嵌套对象),确保其本身也是不可变类型或已做防御性拷贝
public record Person(String name, int age) {
    public Person {
        if (name == null || name.trim().isEmpty()) {
            throw new IllegalArgumentException("name cannot be blank");
        }
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("age must be between 0 and 150");
        }
        // 注意:此处不能对 this.name 或 this.age 赋值,record 自动处理
        // 校验失败直接抛异常,record 实例不会被创建
    }
}

当必须暴露内部对象时,如何做防御性拷贝

有些场景确实需要返回内部对象(如配置类中的 Properties),这时必须做深拷贝或至少是浅拷贝+不可修改包装。关键点是:**拷贝时机在 getter 内部,且不复用已有对象**。

  • 对数组:用 Arrays.copyOf(arr, arr.length)
  • Properties:用 new Properties() {{ putAll(original); }}(注意双大括号初始化的副作用,生产环境建议显式循环)
  • 对自定义对象:若实现了 Cloneable,慎用 clone()(浅拷贝风险);优先用构造器或 builder 创建新实例

特别注意:不要缓存并复用拷贝结果。每次调用 getter 都应生成新副本,否则缓存的副本仍可能被外部修改后影响后续调用。

封装的难点从来不在语法,而在设计时是否愿意把“这个对象该做什么”想清楚,而不是“这个对象有什么字段”。一旦开始用行为方法替代 setter,用不可变视图替代原始引用,用构造期校验替代运行时妥协,封装才真正开始起作用。

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

通义千问
通义千问

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

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1010

2023.08.02

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

334

2025.08.29

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

106

2025.10.23

length函数用法
length函数用法

length函数用于返回指定字符串的字符数或字节数。可以用于计算字符串的长度,以便在查询和处理字符串数据时进行操作和判断。 需要注意的是length函数计算的是字符串的字符数,而不是字节数。对于多字节字符集,一个字符可能由多个字节组成。因此,length函数在计算字符串长度时会将多字节字符作为一个字符来计算。更多关于length函数的用法,大家可以阅读本专题下面的文章。

954

2023.09.19

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

77

2025.09.05

golang map相关教程
golang map相关教程

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

40

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

67

2025.11.17

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

47

2025.11.27

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

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

76

2026.03.11

热门下载

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

精品课程

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

共23课时 | 4.3万人学习

C# 教程
C# 教程

共94课时 | 11.1万人学习

Java 教程
Java 教程

共578课时 | 80.6万人学习

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

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