当前位置: 首页 > news >正文

Java 列表复制与对象引用

Java 列表复制与对象引用

一、知识点

1. 对象引用的基本概念

在 Java 中,List<School> 这样的集合存储的并不是真正的对象,而是对象的“地址”(引用)。就好比你有一个文件柜,文件柜里放的不是文件本身,而是指向文件存放位置的标签。集合中的每个元素都指向堆内存中的实际对象实例。

2. 列表复制与对象引用

当你用 new ArrayList<>(schools) 复制一个列表时,新列表(比如 sortedSchools)只是把原列表(schools)中对象的“地址”复制了一遍,而不是复制对象本身。也就是说,两个列表中的元素都指向同一个对象实例,就像两个标签指向同一个文件。

3. 对象属性修改的影响

因为两个列表中的元素指向同一个对象,所以当你修改复制后的列表(sortedSchools)中对象的属性时,原列表(schools)中对应的对象属性也会跟着变。就好比你通过一个标签修改了文件内容,另一个标签指向的文件内容也会变。

4. 避免原列表被修改的方法

如果你希望修改复制后的列表时不影响原列表,可以在复制列表时创建新的对象,而不是直接复制引用。比如用构造函数重新创建对象:

List<School> sortedSchools = new ArrayList<>();
for (School school : schools) {
    sortedSchools.add(new School(school.abbreviation, school.totalStudents));
}

这种方法虽然能避免原列表被修改,但会增加内存开销(因为要创建新的对象实例)和处理时间(因为要调用构造函数)。


二、面试题

1. 基础概念题

题目:请解释在 Java 中 List<School> 存储的是 School 对象还是对象的引用?并说明当使用 new ArrayList<>(schools) 复制列表时会发生什么?

答案List<School> 存储的是 School 对象的引用,而不是对象本身。就好比你有一个文件柜,文件柜里放的是指向文件的标签,而不是文件本身。当使用 new ArrayList<>(schools) 复制列表时,新列表只是复制了原列表中对象的引用(标签),而不是创建新的对象实例。也就是说,新列表和原列表中的元素都指向堆内存中同一个对象。

2. 代码分析题

题目:以下是一段 Java 代码,请分析代码的输出结果,并解释原因。

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

class School {
    String abbreviation;
    int totalStudents;
    int unassignedStudents;
    int supervisors;

    public School(String abbreviation, int totalStudents) {
        this.abbreviation = abbreviation;
        this.totalStudents = totalStudents;
        this.unassignedStudents = totalStudents;
        this.supervisors = 0;
    }
}

public class Main {
    public static void main(String[] args) {
        List<School> schools = new ArrayList<>();
        School school1 = new School("ABC", 100);
        schools.add(school1);

        List<School> sortedSchools = new ArrayList<>(schools);
        for (School school : sortedSchools) {
            if (school.unassignedStudents > 0) {
                school.unassignedStudents -= 20;
                school.supervisors++;
            }
        }

        System.out.println("原列表 schools 中学校的未分配学生数: " + schools.get(0).unassignedStudents);
    }
}

答案:输出结果是 原列表 schools 中学校的未分配学生数: 80。原因如下:

  • sortedSchools 是通过 new ArrayList<>(schools) 复制的,它只是复制了 schools 中对象的引用,而不是创建新的对象实例。
  • sortedSchools 中修改对象的属性(比如 unassignedStudentssupervisors),因为引用的是同一个对象,所以 schools 中对应的对象属性也会被修改。因此,schools.get(0).unassignedStudents 的值会从 100 变为 80。
3. 优化策略题

题目:如果希望在上述代码中,对 sortedSchools 中 School 对象属性的修改不影响 schools 列表,应该如何修改代码?请说明这种修改的优缺点。

答案

  • 修改方法:在复制列表时创建新的 School 对象,而不是直接复制引用。修改后的代码如下:
    List<School> sortedSchools = new ArrayList<>();
    for (School school : schools) {
        sortedSchools.add(new School(school.abbreviation, school.totalStudents));
    }
    
  • 优点:这样可以保证原列表 schools 不会被 sortedSchools 的操作所影响,数据的独立性更好。就像你复制了一份文件,修改副本不会影响原始文件。
  • 缺点:会增加内存开销(因为需要创建新的对象实例),同时也会增加处理时间(因为每次复制都要调用构造函数来创建新对象)。

相关文章:

  • Python学习第二十五天
  • 10 个pygame经典小游戏
  • 装饰器模式 (Decorator Pattern)
  • SpringCloud消息总线:Bus事件广播与配置动态刷新
  • 基于硅基流动平台API构建定制化AI服务的实践指南
  • 大数据学习(88)-zookeeper实现的高可用(HA)
  • 【JSqlParser】Java使用JSqlParser解析SQL语句总结
  • 垃圾回收学习
  • “thrust“ has no member “device“
  • 视觉Transformer架构的前沿优化技术与高效部署
  • Linux 驱动总线中的 ACPI 设备匹配机制是怎么回事儿?【最大特点是设备的自动发现和热插拔性能良好】
  • vue 组件开发
  • C++运动控制卡开发实践指南
  • 【pm2运行ts的终极解决方案】使用pm2+ tsx 运行 TypeScript 文件指南
  • 3.25-3 request断言
  • 代码随想录算法训练营第二十天 | 字符串 | 反转字符串、替换空格、翻转字符串里的单词(很多基础方法)和左旋转字符串
  • Windows下docker使用教程
  • 【C++特殊类的设计】
  • 和鲸科技执行总裁殷自强受邀主讲华中附属同济医院大模型应用通识首期课程
  • 美摄科技开启智能汽车车内互动及娱乐解决方案2.0
  • 做网站维护的人叫啥/网络营销与策划实践报告
  • 做网站公司哪家正规/无锡网络推广外包
  • 手机端网站的建设/百度广告竞价
  • 担路做网站/湖南专业关键词优化服务水平
  • 我想弄个网站/seo流量排名软件
  • 购物网站前台功能模块/百度搜索广告