Java集合框架

集合框架                                                          

 

  集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。
  接口:即表示集合的抽象数据类型。接口提供了让我们对集合中所表示的内容进行单独操作的可能。
  实现:也就是集合框架中接口的具体实现。实际它们就是那些可复用的数据结构。
  算法:在一个实现了某个集合框架中的接口的对象身上完成某种有用的计算的方法,例如查找、排序等。这些算法通常是多态的,因为相同的方法可以在同一个接口被多个类实现时有不同的表现。事实上,算法是可复用的函数。

 

相关类                                                             

 

  java.util里面有一个Arrays类,它包括了一组可用于数组的static方法,这些方法都是一些实用工具。其中有四个基本方法:用来比较两个数组是否相等的equals();用来填充的fill();用来对数组进行排序的sort();以及用于在一个已排序的数组中查找元素的binarySearch()。所有这些方法都对primitive和Object进行了重载。此外还有一个asList()方法,它接受一个数组,然后把它转成一个List容器。
  虽然Arrays还是有用的,但它的功能并不完整。举例来说,如果它能让我们不用写for循环就能直接打印数组,那就好了。此外,正如你所看到的fill()只能用一个值填数组。所以,如果你想把随机生成的数字填进数组的话,fill()是无能为力的。

框架益处                                                                  

  减少设计辛劳
    集合框架通过提供有用的数据结构和算法使你能集中注意力于你的程序的重要部分上,而不是为了让程序能正常运转而将注意力于低层设计上。通过这些在无关API之间的简易的互用性,使你免除了为改编对象或转换代码以便联合这些API而去写大量的代码。

  提高速度质量
    集合框架通过提供对有用的数据结构和算法的高性能和高质量的实现使你的程序速度和质量得到提高。因为每个接口的实现是可互换的,所以你的程序可以很容易的通过改变一个实现而进行调整。另外,你将可以从写你自己的数据结构的苦差事中解脱出来,从而有更多时间关注于程序其它部分的质量和性能。

  API缺点
    许多API天生的有对集合的存储和获取。在过去,这样的API都有一些子API帮助操纵它的集合内容,因此在那些特殊的子API之间就会缺乏一致性,你也不得不从零开始学习,并且在使用时也很容易犯错。而标准集合框架接口的出现使这个问题迎刃而解。

集合框架复用                                                                

                    

    对于遵照标准集合框架接口的新的数据结构天生即是可复用的。同样对于操作一个实现了这些接口的对象的算法也是如此。
    有了这些优点,并通过合理的使用,它就会成为程序员的一种强大的工具。不过,从历史上来看,集合大多其结构相当复杂,也就给它们一个造成极不合理的学习曲线的坏名声。但是,希望Java2的集合框架能缩短你的学习曲线,从而快速掌握它。
    在许多高级语言中的数组其实也是集合的一种简单实现,比如C,C++,Pascal和Java。数组保存着相同类型的多个值,它的长度在数组被创建时就固定下来,建立之后就无法改变。如果你需要一种大小能动态改变的存储结构,数组就不适合了,这时集合框架就有了用武之地了。

Collection                                                                    

    Collection接口提供了一组操作成批对象的方法

 

List                                                                              

    List接口对Collection进行了简单的扩充
    它的具体实现类常用的有ArrayListLinkedList。你可以将任何东西放到一个List容器中,并在需要时从中取出。ArrayList从其命名中可以看出它是一种类似数组的形式进行存储,因此它的随机访问速度极快,而LinkedList的内部实现是链表,它适合于在链表中间需要频繁进行插入和删除操作。
    ArrayList:ArrayList是线程不安全的,是一个用数组实现的List。能进行快速的随机访问,但是往列表中间插入和删除元素的时候比较慢。
    inkedList:LinkedList是线程不安全的,对顺  序访问进行了优化。

  1、常用方法:     

     ①add():在列表的最后插入元素
     ②add(index,“ewr”):在列表的指定位置插入元素
     ③size():返回当前列表的元素个数。
     ④get(int index):返回下标为index的元素。
     如果没有泛型约束,返回object类型,需要强转,如果有泛型约束,直接返回泛型类型,无需强转。
     ⑤clear():清楚列表中的所有数据;
     isEmpty():检查列表是否为空;
     ⑥contains():传入一个对象,检查列表中是否包含该对象。
     如果传入的是string 和基本数据类型,可以直接比对。
      如果传入的是实体对象,则默认只比对两个对象的地址。因此,需要在实体类重写equals()方法。
     ⑦indexof():传入一个对象,返回该对象在列表中首次出现的地址
      ⑧remove():传入一个下标,或者一个对象,删除指定元素。
        如果传入下标,返回被删除的元素对象,如果下标大于size(),会下标越界错误。
       如果传入对象,则要求重写equals,返回true或false不是删除结果
     ⑨set(index,obj):用传入的对象,将指定位置的元素替换的;
        返回被替换掉的元素。
     ⑩List.subList(1,3):截取一个子列表,返回List类型
       toArray():将列表转为数据组,返回一个object[]类型的数组

 

  2、ArrayList

 

    实现了一个长度可变的数组,在内存空间中开辟了一串连续的空间,与数组的区别在于长度可以随意修改。
    在这种存储结构,循环遍历和随机访问元素的速度非常快。

  3、LinkedList

 

    使用链表结构存储数据,在插入和删除元素时速度非常快。

    特有方法:

            ①addFirst();开头插入元素
       addLast();
            ②removeFirst():删除第一个元素,并返回被删除的元素
       removeLast
       ③getFirst():返回第一个元素,不删除元素

 

 

