GSON源码LinkedTreeMap学习
Posted yi-zeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GSON源码LinkedTreeMap学习相关的知识,希望对你有一定的参考价值。
在学习GSON的过程中,发现了GSON的基础数据类型LinkedTreeMap,因此展开学习。
private final LinkedTreeMap<String, JsonElement> members = new LinkedTreeMap<String, JsonElement>();
LinkedTreeMap,一切如此的熟悉,在jdk中有LinkedMap有TreeMap有TreeMap,这个LinkedTreeMap是个什么,顾名思义,这应该是一个连续的且有序的集合。
package com.google.gson.internal;
一看包名,这是google自己实现的map。
Node<K, V> parent; Node<K, V> left; Node<K, V> right; Node<K, V> next; Node<K, V> prev; final K key; V value; int height;
咋一看,这是啥啊。一个结点包含了父节点,左右结点和前后结点,但是不要慌我们接着往下看。
接着回到LinkedTreeMap,在类的最开时定义了一个比较器NATURAL_ORDER
private static final Comparator<Comparable> NATURAL_ORDER = new Comparator<Comparable>() public int compare(Comparable a, Comparable b) return a.compareTo(b); ;
这个比较器在构造LinkHashMap时传入,如果传入的比较器是空(该类没有实现Comparator)则使用NATURAL_ORDER 比较器进行比较,此处略微介绍Comparator和Comparable的区别,实现Comparable 接口的类即支持排序(因为实现了CompareTo)方法,而如果一个类不支持排序(没有实现Compareable接口)则可以使用Comparator比较器来实现比较方法。
为什么要先介绍这个比较器呢,因为在LinkTreeMap进行新增结点和查找结点都需要使用到这个比较器,在find()方法里,首先判断根节点是否为空。
Node<K, V> find(K key, boolean create) Node<K, V> nearest = root; if (nearest != null) Comparable<Object> comparableKey = (comparator == NATURAL_ORDER) ? (Comparable<Object>) key : null;
当根节点不为空时,判断比较器是否为LinkTreeMap自定义的比较器,如果是则使用K类的比较器,否则传null。此处的null主要是标志作用,决定之后使用Compare方法还是使用compareTo方法。
while (true) comparison = (comparableKey != null) ? comparableKey.compareTo(nearest.key) : comparator.compare(key, nearest.key); // We found the requested key. if (comparison == 0) return nearest; // If it exists, the key is in a subtree. Go deeper. Node<K, V> child = (comparison < 0) ? nearest.left : nearest.right; if (child == null) break; nearest = child;
在这循环中根据返回值判断要寻找的结点可能存在的位置,当值比比较的结点小时在他的左子树上继续查找,反之查询右子树直到找到或者当前对象为空。
紧接着,如果create为false则结束find方法,此时nearest就是要查找的值或者根节点。
如果create为true则创建结点,且nearest为null,nearest为null只有一种情况:当前树是一个空树
created = new Node<K, V>(nearest, key, header, header.prev); root = created;
new Node干的事
/** Create a regular entry */ Node(Node<K, V> parent, K key, Node<K, V> next, Node<K, V> prev) this.parent = parent; this.key = key; this.height = 1; this.next = next; this.prev = prev; prev.next = this; next.prev = this;
当树不是空树时则根据最后一次比较的结果进行插入。
else created = new Node<K, V>(nearest, key, header, header.prev); if (comparison < 0) // nearest.key is higher nearest.left = created; else // comparison > 0, nearest.key is lower nearest.right = created; rebalance(nearest, true);
进行调整。
private void rebalance(Node<K, V> unbalanced, boolean insert) for (Node<K, V> node = unbalanced; node != null; node = node.parent)
进入方法后就开始遍历结点,遍历规则是当结点父节点不为空时,无限循环。
Node<K, V> left = node.left; Node<K, V> right = node.right; int leftHeight = left != null ? left.height : 0; int rightHeight = right != null ? right.height : 0; int delta = leftHeight - rightHeight;
保存结点的左右结点以及高度,并计算高度差。
if (delta == -2) Node<K, V> rightLeft = right.left; Node<K, V> rightRight = right.right; int rightRightHeight = rightRight != null ? rightRight.height : 0; int rightLeftHeight = rightLeft != null ? rightLeft.height : 0; int rightDelta = rightLeftHeight - rightRightHeight; if (rightDelta == -1 || (rightDelta == 0 && !insert)) rotateLeft(node); // AVL right right else assert (rightDelta == 1); rotateRight(right); // AVL right left rotateLeft(node); if (insert) break; // no further rotations will be necessary
当左节点比右结点低2时,保存右左结点,右右结点,右左结点高度,右右结点高度,并计算高度差。当高度等于1或等于0时进行左旋。当高度差为1是进行右结点右旋,根节点左旋。
当右节点比左结点低2时,反之。
当高度差为0时,修改节点高度。
else if (delta == 0) node.height = leftHeight + 1; // leftHeight == rightHeight if (insert) break; // the insert caused balance, so rebalancing is done!
当左右节点差为1时,设置高度为左右结点高度更高者加一。
以上是关于GSON源码LinkedTreeMap学习的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Retrofit & Gson 返回 LinkedTreeMap 列表而不是我预期的类型?
如何将 LinkedTreeMap 转换为 gson JsonObject
com.google.gson.internal.LinkedTreeMap 无法转换为我的班级[重复]
java.lang.ClassCastException:com.google.gson.internal.LinkedTreeMap 无法转换为 ClassName
java.lang.ClassCastException:com.google.gson.internal.LinkedTreeMap 无法转换为 java.util.LinkedHashMap
SharedPreferences 保存List<Bean> 到本地并解决com.google.gson.internal.LinkedTreeMap cannot be cast to异常