1. 程式人生 > 其它 >常用集合類:

常用集合類:

1、iterator便利:

  所有的集合父類collection實現了Iterable。該集合裡有三個方法  其中一個重要的方法 iterator()方法。在所有集合的實現類重寫了這個方法。

 ArrayList list= new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
       
        Integer integer = new Integer(2);
        list.remove(integer);
        
        Iterator iterator 
= list.iterator(); // ListIterator iterator = list.listIterator(); while(iterator.hasNext()){ Object o = iterator.next(); if(o.equals(1)){ iterator.remove(); //此處遍歷器已經不支援刪除操作 也不zhichilist.remove(o) 所以用list。listIterator() } System.out.println(o); } }

 但是通過便利刪除list.remove()會資料上移,造成遊標的混亂判斷。所以會報異常,那麼可以用通過iterator 的remove方法實現,通過原始碼可以看到此處丟擲了一個異常,不支援這個方法。

那麼可以通過arraylIst的listIterator()來進行便利實現。

在使用iterator進行迭代的過程中如果刪除其中的某個元素會報錯,併發操作異常,因此
*       如果遍歷的同時需要修改元素,建議使用listIterator(),
*   ListIterator迭代器提供了向前和向後兩種遍歷的方式
*       始終是通過cursor和lastret的指標來獲取元素值及向下的遍歷索引
* 當使用向前遍歷的時候必須要保證指標在迭代器的結果,否則無法獲取結果值
Iterator iterator = list.iterator();
//        ListIterator iterator = list.listIterator();
        while(iterator.hasNext()){
            Object o = iterator.next();
            if(o.equals(1)){
                iterator.remove();
            }
            System.out.println(o);
        }
//        System.out.println("-------------");
//        while (iterator.hasPrevious()){
//            System.out.println(iterator.previous());
//        }
//        for(Object i : list){
//            System.out.println(i);
//        }

如上圖:此時向前便利,向後便利。如果指標在最後面獲取不到元素。

2、vector也是list的實現類,他是執行緒安全的。

3、list的實現類主要有arrayList和LinkList兩類。arraylist底層是陣列實現,那麼查詢會快一些。linkList底層是連結串列實現。刪除和插入快一些。修改的查詢話都需要逐個便利元素。

4、以後儘量減少使用增強for迴圈,不變與對資料的操作。

5、摘要

ListIterator的作用解決併發操作異常
▪ 在迭代時,丌可能通過集合物件的方法(al.add(?))操作集合中的元素,
▪ 會發生併發修改異常。
▪ 所以,在迭代時只能通過迭代器的方法操作元素,但是Iterator的方法
▪ 是有限的,只能進行判斷(hasNext),取出(next),刪除(remove)的操作,
▪ 如果想要在迭代的過程中進行向集合中新增,修改元素等就需要使用
▪ ListIterator介面中的方法
ListIterator li=al.listIterator();
while(li.hasNext()){
 Object obj=li.next();
 if ("java2".equals(obj)) {
 li.add("java9994");
 li.set("java002");
 }
}

6、迭代器會維持到方法體結束,消耗記憶體空間。迭代器從建立一開始,一直到方法結束。所以建議用第二種方法。寫在for 迴圈裡作用域是這個迴圈內。

  建議用第二中反方法,放到for迴圈裡實現。

二、set set是無序的且不重複的集合。常見的實現有hashSet和TreeSet和LinkHashSet。

  通過底層程式碼,我們可以看到hashSet就是hashMap。是通過計算新增資料的hashcode值。在比較equas方法,通過演算法去重,資料雜湊,實現無序且不可重複的集合。好的演算法可以減少資料的雜湊。

   TreeSet可以確保資料的一致性,底層是TreeMap 紅黑樹。查詢速度快一些。紅黑樹與平衡樹最大的區別就是減少了自旋所帶來的效能消耗,提升了插入效率。

  1、hashSet和TreeSet的區別:

Set介面中的實現類
▪HashSet:採用Hashtable雜湊表儲存結構
–優點:新增速度快,查詢速度快,刪除速度快
–缺點:無序
–LinkedHashSet
▪ 採用雜湊表儲存結構,同時使用連結串列維護次序
▪有序(新增順序)
▪TreeSet
–採用二叉樹(紅黑樹)的儲存結構
–優點:有序(排序後的升序)查詢速度比List快
–缺點:查詢速度沒有HashSet快

  不同點:treeSet新增資料的時候,必須要新增同一型別,並且有可以排序的資料比較。

  

 

 

 內部比較器:實現compareable介面。

  

 

 

 外部比較器的使用:

  在當前類中實現 Comparator介面,並重寫了 compare方法。然後把該比較器傳入到集合中。

public class SetDemo implements Comparator<Person> {
    public static void main(String[] args) {

        TreeSet treeSet = new TreeSet(new SetDemo());
        treeSet.add(new Person("lisi",15));
        treeSet.add(new Person("wangwu",13));
        treeSet.add(new Person("maliu",12));
        treeSet.add(new Person("zhangsan",19));
        treeSet.add(new Person("zhangsan",12));
        System.out.println(treeSet);


    }