Set                                                                           

 

    Set接口也是Collection的一种扩展
    与List不同的是,在Set中的对象元素不能重复,也就是说你不能把同样的东西两次放入同一个Set容器中。它的常用具体实现有HashSetTreeSet类。HashSet能快速定位一个元素,但是你放到HashSet中的对象需要实现hashCode()方法。
    而TreeSet则将放入其中的元素按序存放,这就要求你放入其中的对象是可排序的,这就用到了集合框架提供的另外两个实用类ComparableComparator。一个类是可排序的,它就应该实现Comparable接口。有时多个类具有相同的排序算法,那就不需要在每分别重复定义相同的排序算法,只要实现Comparator接口即可。集合框架中还有两个很实用的公用类:CollectionsArraysCollections提供了对一个Collection容器进行诸如排序、复制、查找和填充等一些非常有用的方法,Arrays则是对一个数组进行类似的操作。


    set接口的特点:唯一 无序。
    hashset 底层是调用hashmap的相关方法,传入数据后,根据数据的hashcode进行散列运算。
    得到一个散列值再进行运算,确定元素在序列中存储的位置。

 

 

  hashset如何确定对象是否相等

 

    ①先判断对象的hashcode(),如果hashcode不同,那肯定不是一个对象
     如果hashcode相同,继续判断equals()方法。
         ②重写equals()方法。

 

 

TreeSet:将存入的元素进行排序再输出                   

 

 

    如果存入的是实例对象,那么实体类必须实现Comparable接口,并重写 comparaTo()方法。

     也可以在实例化TreeSet的同时,通过构造函数传入一个比较器;
      比较器:一个实现了comparator接口,并重写compare()方法的实现类的对象。

     

Set <Person> set =new TreeSet <Person>(new comparator()){
     public int compare(Person p1,Person p2){
      return p1.getID()-p2.getID();
       }
     }

  


     //自定义一个比较类,实现comparator接口
    

 Set <Person> set =new TreeSet <Person>(new Compare()) 
    class Compare implements Comparator(){
     //重写compare方法
     }

  

 

 

Map                                                                            

 

    1、Map接口特点:以键值对的形式存储数据,以键取值
     键不能重复,值可以重复

    2、Map接口的常用方法
      ①put(key,value):向map的最后增加一个键值对
      ②get(key):通过键取到值
      ③clesr():清除map的所有数据
      ④containsValue(obj):检测是否包含指定的值。
       containsKey(obj):检测是否包含指定的键。

 

 

linkedHashMap                                                         

    可以使用链表,记录数据放入的次序,读出顺序等于存放顺序。

TreeMap                                                                    

 

     根据键的顺序 进行排序后输出。
     如果传入的是实体对象。必须重写比较函数,详见TreeSet

 

  HashMap和Hashtable的区别

 

    两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全。Hashtable的实现方法里面都添加了synchronized关键字来确保线程同步,因此相对而言HashMap性能会高一些,我们平时使用时若无特殊需求建议使用HashMap,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合(Collections.synchronizedMap()实现原理是Collections定义了一个SynchronizedMap的内部类,这个类实现了Map接口,在调用方法时使用synchronized来保证线程同步,当然了实际上操作的还是我们传入的HashMap实例,简单的说就是Collections.synchronizedMap()方法帮我们在操作HashMap时自动添加了synchronized来实现线程同步。
    HashMap可以使用null作为key,不过建议还是尽量避免这样使用。HashMap以null作为key时,总是存储在table数组的第一个节点上。而Hashtable则不允许null作为key。
    HashMap继承了AbstractMap,HashTable继承Dictionary抽象类,两者均实现Map接口。
    HashMap的初始容量为16,Hashtable初始容量为11,两者的填充因子默认都是0.75。
    HashMap扩容时是当前容量翻倍即:capacity*2,Hashtable扩容时是容量翻倍+1即:capacity*2+1。
    两者计算hash的方法不同:

 

    Hashtable计算hash是直接使用key的hashcode对table数组的长度直接进行取模:

int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;


HashMap计算hash对key的hashcode进行了二次hash,以获得更好的散列值,然后对table数组长度取摸:


static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}


static int indexFor(int h, int length) {
return h & (length-1);
}

  

    判断是否含有某个键
    在HashMap 中,null 可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null 值时,既可以表示HashMap 中没有该键,也可以表示该键所对应的值为null。因此,在HashMap 中不能用get()方法来判断HashMap 中是否存在某个键,而应该用containsKey()方法来判断。Hashtable 的键值都不能为null,所以可以用get()方法来判断是否含有某个键。

   


 

posted @ 2018-04-15 19:35  wyu1258  阅读(134)  评论(0编辑  收藏  举报