You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot GET API列表值重复问题求助

Spring Boot GET API列表值重复问题:复用POJO对象导致的引用重复

你遇到的重复问题核心原因很明确:列表中存储的是对象的引用,而你一直在复用同一个getAllRoomsobj对象。每次循环你只是修改这个对象的属性值,然后把它的引用添加到列表里,最终列表里的所有元素其实都是指向同一个对象的指针,所以最后所有元素都会显示最后一次循环设置的属性值。

下面给你提供几种符合你“不想每次创建新对象”需求的解决方案:


方案1:使用对象克隆实现复用

如果你只是想避免每次显式new对象,可以通过克隆当前对象的副本添加到列表,这样既复用了基础对象,又能保证列表元素独立。

步骤1:让GetAllRooms实现克隆能力

在你的POJO类里实现Cloneable接口并重写clone方法:

public class GetAllRooms implements Cloneable {
    private int roomId;
    private String roomName;

    // 省略getter、setter方法

    @Override
    protected GetAllRooms clone() throws CloneNotSupportedException {
        // 浅克隆:适合属性都是基本类型的场景
        return (GetAllRooms) super.clone();
        // 如果有引用类型属性,需要手动实现深克隆,比如:
        // GetAllRooms clone = (GetAllRooms) super.clone();
        // clone.setSomeRefField(this.getSomeRefField().clone());
        // return clone;
    }
}

步骤2:修改循环代码添加克隆副本

List<GetAllRooms> getallroomslistobj = new ArrayList<GetAllRooms>();
// 只初始化一次对象
GetAllRooms getAllRoomsobj = new GetAllRooms();

for (int i = 0; i < getroomslistobj.size(); i++) {
    int dbroomId = getroomslistobj.get(i).getRoomId();
    String dbroomName = getroomslistobj.get(i).getRoomName();
    
    // 修改复用对象的属性
    getAllRoomsobj.setRoomId(dbroomId);
    getAllRoomsobj.setRoomName(dbroomName);
    
    // 添加克隆后的独立副本到列表
    try {
        getallroomslistobj.add(getAllRoomsobj.clone());
    } catch (CloneNotSupportedException e) {
        // 异常降级:克隆失败时新建对象兜底
        GetAllRooms fallbackObj = new GetAllRooms();
        fallbackObj.setRoomId(dbroomId);
        fallbackObj.setRoomName(dbroomName);
        getallroomslistobj.add(fallbackObj);
    }
}

方案2:用对象池管理复用(适合高并发场景)

如果你的服务是高并发场景,担心频繁创建对象的性能开销,可以用对象池来统一管理GetAllRooms对象的复用,比如使用Apache Commons Pool2:

步骤1:添加依赖(Maven)

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.12.0</version>
</dependency>

步骤2:创建对象池配置与工厂

import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;

public class GetAllRoomsPool {
    private static final GenericObjectPool<GetAllRooms> pool;

    static {
        // 配置对象池参数
        GenericObjectPoolConfig<GetAllRooms> config = new GenericObjectPoolConfig<>();
        config.setMaxTotal(20); // 池内最大对象数
        config.setMaxIdle(10);  // 最大空闲对象数
        pool = new GenericObjectPool<>(new GetAllRoomsFactory(), config);
    }

    // 从池里借对象
    public static GetAllRooms borrowObject() throws Exception {
        return pool.borrowObject();
    }

    // 归还对象到池里(注意:如果列表需要长期持有对象,不能归还)
    public static void returnObject(GetAllRooms obj) {
        // 归还前重置属性,避免残留数据影响下次复用
        obj.setRoomId(0);
        obj.setRoomName(null);
        pool.returnObject(obj);
    }
}

// 对象工厂:负责创建和包装池内对象
class GetAllRoomsFactory extends BasePooledObjectFactory<GetAllRooms> {
    @Override
    public GetAllRooms create() {
        return new GetAllRooms();
    }

    @Override
    public PooledObject<GetAllRooms> wrap(GetAllRooms obj) {
        return new DefaultPooledObject<>(obj);
    }
}

步骤3:循环中使用对象池

List<GetAllRooms> getallroomslistobj = new ArrayList<GetAllRooms>();

for (int i = 0; i < getroomslistobj.size(); i++) {
    int dbroomId = getroomslistobj.get(i).getRoomId();
    String dbroomName = getroomslistobj.get(i).getRoomName();
    
    try {
        // 从池里借对象
        GetAllRooms obj = GetAllRoomsPool.borrowObject();
        obj.setRoomId(dbroomId);
        obj.setRoomName(dbroomName);
        getallroomslistobj.add(obj);
        
        // 注意:如果后续列表需要长期保留对象,不要归还到池里,否则池复用对象会修改列表数据
        // 若对象用完即弃,记得在合适时机调用GetAllRoomsPool.returnObject(obj);
    } catch (Exception e) {
        // 异常降级:借对象失败时新建对象
        GetAllRooms fallbackObj = new GetAllRooms();
        fallbackObj.setRoomId(dbroomId);
        fallbackObj.setRoomName(dbroomName);
        getallroomslistobj.add(fallbackObj);
    }
}

额外建议

其实在大多数普通业务场景下,每次循环新建GetAllRooms对象的性能开销几乎可以忽略——JVM的垃圾回收机制对这类短生命周期的对象处理非常高效,代码复杂度也更低。如果没有特殊的性能要求,直接在循环内new对象是最简单且不易出错的方案。


内容的提问来源于stack exchange,提问作者GURU

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 10:32:49