List、Set、Map总结!

来源:互联网 发布:bp算法 链式求导 编辑:程序博客网 时间:2024/05/16 18:32

1.Set

            Set在数学上表示集合。元素是无序放入,元素不可重复。因此存入Set的每个元素都必须定义equals()方法判断对象的唯一性。一般情况Set有两个实现类HashSet、TreeSet。其中TreeSet实现了SortedSet接口,所以TreeSet里面的元素是有序的!

2.List

            List是列表。List按照对象进入的顺序保存对象,所以List能对列表中的每个元素的插入和删除的位置进行精确的控制。同时存入的对象可以重复。LinkedList、ArrayList和Vector都实现了List接口。

          ①LinkedList 

                   LinkedList是底层基于链表实现,链表内存是无序的,每个元素存储本身内存地址的同时还存储了下一个元素的地址。对数据的索引需要从列表头开始遍历,所以它的随机访问效率低。但是插入和删除元素时不需要对数据进行移动。因此插入和删除的效率高。但是LinkedList是线程不安全的。线程安全集合简单记:喂!SHE!  喂是指  vector,S是指 stack, H是指   hashtable,E是指:Eenumeration
            

          ②ArrayList

                    ArrayList是基于数组存储的,但它的存储是动态的。通过添加和删除元素,就可以动态改变数组的长度。由于数据存储是连续的所以它的随机访问效率非常的高,但是增加和删除操作如果不是最后一个元素就需要移动之前的数据,你不可能保存每次的增加和删除操作都是在最后处进行的,所以增加和删除操作的效率很低。为了提高程序的效率,每次扩充容量不是简单的扩充一个存储单元,ArrayList默认是扩充为原来的1.5倍。也是线程不安全的!
         

          ③Vector

            Vector和ArrayList基本相同,最大的区别在于。Vector是线程安全的。但是在性能上却是比不上ArrayList。Vector每次扩充容量,一般为之前的2倍,但是它的扩充的大小是可以设置的。

          ④如何使用它们:

            当对数据的主要操作为索引或者只在集合的最后处进行增加删除操作的时候,使用ArrayList或Vector效率比较高!当对数据的操作主要为指定位置进行插入或删除操作的时候,使用LinkedList的效率会比较高!当在多线程中使用时,选用Vector比较安全!

3.Map

             Map提供了一个从键映射到值的数据结构。它用于保存键值对,其中值可以重复,但键是唯一的。HashMap、TreeMap、HashTable、LinkedHashMap、WeakHashMap、IdentityHashMap和ConcurrentSkipListMap都实现了该接口。HashMap是基于散列表存储的,采用对象的HashCode可以进行快速的查询。平均时间复杂能够达到O(1)。LinkedMap采用列表来维护内部的顺序。TreeMap基于红黑树的数据结构来实现的,平均时间复杂度能够达到O(logn),内部的元素是需要排序的。ConcurrentSkipListMap是基于跳表实现的,平均时间复杂度可以达到O(logn)。

        ①HashMap与HashTable区别

                 一、HashMap是HashTable的轻量级实现。都实现了Map接口。public class Hashtable<K,V>extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable     public class HashMap<K,V>extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable。这是它们在代码继承的类和实现的接口。HashMap的键值允许为空,但最多只能是一个。
                二、HashMap把HashTable的contains方法去掉了,改成了containsvalue和containsKey,因为contains方法容易让人引起误解。HashTable继承Dictionary类,而HashMap继承AbstractMap,是java1.2引进的Map interface的一个实现。
                三、HashTable是线程安全的,而HashMap是不支持线程同步的,所以它是线程不安全的。在多个线程访问HashTable时,不需要开发人员对它进行同步。而对于HashMap而言,开发者必须额外提供同步机制。效率而言HashMap高于HashTable。
                四、HashTable使用Enumeration,HashMap使用Iterator。 
                五、HashTable和HashMap采用的hash/rehash算法都几乎是一样,所以性能不会有很大的差异。
                六、HashTable中hash数据默认的大小是11,增加的方式是old*2+1,HashMap中hash数据的默认大小是16,而且一定是2的指数。
                七、hash值的使用不同,HashTable直接使用对象的HashCode。
                

         ②自定义作为HashMap需要注意什么?

                 HashMap是采用键值对存放的。在使用的时候有一个限制:不能用来存储重复的键。简而言之,每个键只能映射一个值。当有重复的键时,不会创建新的映射关系,而会使用先前的value值。      
从上面可以看出“222”,被后面的“333”覆盖了。这是因为前面已经添加的数据有相同的key:"111",因此会用新的值“333”代替“222”的值。但当用自定义类的对象作为HashMap的key时,有时候会给人造成一种假象——key可以重复。
从这个例子看它们的key的值时相同的,为什么后面没有覆盖前面的value?
       在向HashMap中添加键值对的时候,需要经过几个步骤。
         首先调用key的hashCode()方法生成的hash的值,如果这个值不存在,那么这个值在HashMap中不存在,之后直接将<key,value>添加到HashMap中。如果这个值已经存在,那么找出HashMap中所以hash值和它相同的key,然后分别调用key的equas()方法判断当前的添加的key值是否与已经存在的key值相同,返回true,说明当前需要添加的key已经存在,那么新的value会覆盖之前的value。如果返回false,说明新增的key之前不存在,那么会在HashMap中创建新的映射关系。当新增key的hash值已经存在HashMap时,就会产生冲突。一般而言,处理关系的方法有开放地址法、再次哈希、链地址法等。HashMap使用的是链地址法来解决冲突的。 
         上图中在使用自定义的类作为HashMap作为HashMap时没有重写hashCode()和equals()方法,默认使用了Object中的方法。上图中虽然它们的值时相同,但你调用的是Object的方法,它判断的时候值的地址是否相同。由于是new 所以它们的地址不同,equals()返回的是false,所以对HashMap是两个不同的对象,就会分别创建不同的映射关系。若果想要实现判断两个对象的内容是否相等,就需要重写hashCode()和equals()方法。
public int hashCode() {
return id.hashCode();
}
public boolean equals(Object obj) {
People people = (People) obj;
if (people.id.equals(this.id)) {
return true;
}else {
return false;
}
}