Java集合###
直接输出Collection是通过AbstractCollection类的toString()方法:
public String toString() {
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}
Map类的是通过AbstractMap类的toString()方法###
public String toString() {
Iterator<Entry<K,V>> i = entrySet().iterator();
if (! i.hasNext())
return "{}";
StringBuilder sb = new StringBuilder();
sb.append('{');
for (;;) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
sb.append(key == this ? "(this Map)" : key);
sb.append('=');
sb.append(value == this ? "(this Map)" : value);
if (! i.hasNext())
return sb.append('}').toString();
sb.append(',').append(' ');
}
}
数组是连续的内存空间,查询速度快,增删慢;
链表充分利用了内存,内存间是不连续的。首尾存储上下一个节点的信息,所以寻址麻烦,查询速度慢。
哈希表综合了上面两点,一个哈希表,由数组和链表组成。如果一条链表有1000条节点,要查找最后一个节点。用哈希表,将链表分为10组,用一个容量10数组来存储这10组链表的表头节点,这样寻址就快了。
Hash碰撞,不同的key根据hash算法算出的值可能一样,一样的话就会出现所谓的碰撞。
HashMap的扩容代价非常大,要生成一个新的桶数组,然后把所有元素重新hash落桶一次,几乎等于重新执行了一次所有元素的put。如果要对map的大小有一个范围的话,可以在构造时给定大小,一个大小设置为:(int) ((float) expectedSize / 0.75F + 1.0F)。并且,key尽量设计简洁。
HashMap的遍历方式中,使用keySet的两种方式都会遍历两次,所以效率没有使用EntrySet高
HashMap输出是无序的,这个无序不是说每次遍历结果顺序不一样,而是说输出和输入顺序不一样。
HashMap排序方式:
- HashMap的按值排序通过Collection 的sort方法
- TreeMap是按键排序的,默认升序,再把已经排序的TreeMap防务HashMap中
- 通过keySet取出所有key然后将key排序,再有序将key-value键放到LinkedHashMap中
HashMap去重: - 将HashMap的key-value对调,赋值给一个新的HashMap中,然后再对调。
HashMap线程同步###
//方式一:
Map<Integer, String> hs = new HashMap<Integer, String>();
hs.Collections.synchornizedMap(hs);
//方式二:
ConcurrentHashMap<Integer, String> hs = new ConcurrentHashMap<Integer, String>();
IdentifyHashMap###
与HashMap基本相似,只是当两个key严格相等时,才认为两个key相等。允许使用key,但不保证键值对之间的顺序。
WeakHashMap###
与HashMap基本相同,HashMap的key保留对象的强引用即只要HashMap对象不被销毁,其对象所有key所引用的对象不会被垃圾回收,HashMap也不会自动删除这些key所对应的键值对对象。但WeakHashMap的key所引用的对象没有被其他强引用变量所引用,则这些key所引用的对象可能被回收。WeakHashMap中的每个key对象保存了实际对象的弱引用,当回收了该key所对应的实际对象后,WeakHashMap会自动删除该key所对应的键值对
ArrayList和Vector本质都是用数组实现的,而LinkList是用双链表实现的
Map集合遍历###
import java.util.*;
public class MapI{
public static void main(String[] args){
Map<Integer, String> m = new HashMap<Integer, String>();
m.put(1,"String1");
m.put(2,"String2");
m.put(3,"String3");
m.put(4,"String4");
//Map.Entry<Integer, String> me = m.entrySet();
Iterator<Map.Entry<Integer, String>> iterator = m.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<Integer,String> entry = iterator.next();
System.out.println(entry.getKey() + " --- " + entry.getValue());
}
for(Map.Entry<Integer,String> entry: m.entrySet()){
System.out.println(entry.getKey() + " --- " + entry.getValue());
}
}
}
HashSet###
散列码是由对象导出的一个整数值。在Object中有一个hashCode方法来得到散列码。基本上,每一个对象的默认散列码,其值就是对象的内存地址。但也有一些对象的散列码不同,比如String对象,它的散列码就是对内容的计算结果:
public int hashCode() {
int h = hash; //hash默认值0
if (h == 0 && value.length > 0) { //value是字符数组
char val[] = value;
for (int i = 0; i < value.length; i++) { //遍历字符数组
h = 31 * h + val[i]; //31乘以现有hash值加上数组元素,String通过内容计算的
}
hash = h;
}
return h; //返回hash值
}
HashSet的添加机制(默认大小:16,每次增加一倍):Java默认的散列单元大小全部都是2的次幂,初始值为16(2的4次幂)。加入链表的75%有数据的时候,则认为加载因子达到默认的0.75,HashSet开始重新散列,也就是将原来的散列结构全部抛弃,重新开辟一个散列单元为32(2的5次幂)的散列结果,并重新计算各个数据的存储位置。
根据数据的散列码和散列表的数组大小计算除余后,就得到了所在数组的位置,然后再查找链表中是否有这个数据即可。
查找的代价就是在链表中,但是真正一条链表中的数据很少,有的甚至没有。几乎没有什么迭代的代表可言,所以散列表的查找效率教黎在散列单元所指向链表中的数据要少。
HashSet不能重复存储equals相同的数据。原因就是equals相同,数据的散列码也就相同。大量相同的数据存放在同一个散列单元所指向的链表中,造成严重的散列冲突,对查找效率灾难性的
LinkedHashSet
以哈希表和链表实现的set集合,链表定义了迭代顺序,即我们插入元素的顺序。如果一个元素被重复插入到集合中并不会改变集合的插入顺序
LinkedHashSet在迭代访问Set全部元素时,性能比HashSet好。但是在插入的时候稍微逊色于HashSet。
TreeSet###
比较器比较
Set<Person> s = new TreeSet<Person>(
new Comparator<Person>(){
public int compare(Person p1, Person p2) {
int num = p2.getAge() - p1.getAge();
return num;
}
}
);
自然排序:通过实现Comparable接口
TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序(没有就报错ClassCastException)
TreeSet如果传入Comparator, 就优先按照Comparator
ArrayList 初始值10,扩容倍数1.5 新的容量是1.5+1
ArrayDeque 初始值8,扩容倍数2
vector 初始值10,扩容倍数2
BitSet 初始值64,扩容倍数2
HashMap 初始值16,扩容倍数2
HashSet/TreeSet 同HashSet(基于HashMap实现,value为空Object)
Hashtable 初始值11,扩容倍数2
WeakHashMap 同HashMap
PriorityQueue 初始值11,两倍太小的话再增加50%
注意:HashSet,HashMap,Hashtable的加载因子都是0.75,即容量达到0.75就扩容。