导读:本期聚焦于小伙伴创作的《面向对象开发中为什么要做防御性拷贝?如何保护对象内部变量不被外部修改》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《面向对象开发中为什么要做防御性拷贝?如何保护对象内部变量不被外部修改》有用,将其分享出去将是对创作者最好的鼓励。

在面向对象编程中,封装是核心特性之一,我们希望对象的内部状态只能通过自身提供的方法修改,避免外部代码随意篡改。但实际开发中,很多开发者会忽略引用类型变量的传递问题,导致内部状态被意外修改,而防御性拷贝就是解决这类问题的关键方案。

面向对象开发中为什么要做防御性拷贝?如何保护对象内部变量不被外部修改

什么是防御性拷贝

防御性拷贝指的是在返回对象内部的可变引用类型变量时,不直接返回原变量的引用,而是先复制一份新的对象返回给外部。这样外部对返回对象的修改,只会作用于拷贝出来的新对象,不会影响原对象的内部状态,从而保护对象内部的变量不被意外修改。

为什么需要防御性拷贝

我们先看一个没有做防御性拷贝的反面案例,假设我们有一个Person类,内部包含一个可变的学生列表:

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

class Person {
    private String name;
    private List<String> studentList;

    public Person(String name, List<String> studentList) {
        this.name = name;
        // 构造时直接赋值引用,存在风险
        this.studentList = studentList;
    }

    // 直接返回内部列表的引用
    public List<String> getStudentList() {
        return studentList;
    }

    public void addStudent(String student) {
        studentList.add(student);
    }
}

public class Test {
    public static void main(String[] args) {
        List<String> originList = new ArrayList<>();
        originList.add("张三");
        Person person = new Person("李老师", originList);
        // 外部拿到列表引用后直接修改
        List<String> getList = person.getStudentList();
        getList.add("李四");
        // 此时person的内部列表已经被修改
        System.out.println(person.getStudentList().size()); // 输出2
    }
}

上面的代码中,getStudentList方法直接返回了内部studentList的引用,外部代码拿到引用后可以直接修改列表内容,完全绕过了Person类的addStudent方法,破坏了对象的封装性。如果Person类内部对列表有业务约束,比如最多只能有3个学生,外部修改就会直接打破这个约束,导致程序逻辑出错。

如何实现防御性拷贝

1. 构造方法中的防御性拷贝

构造方法接收外部传入的可变引用类型参数时,也需要做拷贝,避免外部后续修改参数影响对象内部状态:

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

class Person {
    private String name;
    private List<String> studentList;

    public Person(String name, List<String> studentList) {
        this.name = name;
        // 构造时拷贝传入的列表,而不是直接引用
        this.studentList = new ArrayList<>(studentList);
    }

    public List<String> getStudentList() {
        // 返回时做拷贝
        return new ArrayList<>(studentList);
    }

    public void addStudent(String student) {
        studentList.add(student);
    }
}

2. 返回可变对象时的防御性拷贝

如果对象内部包含自定义的可变类实例,同样需要做拷贝返回,比如我们有一个Address类:

class Address {
    private String city;
    private String street;

    public Address(String city, String street) {
        this.city = city;
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }
}

class User {
    private String name;
    private Address address;

    public User(String name, Address address) {
        this.name = name;
        // 拷贝Address对象
        this.address = new Address(address.getCity(), address.getStreet());
    }

    public Address getAddress() {
        // 返回时拷贝Address对象
        return new Address(address.getCity(), address.getStreet());
    }
}

防御性拷贝的注意事项

  • 不可变对象不需要做防御性拷贝,比如String、基本类型的包装类,因为这类对象本身无法被修改,返回引用也不会影响内部状态。
  • 如果拷贝的对象层级很深,需要考虑深拷贝和浅拷贝的问题,上面的Address案例属于浅拷贝,如果Address内部还有引用类型变量,就需要递归拷贝所有层级的可变对象。
  • 防御性拷贝会带来额外的内存开销和性能消耗,所以只需要对可能被外部修改的可变引用类型做拷贝,不需要对所有变量都做拷贝。

防御性拷贝的适用场景

防御性拷贝主要适用在以下场景:

场景说明
返回对象内部的可变集合比如ListMapSet等,避免外部修改集合内容
返回自定义的可变对象比如自定义的实体类、数据类,避免外部修改对象内部属性
构造方法接收可变引用参数避免外部后续修改参数影响对象内部状态
方法参数需要长期保存如果方法会把传入的引用类型参数保存到对象内部,需要做拷贝

防御性拷贝是面向对象开发中保障对象封装性的重要手段,合理运用可以有效避免很多因为引用传递导致的隐蔽bug,让代码的健壮性和安全性得到提升。

防御性拷贝面向对象开发对象内部变量Java修改时间:2026-06-18 23:45:54

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。