集合--TreeSet/TreeMap、hashSet/hashMap、vector/arraylist

TreeSet和TreeMap的比较

TreeSet是基于TreeMap是实现的,底层是一颗红黑树。调用TreeSet的add(element)方法,实则调用的是TreeMap的put(key,value)方法,这里的Key是指通过hash函数运算直接映射到对应的二叉树中的位置,value值为TreeSet.add()方法传入的值。

TreeSet和TreeMap集合(按照key排序)里的元素是有序的,因为红黑树是一颗二叉排序树。缺省按照自然排序进行。

TreeSet排序:

使用TreeSet的时候,可以自定义比较器(comparator<泛型>),然后创建TreeSet对象的时候传入比较器对象,实现按照比较器定义的方法进行排序。 如:TreeSet<Person> s = new TreeSet<Person>(new PersonComparator());

TreeMap排序:

由于TreeMap需要排序,所以需要一个Comparator为键值进行大小比较.当然也是用Comparator定位的.
a. Comparator可以在创建TreeMap时指定
b. 如果创建时没有确定,那么就会使用key.compareTo()方法,这就要求key必须实现Comparable接口.
c. TreeMap是使用Tree数据结构实现的,所以使用compare接口就可以完成定位了.

hashSet和hashMap:

hashSet 是基于hashMap实现的,相关的hashSet操作基本上都是直接调用底层hashMap相关方法来实现的。所有放入HashSet中的集合元素实际上由HashMap的key来保存,而HashMap的value则存储了一个static  final 类型的PRESENT变量(没有实际作用),它是一个静态的Object对象。

hashSet和hashMap本身没有排序功能。但可以使用集合包装类collections.sort(集合对象)方法来排序,缺省时为自然排序,可以自定义比较器,collections.sort(集合对象,比较器对象)实现自定义排序。

hashSet扩容:   默认初始容量为16

              加载因子为0.75:即当 元素个数 超过 容量长度的0.75倍 时,进行扩容

                扩容增量:原容量的 1 倍

hashMap扩容:默认初始容量为16

           (为何是16:16是2^4,可以提高查询效率,另外,32=16<<1 )

             加载因子为0.75:即当 元素个数 超过 容量长度的0.75倍 时,进行扩容

             扩容增量:原容量的 1 倍

hashMap插入键值对的底层实现:

hashMap底层是使用Entry对象数组存储的,而Entry是一个单项的链表。当调用一个put()方法将一个键值对添加进来是,先使用hash()函数获取该对象的hash值,然后调用indexFor方法查找到该对象在数组中应该存储的下标,假如该位置为空,就将value值插入,如果该下标出不为空,则要遍历该下标上面的对象,使用equals方法进行判断,如果遇到equals()方法返回真的则进行替换,否则将其插入。

hashSet 是怎么保证元素不重复的?

HashMap的key是不能重复的,而这里HashSet的元素又是作为了map的key,当然也不能重复了

为什么String, Interger这样的wrapper类适合作为键?
String, Interger这样的wrapper类作为HashMap的键是再适合不过了,而且String最为常用。因为String是不可变的,也是final的,而且已经重写了equals()和hashCode()方法了。其他的wrapper类也有这个特点。不可变性是必要的,因为为了要计算hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的hashcode的话,那么就不能从HashMap中找到你想要的对象。不可变性还有其他的优点如线程安全。如果你可以仅仅通过将某个field声明成final就能保证hashCode是不变的,那么请这么做吧。因为获取对象的时候要用到equals()和hashCode()方法,那么键对象正确的重写这两个方法是非常重要的。如果两个不相等的对象返回不同的hashcode的话,那么碰撞的几率就会小些,这样就能提高HashMap的性能。

可以使用自定义的对象作为键吗?
当然你可能使用任何对象作为键,只要它遵守了equals()和hashCode()方法的定义规则,并且当对象插入到Map中之后将不会再改变了。如果这个自定义对象时不可变的,那么它已经满足了作为键的条件,因为当它创建之后就已经不能改变了。

hashMap怎么实现去重?

重写hashcode()方法和equals方法。因为hashMap插入元素是根据key的hashcode找到对应的桶,在对应的桶下比较equals()来找到正确的链表位置,如果equals相等,旧值会被新值覆盖。

ArrayList和Vector

ArrayList和Vector的底层结构是数组。支持随机访问,插入和删除需要移动元素,都有个初始化容量大小,ArrayList、Vector默认初始容量为10。

Vector:线程安全,但速度慢。

扩容:加载因子为1:即当 元素个数 超过 容量长度 时,进行扩容。

         扩容增量:原容量的 1倍。

ArrayList:线程不安全,查询速度快。

扩容:扩容增量:原容量的 0.5倍+1。

数组扩容,就是重新创建新数组,将原数组的值复制到新数组中去。

猜你喜欢

转载自blog.csdn.net/qq_38297106/article/details/80456854