Java中的WeakHashMap、LinkedHashMap、TreeMap与Set详解
作者:超大充电宝
WeakHashMap
Java中的四种引用
在JVM中,一个对象如果不再被使用就会被当做垃圾给回收掉,判断一个对象是否是垃圾,通常有两种方法:引用计数法和可达性分析法。不管是哪一种方法判断一个对象是否是垃圾的条件总是一个对象的引用是都没有了。
JDK1.2 之后,Java 对引用的概念进行了扩充,将引用分为了:强引用、软引用、弱引用、虚引用4 种。而我们的WeakHashMap就是基于弱引用。
强引用
如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出OutOfMemoryError错误,使程序异常终止。比如String str = new String("hello");这时候str就是一个强引用。
软引用
内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。
弱引用
如果一个对象具有弱引用,在垃圾回收时候,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。
虚引用
如果一个对象具有虚引用,就相当于没有引用,在任何时候都有可能被回收。使用虚引用的目的就是为了得知对象被GC的时机,所以可以利用虚引用来进行销毁前的一些操作,比如说资源释放等。
LinkedHashMap
LinkedHashMap它虽然增加了时间和空间上的开销,但是通过维护一个运行于所有条目的双向链表,LinkedHashMap保证了元素迭代的顺序。该迭代顺序可以是插入顺序或者是访问顺序。
LinkedHashMap存储结构
/** * The head (eldest) of the doubly linked list. */ transient LinkedHashMap.Entry<K,V> head; /** * The tail (youngest) of the doubly linked list. */ transient LinkedHashMap.Entry<K,V> tail; /** * The iteration ordering method for this linked hash map: <tt>true</tt> * for access-order, <tt>false</tt> for insertion-order. * * @serial */ final boolean accessOrder; /** * HashMap.Node subclass for normal LinkedHashMap entries. */ static class Entry<K,V> extends HashMap.Node<K,V> { Entry<K,V> before, after; Entry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); } }
LinkedHashMap的结点结构在继承于HashMap的基础上,增加了 before 和 after 属性来确保插入顺序。并且还维护了头结点 head 和尾结点 tail 。在插入数据时,不但需要通过哈希算法进行存储,还需要通过 before 和 after 模拟双向链表存储结构,进行插入顺序的维护。
LinkedHashMap所继承于HashMap结点中的 next 属性是用于维护HashMap中table数组中存储的链表。而其独有的 before 和 after 是模拟双向链表进行结点插入顺序的维护
TreeMap
在前面我们通过HashMap中插入顺序无序引出了LinkedHashMap的使用,但是我们又可以发现,这两种存储方式在迭代时均不是按照数据的大小顺序进行遍历的,而当我们需要将数据按照大小顺序迭代时,就需要此时的TreeMap集合了。
- TreeMap是一个大小有序的key-value集合,底层结构是红黑树,不允许插入null值。
- TreeMap采用红黑树的插入和删除方法,通过比较key决定新元素的插入位置,也通过红黑树的有序性质进行删除。
- TreeMap需要通过Comparable或Comparator进行元素的排序。
TreeMap的存储结构
// Red-black mechanics private static final boolean RED = false; private static final boolean BLACK = true; /** * Node in the Tree. Doubles as a means to pass key-value pairs back to * user (see Map.Entry). */ static final class Entry<K,V> implements Map.Entry<K,V> { //key,val是存储的原始数据 K key; V value; //定义了结点的左孩子 Entry<K,V> left = null; //定义了结点的右孩子 Entry<K,V> right = null; //通过该节点可以反过来往上找到自己的父亲 Entry<K,V> parent; //默认情况下为黑色节点,可调整 boolean color = BLACK; /** * Make a new cell with given key, value, and parent, and with * {@code null} child links, and BLACK color. */ Entry(K key, V value, Entry<K,V> parent) { this.key = key; this.value = value; this.parent = parent; } }
黑树规则特点:
1、节点分为红色或者黑色;
2、根节点必为黑色;
3、叶子节点都为黑色,且为null;
4、连接红色节点的两个子节点都为黑色(红黑树不会出现相邻的红色节点);
5、从任意节点出发,到其每个叶子节点的路径中包含相同数量的黑色节点;
6、新加入到红黑树的节点为红色节点;
红黑树自平衡基本操作:
1、变色:在不违反上述红黑树规则特点情况下,将红黑树某个node节点颜色由红变黑,或者由黑变红;
2、左旋:逆时针旋转两个节点,让一个节点被其右子节点取代,而该节点成为右子节点的左子节点;
3、右旋:顺时针旋转两个节点,让一个节点被其左子节点取代,而该节点成为左子节点的右子节点;
Set
Set集合类似于一个罐子,程序可以依次把多个对象“丢进”Set集合,而Set集合通常不能记住元素的添加顺序。实际上Set就是Collection只是行为略有不同(Set不允许包含重复元素)。
Set集合不允许包含相同的元素,如果试图把两个相同元素加入同一个Set集合中,则添加操作失败,add()方法返回false,且新元素不会被加入。
Set集合的特征
- Set集合,基础自Collection。特征是插入无序,不可指定位置访问。
- Set集合的实现类可说是基于Map集合去写的。通过内部封装Map集合来实现的比如HashSet内部封装了HashMap。
- Set集合的数据库不能重复(== 或 eqauls)的元素。
- Set集合的常用实现类有 HashSet、TreeSet。
HashSet
HashSet是Set接口的典型实现,大多数时候使用Set集合时就是使用这个实现类。HashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。底层数据结构是哈希表。
HashSet特点
HashSet具有以下特点:
- 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也可能发生变化;
- HashSet不是同步的;
- 集合元素值可以是null;
HashSet的存储结构
当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode方法来得到该对象的hashCode值,然后根据该hashCode值决定该对象在HashSet中的存储位置。如果有两个元素通过equals方法比较true,但它们的hashCode方法返回的值不相等,HashSet将会把它们存储在不同位置,依然可以添加成功。
也就是说。HashSet集合判断两个元素的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode方法返回值也相等。
即:靠元素重写hashCode方法和equals方法来判断两个元素是否相等,如果相等则覆盖原来的元素,以此来确保元素的唯一性。
TreeSet
TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。
存储结构 TreeSet内部实现的是红黑树,默认整形排序为从小到大。
常用方法
与HashSet集合相比,TreeSet还提供了几个额外方法:
- Comparator comparator():如果TreeSet采用了定制顺序,则该方法返回定制排序所使用的Comparator,如果TreeSet采用自然排序,则返回null;
- Object first():返回集合中的第一个元素;
- Object last():返回集合中的最后一个元素;
- Object lower(Object e):返回指定元素之前的元素。
- Object higher(Object e):返回指定元素之后的元素。
- SortedSet subSet(Object fromElement,Object toElement):返回此Set的子集合,含头不含尾;
- SortedSet headSet(Object toElement):返回此Set的子集,由小于toElement的元素组成;
- SortedSet tailSet(Object fromElement):返回此Set的子集,由大于fromElement的元素组成;
排序方式
TreeSet支持两种排序方法:自然排序和定制排序,在默认情况下,采用的是自然排序。
EnumSet
EnumSet类的特点:
- EnumSet是一个专门为枚举类设计的集合类,EnumSet中的所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式或隐式地指定。
- EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum类内的定义顺序来决定集合元素的顺序。
- EnumSet在内部以位向量的形式存储,这种存储形式非常紧凑、高效,因此EnumSet对象占用内存很小,而且运行效率很好。
- EnumSet集合不允许加入null元素。
EnumSet类没有暴露任何构造器来创建该类的实例,EnumSet类提供了以下类方法来创建EnumSet对象。
- EnumSet allOf(Class elementType):创建一个包含指定枚举类里所有枚举值的EnumSet集合。
- EnumSet complementOf(EnumSet s):创建一个其元素类型与指定EnumSet里元素类型相同的EnumSet集合,新的集合里包含原集合不包含的枚举值。
- EnumSet copyOf(Collection c):使用一个普通集合来创建EnumSet集合;
- EnumSet copyOf(EnumSet s):复制原集合;
- EnumSet noneOf(Class elementType):创建一个元素类型为指定枚举类型的空EnumSet;
- EnumSet of(E first,E...rest):创建一个包含一个或多个枚举值的EnumSet集合。传入的枚举值必须是同一枚举类。
- EnumSet range(E from,E to):创建一个包含从from到to枚举值范围所有枚举值的EnumSet集合。
到此这篇关于Java中的WeakHashMap、LinkedHashMap、TreeMap与Set详解的文章就介绍到这了,更多相关Java的WeakHashMap、TreeMap与Set内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!