解决在树状结构节点共用同个对象的问题

文章描述了一个Java编程中的问题,即在构建树状结构时,由于相同的叶子节点可能属于两个不同但具有相同code和parentCode的父节点,导致唯一标识符冲突。为了解决这个问题,文中提出了使用深拷贝并通过Gson进行序列化和反序列化的方法来复制对象,确保每个父节点下的叶子节点都有唯一的标识。此外,还展示了如何在泛型类中处理这种拷贝操作。
摘要由CSDN通过智能技术生成

目前有个需求场景是这样,有个叶子节点,他对应的父节点是一致的,但是该父节点会在两个不同的根节点下,因此该场景下,该父节点是有两个,但是叶子节点只是一个(因为其code和parentCode是一致的,无法区分成不同的节点),但是生成树状结构时要给个唯一标识符,这会导致两个叶子节点下的唯一标识符一致(因为共用同个对象)。因此解决方案是,在生成树状结构节点的时候,通过深拷贝,将两个节点区分开来,而深拷贝采用json序列化和反序列化实现(此处使用gson序列化和反序列工具)。
具体如下:

public abstract class AbstractTreeNode<T extends AbstractTreeNode> {
    /**
     * 编码
     */
    @ApiModelProperty("编码")
    public String code;
    /**
     * 父类编码
     */
    @ApiModelProperty("父类编码")
    public String parentCode;
    /**
     * 文本内容
     */
    @ApiModelProperty("文本内容")
    public String label;
    /**
     * 子节点
     */
    @ApiModelProperty("子节点")
    public List<T> children;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getParentCode() {
        return parentCode;
    }

    public void setParentCode(String parentCode) {
        this.parentCode = parentCode;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public List<T> getChildren() {
        return children;
    }

    public void setChildren(List<T> children) {
        this.children = children;
    }

    /**
     * 判断是否为根节点(默认为parentCode为null,如果逻辑为parentCode为自身Code,则重写该方法)
     * @return
     */
    @JsonIgnore
    public boolean isRoot(){
        return parentCode == null;
    }

    /**
     * 非根节点
     * @return
     */
    @JsonIgnore
    public boolean isNotRoot(){
        return !isRoot();
    }
}

@ApiModel("归因穿透返回vo")
public class PenetrationReturnVO extends AbstractTreeNode<PenetrationReturnVO> {
    /**
     * 指标值
     */
    @ApiModelProperty("指标值")
    private String indicatorValue;

     public String getIndicatorValue() {
        return indicatorValue;
    }

    public void setIndicatorValue(String indicatorValue) {
        this.indicatorValue = indicatorValue;
    }

}
    /**
     * 转换为树状结构(除根节点外都进行深拷贝),需要继承AbstractTreeNode抽象类(如有必要要重写isRoot方法)
     *
     * @param abstractTreeNodes
     * @return
     */
    public static <T extends AbstractTreeNode> List<T> convertToTreeNodeCopy(List<T> abstractTreeNodes) {
        if (CollectionUtils.isEmpty(abstractTreeNodes)) {
            return Collections.emptyList();
        }
        Gson gson = GsonUtils.gson();
        //过滤掉非根节点的节点,并按父节点分组。(排除根节点的父类是其自身导致的无限循环。)
        Map<String, List<T>> maps = abstractTreeNodes.stream().filter(AbstractTreeNode::isNotRoot).collect(Collectors.groupingBy(AbstractTreeNode::getParentCode));
        List<T> roots = abstractTreeNodes.stream().filter(AbstractTreeNode::isRoot).collect(Collectors.toList());
        for (T root : roots) {
            List<T> abstractTreeNodesRes = queryChildren(root.getCode(), maps);
            //深拷贝对象
            List<T> res =
                    abstractTreeNodesRes.stream().map(a -> (T)gson.fromJson(gson.toJson(a), a.getClass())).collect(Collectors.toList());
            root.setChildren(res);
        }
        return roots;
    }
 /**
     * 递归实现查询子节点
     *
     * @param parentCode
     * @param maps
     * @return
     */
    private static <T extends AbstractTreeNode> List<T> queryChildren(String parentCode, Map<String, List<T>> maps) {
        List<T> nodes = maps.get(parentCode);
        if (CollectionUtils.isEmpty(nodes)) {
            return Collections.emptyList();
        }
        for (T node : nodes) {
            //排除父节点是其自身的死循环,只走一次。
            if (!parentCode.equals(node.getCode())) {
                node.setChildren(queryChildren(node.getCode(), maps));
            } else {
                node.setChildren(Collections.emptyList());
            }
        }
        return nodes;
    }
public class GsonUtils {
    private static Gson gson;
    static {
        gson = new Gson();
    }
    public static Gson gson(){
        return gson;
    }
}

上面的主要知识点就是如何在序列化和反序列化中获取实际的泛型类型,此处是通过子类集成父类并说明泛型类型实现的,具体知识点可以看我这篇博客。
获取泛型对象实际类型

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值