首页 > 编程语言 >java 转化为树工具类

java 转化为树工具类

时间:2023-07-27 11:47:51浏览次数:35  
标签:java get List private id 转化 TestTree parentId 为树

Java 树状结构转化工具类

1:使用场景:菜单结构数(n级别)

2:数据库存储的往往的是一条条的数据,通过id,查询数据库的父类id进行获取子类数据,然后进行组装数据,数据曾经可能很多。

往往的解决思路是通过递归进行查询,递归中可能会写sql查询,效率极低。有需要的可以了解一下递归的时间复杂度和空间复杂度。

3:本工具类的优点在于以空间换时间的思路。通过查询出所需要的数据,将数据进行内存中处理,使用一层for结构,进行遍历循环,获取子类并进行组装数据

具体可以看代码

package org.springblade.common.utils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

public class TreeUtils<T> {
    private final Map<Object, T> nodeMap = new HashMap<>();
    private final List<T> root = new ArrayList<>();
    private final List<T> baseRoot = new ArrayList<>();
    private String childParamName = null;
    private String parentParamName = null;
    private String listParamName = null;
    private final List<T> listData;
    private final Class<?> aClass;
    private Method methodGet;
    private Method methodSet;

    /**
     * 初始化数据
     * @param nodes
     */
    public TreeUtils(List<T> nodes) {
        this.listData = nodes;
        aClass = nodes.get(0).getClass();
        setBase();
        listData.forEach(res -> nodeMap.put(getVal(res, parentParamName), res));
    }

    /**
     * 转化为树,默认返回跟节点
     */
    public List<T> tree() {
        listData.forEach(one -> {
            T childData = nodeMap.get(getVal(one, childParamName));
            if (childData != null) {
                setVal(childData, one);
            } else {
                baseRoot.add(one);
            }
        });
        return getBaseRoot();
    }

