Java 知识点
ArrayList与LinkedList联系与区别:
二者都实现List接口。
1> ArrayList是实现基于动态数组的数据结构;LinkedList实现的是链表的数据结构。
2> 对于随机访问Get和Set,ArrayList优于LinkedList,因为LinkedList要移动指针;
3> 对于新增和删除add、remove,LinkedList优于ArrayList,因为要移动数据;
可以这样说:当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。
HashMap原理:
一般的数据存储物理结构有两种:顺序存储和链式存储。顺序存储的优势在于快速的查找,链式存储的优势在于新增和删除。为了打破二者的尴尬,HashMap就应运而生了。
HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元。Entry是HashMap中的一个静态内部类。
HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度依然为O(1),因为最新的Entry会插入链表头部,急需要简单改变引用链即可,而对于查找操作来讲,此时就需要遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。
Put:
key -> hash(key) -> indexFor(hash(key)): 如果该对应数据已存在,执行覆盖操作。用新value替换旧value,并返回旧value. 否则执行addEntry(hash, key, value, i);
public V put(K key, V value) { //如果table数组为空数组{},进行数组填充(为table分配实际内存空间),入参为threshold,此时threshold为initialCapacity 默认是1<<4(24=16) if (table == EMPTY_TABLE) { inflateTable(threshold); } //如果key为null,存储位置为table[0]或table[0]的冲突链上 if (key == null) return putForNullKey(value); int hash = hash(key);//对key的hashcode进一步计算,确保散列均匀 int i = indexFor(hash, table.length);//获取在table中的实际位置 for (Entry<K,V> e = table[i]; e != null; e = e.next) { //如果该对应数据已存在,执行覆盖操作。用新value替换旧value,并返回旧value Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++;//保证并发访问时,若HashMap内部结构发生变化,快速响应失败 addEntry(hash, key, value, i);//新增一个entry return null; }
Get:
public V get(Object key) { //如果key为null,则直接去table[0]处去检索即可。 if (key == null) return getForNullKey(); Entry<K,V> entry = getEntry(key); return null == entry ? null : entry.getValue(); }
final Entry<K,V> getEntry(Object key) { if (size == 0) { return null; } //通过key的hashcode值计算hash值 int hash = (key == null) ? 0 : hash(key); //indexFor (hash&length-1) 获取最终数组索引,然后遍历链表,通过equals方法比对找出对应记录 for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } return null; }
get方法的实现相对简单,key(hashcode)-->hash-->indexFor-->最终索引位置,找到对应位置table[i],再查看是否有链表,遍历链表,通过key的equals方法比对查找对应的记录。
参考:http://www.cnblogs.com/chengxiao/p/6059914.html#t1
HashMap与HashTable的区别:
1> 所继承的类不同,HashMap继承AbstractMap ,而HashTable继承Dictionary ;
2> HashMap线程不安全,方法是不同步的,HashTable线程是安全的,方法同步;
3> HashMap允许Null的K,V,而HashTable不允许;
总体来说,HashMap的效率要比HashTable高一些,通常会优先考虑使用。
参考:http://blog.csdn.net/java2000_net/article/details/2512510
Sleep,yield和wait的区别
1.来自不同的类分别是,sleep,yield来自Thread类,和wait来自Object类。
2.最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。sleep不出让系统资源;wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。sleep(milliseconds)可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行打断。
3.wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
4. Sleep需要捕获异常,而wait不需要
5.yield方法是“退让”,判断当前是否有相同优先级的线程处于可运行状态,如果有则让该方法运行,没有则原有线程继续运行。同样的,yeild方法不释放锁。
线程的加入:
在A线程中需要加入B线程,则在A的run方法中调用B.join();