如何将层级数据库记录转换为Java层级对象?
实现扁平数据库记录到嵌套层级对象的转换(Java)
嘿,这个问题其实很常见,核心思路就是先建立节点的快速映射,再逐个关联父子关系,我给你一步步拆解实现方案:
第一步:调整你的实体类(可选但更友好)
你定义的SomeTable结构没问题,不过把list改成children更语义化,另外加上getter/setter方便操作,也可以用Lombok的@Data简化代码:
import java.util.ArrayList; import java.util.List; // 用Lombok的话只需要加@Data,不用手动写getter/setter和toString // @Data public class SomeTable { private Integer parentId; private Integer id; private List<SomeTable> children = new ArrayList<>(); // 提前初始化空列表,避免空指针 // 手动实现getter/setter public Integer getParentId() { return parentId; } public void setParentId(Integer parentId) { this.parentId = parentId; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public List<SomeTable> getChildren() { return children; } public void setChildren(List<SomeTable> children) { this.children = children; } // 自定义toString,输出你想要的嵌套格式 @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(id).append(" : [ "); for (int i = 0; i < children.size(); i++) { sb.append(children.get(i).toString()); if (i != children.size() - 1) { sb.append(" "); } } sb.append(" ]"); return sb.toString(); } }
第二步:核心转换逻辑
主要分三步完成转换,效率和可读性都拉满:
- 把所有节点存入
Map,用id作为key,方便快速查找父节点 - 遍历每个节点,将子节点挂载到对应父节点的
children列表中 - 收集所有根节点(
parentId=0的节点)
代码实现如下:
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class HierarchyConverter { public static List<SomeTable> buildHierarchy(List<SomeTable> flatData) { // 1. 构建节点映射表,O(n)时间复杂度,快速查找父节点 Map<Integer, SomeTable> nodeMap = new HashMap<>(); for (SomeTable node : flatData) { nodeMap.put(node.getId(), node); } // 2. 关联父子节点,同时收集根节点 List<SomeTable> rootNodes = new ArrayList<>(); for (SomeTable node : flatData) { Integer parentId = node.getParentId(); if (parentId == 0) { // 父节点为0,属于根节点 rootNodes.add(node); } else { // 找到父节点,将当前节点加入父节点的子列表 SomeTable parentNode = nodeMap.get(parentId); if (parentNode != null) { // 兼容数据库可能存在的无效数据(父节点不存在) parentNode.getChildren().add(node); } } } return rootNodes; } // 测试用例:模拟数据库查询的扁平数据 public static void main(String[] args) { List<SomeTable> flatData = new ArrayList<>(); flatData.add(createNode(0, 1)); flatData.add(createNode(1, 11)); flatData.add(createNode(1, 12)); flatData.add(createNode(11, 111)); flatData.add(createNode(0, 2)); flatData.add(createNode(2, 21)); flatData.add(createNode(21, 211)); // 构建层级结构 List<SomeTable> hierarchy = buildHierarchy(flatData); // 输出你想要的格式 System.out.println("[ "); for (int i = 0; i < hierarchy.size(); i++) { System.out.println(" " + hierarchy.get(i).toString()); if (i != hierarchy.size() - 1) { System.out.println(" "); } } System.out.println(" ]"); } // 工具方法:快速创建节点 private static SomeTable createNode(Integer parentId, Integer id) { SomeTable node = new SomeTable(); node.setParentId(parentId); node.setId(id); return node; } }
第三步:运行结果
执行上述代码后,输出结果完全匹配你想要的格式:
[ 1 : [ 11 : [ 111 : [ ] ] 12 : [ ] ] 2 : [ 21 : [ 211 : [ ] ] ] ]
为什么这么设计?
- 用
Map存储节点:把查找父节点的时间复杂度从O(n²)降到O(n),数据量大时效率提升非常明显 - 提前初始化
children列表:避免后续添加子节点时出现空指针异常 - 加入空值判断:兼容数据库可能存在的无效数据(比如子节点的父ID不存在)
- 逻辑解耦:映射和关联两步分开,代码可读性更高,也方便后续扩展
内容的提问来源于stack exchange,提问作者JoonT
相关产品推荐
相关产品推荐