    /**
     * 转化为树,默认返回节点为base的节点树
     */
    public List<T> tree(Object base) {
        if (base == null) {
            return tree();
        }
        listData.forEach(one -> {
            T childData = nodeMap.get(getVal(one, childParamName));
            if (childData != null) {
                setVal(childData, one);
            }
            if (base.toString().equals(String.valueOf(getVal(one, parentParamName)))) {
                root.add(one);
            }
        });
        return getRoot();
    }
    private void setBase() {
        Field[] tableDoris = this.aClass.getDeclaredFields();
        for (Field doris : tableDoris) {
            TreeUtil annotation = doris.getAnnotation(TreeUtil.class);
            if (annotation != null) {
                System.out.println(annotation.value());
                if (TreeType.id.name().equals(annotation.value().toString())) {
                    parentParamName = doris.getName();
                } else if (TreeType.parentId.name().equals(annotation.value().toString())) {
                    childParamName = doris.getName();
                } else if (TreeType.childList.name().equals(annotation.value().toString())) {
                    listParamName = doris.getName();
                }
            }
        }
        try {
            this.methodGet = aClass.getMethod("get" + getMethodName(listParamName));
            this.methodGet.setAccessible(true);

            this.methodSet = aClass.getMethod("set" + getMethodName(listParamName), List.class);
            this.methodSet.setAccessible(true);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    private Object getVal(T t, String name) {
        // 获取单个属性
        try {
            Field field = aClass.getDeclaredField(name);
            field.setAccessible(true);
            return field.get(t);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings("unchecked")
    private void setVal(T t, T child) {
        // 获取单个属性
        try {
            List<T> childData = null;
            Object obj = methodGet.invoke(t);
            if (obj instanceof List<?>) {
                childData = (List<T>) obj;
            }
            if (childData == null) {
                childData = new ArrayList<>();
            }
            childData.add(child);
            methodSet.invoke(t, childData);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    private List<T> getBaseRoot() {
        return baseRoot;
    }

    private List<T> getRoot() {
        return root;
    }

    private static String getMethodName(String fieldName) {
        byte[] items = fieldName.getBytes();
        items[0] = (byte) ((char) items[0] - 'a' + 'A');
        return new String(items);
    }
}


@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface TreeUtil {
    TreeType value();
}

enum TreeType {
    //标识为id,
    id,
    //标识为父类id字段
    parentId,
    //表示为结果存储对象
    childList
}
View Code

 



使用

加入注解

@Data
public class TestTree {
    /**
     * 主键ID
     */
    @JsonSerialize(using = ToStringSerializer.class)
    @TreeUtil(value = TreeType.id)
    private Long id;

    /**
     * 父节点ID
     */
    @JsonSerialize(using = ToStringSerializer.class)
    @TreeUtil(value =TreeType.parentId)
    private Long parentId;
    /**
     * 子孙节点
     */
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    @TreeUtil(value = TreeType.childList)
    private List<TestTree> children;

}
View Code

测试

    public static void main(String[] args) {
        List<TestTree> list1 = new ArrayList<>();
        for (long i = 0; i < 10; i++) {
            TestTree menuVO = new TestTree();
            menuVO.setId(i);
            list1.add(menuVO);
        }
        list1.get(0).setParentId(-1L);
        list1.get(1).setParentId(0L);
        list1.get(2).setParentId(1L);
        list1.get(3).setParentId(2L);
        list1.get(4).setParentId(3L);
        list1.get(5).setParentId(4L);
        list1.get(6).setParentId(5L);
        list1.get(7).setParentId(6L);
        list1.get(8).setParentId(7L);
        list1.get(9).setParentId(8L);
        List<TestTree> list2 = new TreeUtils<TestTree>(list1).tree();
        System.out.println(list2);
    }
View Code

效果

[TestTree(id=0, parentId=-1, children=[TestTree(id=1, parentId=0, children=[TestTree(id=2, parentId=1, children=[TestTree(id=3, parentId=2, children=[TestTree(id=4, parentId=3, children=[TestTree(id=5, parentId=4, children=[TestTree(id=6, parentId=5, children=[TestTree(id=7, parentId=6, children=[TestTree(id=8, parentId=7, children=[TestTree(id=9, parentId=8, children=null)])])])])])])])])])]



 

 

标签:java,get,List,private,id,转化,TestTree,parentId,为树
From: https://www.cnblogs.com/tdf-/p/17584541.html

相关文章

  • 带你详细刨析JavaScript 对象数组的深浅拷贝
    深浅拷贝●深浅拷贝指的是一种复制对象或者数组的行为●也就是把一个对象或者数组中的数据完完整整的复制一份放到另一个数组或者对象中●并且相互之间没有联系●说道深浅拷贝这个我们不考虑基本数据类型●因为基本数据类型没有引用地址一说●说到复制这个事儿有三个级别○赋值......
  • Java十大经典排序算法汇总
    以下是十大经典排序算法:冒泡排序(BubbleSort):比较相邻两个元素,如果逆序则交换,重复多轮,直到无逆序情况。选择排序(SelectionSort):在待排序元素中选择最小(大)元素,放在已排序序列的起始位置,重复多轮,直到所有元素有序。插入排序(InsertionSort):从第二个元素开始,将每个元素插入到已排序......
  • java启动jar包修改JVM默认内存问题
    JVM默认物理内存JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每......
  • Java基础和MySQL
    Java基础==和equals的区别==比较的是值是否相等。==作用于基本数据类,他比较的是内容==作用于引用数据类型,比较的是地址值equals比较的是对象是否是同一个对象,比较的是对象的内容equals()方法存在于Object类中,在没有重写之前和==是一样,也是比较的是引用数据类型的地址......
  • 尚硅谷Java 宋红康2023版 - 学习笔记
    尚硅谷Java宋红康2023版-学习笔记观看地址https://www.bilibili.com/video/BV1PY411e7J6JDKJREJVMjdk是开发包,jre是运行包,jvm是java虚拟机(最小核心)javajdk版本8或11我这里就用8了。......
  • java.security.InvalidKeyException: Illegal key size 的解决方法
    一、原因JDK受版本安全限制,默认只允许128位长度以内的。秘钥长度,如果密钥大于128,会抛出java.security.InvalidKeyException:Illegalkeysize异常.java运行时环境默认读到的是受限的policy文件.文件位于${java_home}/jre/lib/security,这种限制是因为美国对软件出口的控制......
  • Java面试题 P9:List和Set的区别
    List:有序,按对象进入的顺序保存对象,可重复,允许多个Null元素对象,可以使用Iterator取出所有元素,在逐一遍历,还可以使用get(intindex)下标方式,获取指定下标的元素值Set:无序,不可重复,最多允许有一个Null元素对象,取元素时只能用lterator接口取得所有元素,在逐一遍历各个元素  ......
  • goole-java-format
    使用GoogleJavaFormat概述在本文中,我将教会你如何使用GoogleJavaFormat。GoogleJavaFormat是一个用于自动格式化Java代码的工具,可以帮助开发者编写符合Google代码风格指南的代码。通过使用GoogleJavaFormat,你可以减少手动调整代码格式的工作量,提高代码的可读性和一致性。......
  • Java方法详解
    Java方法详解什么是方法-System.out.println(),那么她是什么?-Java方法是语句的集合,它们在一起执行一个功能1方法是解决一类问题的步骤的有序组合2方法包含于类或对象中3方法在程序中被创建,在其他地方被引用-设计方法的原则:方法的本意是功能......
  • Java面试题 P8:接口和抽象类的区别
    普通回答:1、抽象类可以有抽象方法和实现的方法,可以存在普通成员函数,而接口中只能存在publicinterface方法。2、抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是publicstaticfinal类型的。3、抽象类只能继承一个,接口可以实现多个。抽象类和接口的异同点 ......