    @Override
    public int compare(Person o1, Person o2) {
        if(o1.getAge()>o2.getAge()){
            return -1;
        }else if(o1.getAge() < o2.getAge()){
            return 1;
        }else{
            return 0;
        }
    }

set內容總結:

*   1、set中存放的是無序,唯一的資料
*   2、set不可以通過下標獲取對應位置的元素的值,因為無序的特點
*   3、使用treeset底層的實現是treemap,利用紅黑樹來進行實現
*   4、設定元素的時候,如果是自定義物件,會查詢物件中的equals和hashcode的方法,如果沒有,比較的是地址
*   5、樹中的元素是要預設進行排序操作的,如果是基本資料型別,自動比較,如果是引用型別的話,需要自定義比較器
*       比較器分類:
*         內部比較器
*               定義在元素的類中,通過實現comparable介面來進行實現
*         外部比較器
*               定義在當前類中,通過實現comparator介面來實現,但是要將該比較器傳遞到集合中
*         注意:外部比較器可以定義成一個工具類,此時所有需要比較的規則如果一致的話,可以複用,而
*               內部比較器只有在儲存當前物件的時候才可以使用
*               如果兩者同時存在,使用外部比較器
*               當使用比較器的時候,不會呼叫equals方法

  當使用比較器的時候,如果比較的值相當,那麼會進行去重操作。

 三、泛型

  泛型的使用: 

 泛型的高階應用:
 *      1、泛型類
 *          在定義類的時候在類名的後面新增<E,K,V,A,B>,起到佔位的作用,類中的方法的返回值型別和屬性的型別都可以使用
 *      2、泛型介面
 *          在定義介面的時候,在介面的名稱後新增<E,K,V,A,B>,
 *          1、子類在進行實現的時候,可以不填寫泛型的型別,此時在建立具體的子類物件的時候才決定使用什麼型別
 *          2、子類在實現泛型介面的時候,只在實現父類的介面的時候指定父類的泛型型別即可,此時,測試方法中的泛型型別必須要跟子類保持一致
 *      3、泛型方法
 *          在定義方法的時候,指定方法的返回值和引數是自定義的佔位符,可以是類名中的T,也可以是自定義的Q,只不過在使用Q的時候需要使用<
 *          Q>定義在返回值的前面
 *      4、泛型的上限(工作中不用)
 *          如果父類確定了,所有的子類都可以直接使用
 *      5、泛型的下限(工作中不用)
 *          如果子類確定了,子類的所有父類都可以直接傳遞引數使用
 *

   1、定義泛型類 預設E代表element  k是key  v是value

public class FanXingClass<A> {

    private int id;
    private A a;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }

    public void show(){
        System.out.println("id : "+id+" ,A : "+a);
    }

    public A get(){
        return a;
    }

    public void set(A a){
        System.out.println("執行set方法:" + a);
    }

    2、定義泛型的介面實現:

package _05_第五章泛型.E202_05_02_資料相加;
public class Test {
    public static void main(String[] args) {
        Point p1 = new Point(1,1);
        Point p2 = new Point(3,2);
 
        Circle circle = new Circle(p1,2);
        Circle circle2 = new Circle(p2,3);
        System.out.printf("兩個 圓 相加結果:\n");
        System.out.println(circle2.add(circle));
 
        Complex complex = new Complex(1,1);
        Complex complex2 = new Complex(2,2);
        System.out.printf("兩個 複數 相加結果:\n");
        complex2.Print(complex2.add(complex));
    }
}
 
package _05_第五章泛型.E202_05_02_資料相加;
public interface Add<T> {
    public T add(T t);
}
 
package _05_第五章泛型.E202_05_02_資料相加;
public class Circle implements Add<Circle> {
    private Point p;//圓心
    private float r;//半徑
 
    public Circle(Point p, float r) {
        this.p = p;
        this.r = r;
    }
    public Circle add(Circle circle2){
        circle2.p =this.p.add(circle2.p);
        circle2.r =this.r + circle2.r ;
        return circle2;
    }
    @Override
    public String toString() {
        return String.format("圓心:(%f,%f)  半徑:%f",p.x,p.y,r);
    }
}

    3、泛型的方法比較特殊,如果沒有返回值,那麼需要新增哥泛型。

public class FanXingMethod<T> {
    private T t;
    public T getT() {
        return t;
    }
    public void setT(T t) {
        this.t = t;
    }
    public <Q> void show(Q q){
        System.out.println(q);
        System.out.println(t);
    }

三、Map類 

1、hashmap跟hashtable的區別:

1、hashmap執行緒不安全,效率比較高,hashtable執行緒安全,效率低
2、hashmap中key和value都可以為空,hashtable不允許為空

map儲存的是k-v鍵值對對映的資料
 *      實現子類:
 *          HashMap:資料+連結串列(1.7) 陣列+連結串列+紅黑樹(1.8*          LinkedHashMap:連結串列
 *          TreeMap:紅黑樹

2、常見的hashMap便利操作

 //遍歷操作
        Set<String> keys = map.keySet();
        for(String key:keys){
            System.out.println(key+"="+map.get(key));
        }

        //只能獲取對應的value值,不能根據value來獲取key
        Collection<Integer> values = map.values();
        for (Integer i:values){
            System.out.println(i);
        }

        //迭代器
        Set<String> keys2 = map.keySet();
        Iterator<String> iterator = keys2.iterator();
        while(iterator.hasNext()){
            String key = iterator.next();
            System.out.println(key+"="+map.get(key));
        }
        //Map.entry
        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator1 = entries.iterator();
        while (iterator1.hasNext()){
            Map.Entry<String, Integer> next = iterator1.next();
            System.out.println(next.getKey()+"--"+next.getValue());
        }

Map.ENtry格式型別:有key和value和hashCode值 有指標

  

  在java8以後hashMap是什麼時候使用紅黑樹的?在大於8的時候。

  hashMap初始化的陣列長度為2的N次冪。這樣便於位移運算擴容。