> 文章列表 > Java集合使用遇到的一例错误记录

Java集合使用遇到的一例错误记录

Java集合使用遇到的一例错误记录

文章目录

    • 概要
    • 集合
    • Java中的引用
    • 错误使用案例

概要

  • Java集合类是我们开发中经常使用到的一种类,也是Java开发者必须掌握的一个知识点。
  • 在Java中,引用类型是一种数据类型,所有非基本数据类型都是引用类型。
  • Java中的集合类中存储的元素都是引用类型,即存储的是对象的引用。在使用集合时,需要注意引用的使用方式,避免出现内存泄漏等问题。
  • 本次记录的一处集合使用错误,就是忽略了对象引用,对象数据变化导致程序执行出错,特此总结记录一次,加深印象

集合

  • Java集合是Java开发中的重要部分之一,它提供了一种管理和存储一组对象的方式。Java集合框架包括接口和类,可以在不同的场景下使用。
  • Java集合类是一组支持存储和操作多个数据元素的数据结构类,可以通过集合类的方法来实现对数据集合的添加、删除、查找等操作。
  • Java集合主要包括三大类:List、Set和Map。
    • List是一个有序的集合,可以包含重复元素。List接口的实现类有ArrayList、LinkedList、Vector等。
    • Set是一个无序的集合,不允许包含重复元素。Set接口的实现类有HashSet、TreeSet等。
    • Map是一个键值对的集合,每个元素包含一个键和一个值,键不能重复。Map接口的实现类有HashMap、TreeMap等。
  • 除此之外,Java还提供了一些其他的集合类,如Queue、Deque、Stack等。这些集合类可以在不同的场景下使用,提高了Java开发的效率和灵活性。

Java中的引用

  • 在Java中,引用类型是一种数据类型,它与基本数据类型(如整数、字符、布尔等)不同,可以指向对象、数组、接口以及其他引用类型,它是指向对象的地址,允许对对象进行间接访问。在Java中,所有非基本数据类型都是引用类型,并且存储在Java虚拟机的堆中。
  • Java中的引用是一种用于访问对象的机制。在Java中,每个对象都有一个引用,它是指向对象内存地址的变量。通过引用,程序可以访问对象的属性和方法,对对象进行操作。对象的创建和销毁都是由Java的垃圾回收机制来负责处理的,引用可以帮助垃圾回收机制判断一个对象是否可以被回收。
  • Java中有四种类型的引用:强引用、软引用、弱引用和虚引用。
    • 强引用是最普通的引用,它指向一个对象,只要强引用存在,对象就不会被垃圾回收器回收。
    • 软引用是一种比强引用弱的引用,如果内存充足,系统不会回收被软引用引用的对象,但是内存紧张时,系统可以回收这些对象。
    • 弱引用比软引用更弱,当垃圾回收器线程扫描到一个只被弱引用引用的对象时,就会将其回收。
    • 虚引用是最弱的引用,它仅仅是为了在对象被回收时收到通知。一个对象被虚引用指向后,相当于没有任何引用指向这个对象,所以在任何时候都有可能被垃圾回收器回收。
  • 引用是Java语言中一个非常重要且基础的概念,严谨的引用设计可以有效地利用JVM内存资源,从而提高程序的性能和效率。

错误使用案例

  • 业务逻辑简述:从一个对象phaseStatusDTO中取出相应值(包含一个map类型的channelStatusMap赋值PhaseStatusVO的对象,放入缓存;后面的业务是修改channelStatusMap
  • 错误修改:之前出错是忽略了map的对象引用,导致后面业务修改channelStatusMap 时,前面的数值也跟着变动了。修复逻辑也很简单,用new包一下即可,new HashMap<>(phaseStatusDTO.getChannelStatusMap())
  • 原错误代码
			PhaseStatusVO statusVO = new PhaseStatusVO();BeanUtils.copyProperties(phaseStatusDTO, statusVO);statusVO.setTimestamp(System.currentTimeMillis());// 这里将 Map<Integer, ChannelStatus> channelStatusMap 对象赋值给 statusVOstatusVO.setChannelStatusMap(phaseStatusDTO.getChannelStatusMap());UNIT_ID_STATUS_MAP.put(unitId, statusVO);// 红闪/灭灯 缓存存在时,赋值Map<Integer, ChannelStatus> channelStatusMap = UNIT_ID_SPECIAL_CHANNEL_MAP.get(unitId);if (null != channelStatusMap && channelStatusMap.size() > 0) {for (Map.Entry<Integer, ChannelStatus> channelStatus : channelStatusMap.entrySet()) {// 这里又修改了 channelStatusMap 对象,这时,前面的statusVO里面的channelStatusMap值也就变了,导致出错phaseStatusDTO.setChannelStatus(channelStatus.getKey(), channelStatus.getValue());}}
  • 修改后的代码
			PhaseStatusVO statusVO = new PhaseStatusVO();BeanUtils.copyProperties(phaseStatusDTO, statusVO);statusVO.setTimestamp(System.currentTimeMillis());// 新建map防止对象引用造成的数据变动Map<Integer, ChannelStatus> statusMap = new HashMap<>(phaseStatusDTO.getChannelStatusMap());// 这里是把新 map 赋值给 statusVOstatusVO.setChannelStatusMap(statusMap);UNIT_ID_STATUS_MAP.put(unitId, statusVO);// 红闪/灭灯 缓存存在时,赋值Map<Integer, ChannelStatus> channelStatusMap = UNIT_ID_SPECIAL_CHANNEL_MAP.get(unitId);if (null != channelStatusMap && channelStatusMap.size() > 0) {for (Map.Entry<Integer, ChannelStatus> channelStatus : channelStatusMap.entrySet()) {// 这时再改动 channelStatusMap ,就不会影响 statusVOphaseStatusDTO.setChannelStatus(channelStatus.getKey(), channelStatus.getValue());}}