java 集合封装树形结构

本例父子关系,子节点的parentId和父节点的id相同。

实现树形排列的方法

    public static List<Type> buildTree(List<Type> treeNodes) {
        List<Type> trees = new ArrayList<>();
        for (Type treeNode : treeNodes) {        // 第一层遍历,对每一个节点(目标)做一次父亲,找其孩子节点,进行封装
        	// 需要知道根节点的特征,遍历到根节点就可以封装到trees中(根节点就不会在有上层了),本例根节点parentId为空
            if (StringUtils.isBlank(treeNode.getParentId())) {
                trees.add(treeNode);
            }
            for (Type it : treeNodes) {   // 第二层遍历全部,校验是否是(目标)的孩子节点,进行父子封装
                if (Objects.equals(it.getParentId(), treeNode.getId())) {
                    if (treeNode.getChildList() == null) {
                        treeNode.setChildList(new ArrayList<Type>());   // 防止空指针
                    }
                    treeNode.getChildList().add(it);
                }
            }
        }
        return trees;
    }

实现原理:
集合可以理解为对多个对象的引用。本例中入参为treeNodes集合。不管在后面的for循环还是add方法中,实际只是对trees(必须new出来,不能直接用treeNodes赋值)集合的组装,对于treeNodes集合而言,每一个对象的引用和顺序至始至终没有发生任何改变,改变的仅仅是值发生改变,每一个值都包含了childList对象。对于trees而言,只含有根节点数量个对象。

遇到的问题:
在调用处,获取trees集合的同时,传入的treeNodes也会发生多出childList的改变。如果不希望入参的treeNodes发生这个改变,就需要入参集合与treeNodes集合引用不同的对象地址。
错误的赋值引用
List list2 = new ArrayList();
list2.addAll(treeNodes);
当list2作为入参后,执行过方法发现treeNodes还是多了childList的属性。因为这种方法对list2而言是新的引用没错,此时对list2进行增删操作也不会影响treeNodes。但是加入的对象确不行,引用是相同的,当Type改变值的时候,在treeNodes和list2中都会发生改变。当然List list2 =treeNodes;就更不正确了
在这里插入图片描述
正确的赋值引用
需要不仅对list对象new出来,还需要对其中的每一个对象new出来一遍。
如引用代码:
List list3 = copyList(list1, Type::new);
具体方法:

public static <S, T> List<T> copyList(List<S> sources, Supplier<T> target) {
        List<T> list = new ArrayList<>(sources.size());
        for (S source : sources) {
            T t = target.get();
            try {
                BeanUtils.copyProperties( t,source);
            } catch (Exception e) {
                e.printStackTrace();
            }
            list.add(t);
        }
        return list;
    }

在这里插入图片描述
可以看到,前面虽然值一样,但是实际的引用地址已经不同了。

学海无涯苦作舟!!!

你可能感兴趣的:(javaWEB,java,数据结构)