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();

posted @ 2017-04-13 00:58  小猪阿正  阅读(145)  评论(0编辑  收藏  举报