Java集合(上)

來源:互聯網
上載者:User

標籤:區別   each   title   contains   type   article   代碼   array   string   

基礎知識:

什麼是集合?

集合是一個容器。把多個對象放入容器中。有一個水杯,你可以選擇把水不斷往裡裝,也可以選擇裝牛奶。但是不能兩種不同的東西混合裝一個杯子。集合這個容器裡裝的一定是同一類型的東西。(參考型別,不能是基本類型)

看到這個介紹,我們可能想到數組,數組要求的也是裡面必須存放的是一種資料類型的結構。

數組和集合的區別呢?

數組大小是固定的,集合的大小理論上是不限定。

數組裡的元素可以是基本類型,也可以是參考型別。集合只能放參考型別。

是集合家族的主要成員們(圖來自百度)

由圖可見,Collection介面Map介面是兩個老大。Collection介面下面又生出來了Set介面(無序),List介面(有序),queue介面。Map介面儲存的是有映射關係的資料。Map裡的子類都有一個共同的特徵就是裡面資料都是key-value.舉例,語文-80,數學-78,科目是不能重複的,分數是可以重複的,所以,Map裡的key不能重複,value可重複。需要查分數(value),就通過科目(Key)來取。

具體實作類別,常用的有ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap等等,主要分為以下三類

從可知,Set集合是無序的,只能根據集合裡的元素本身訪問。

List集合是有序的,可以通過索引訪問。

Map集合可通過每個元素的Key訪問value.

下面列出了Collection介面下方法

 大概看一眼,這些方法無非就是添加對象,移除對象,判斷集合是不是空,清空容器,所以無需記憶。

有方法值的一提的是  當你需要把集合元素轉成數組元素時候用Object[]  toArray() ,有個陷阱:注意注釋部分,數組不能直接(String[])這樣強制將陣列變數轉換,只有在使用使將元素轉換為String,

首先看下List的這兩個方法的說明:

 Object[ ] toArray() :返回按適當順序包含列表中的所有元素的數組(從第一個元素到最後一個元素)。

 <T> T[ ]  toArray(T[] a) :返回按適當順序(從第一個元素到最後一個元素)包含列表中所有元素的數組;返回數組的運行時類型是指定數組的運行時類型

 Collection<String> arr = new ArrayList<String>();       arr.add("a");       arr.add("b");       arr.add("b");//可以添加重複的對象       // String[] str = (String[])arr.toArray();//error

       Object[] obj = arr.toArray();//第一種方法

       String[] obj1 = arr.toArray(new String[3]);//第二種方法

Db.query()第二個是多個不確定的參數,多個參數可以被作為數組傳進來。List集合轉數組舉例

/**     * 封裝預先處理參數解析並執行查詢     * @param sqlId     * @param param     * @return     */    public <T> List<T> query(String sqlId, Map<String, Object> param){        LinkedList<Object> paramValue = new LinkedList<Object>();        String sql = getSqlByBeetl(sqlId, param, paramValue);        return Db.query(sql, paramValue.toArray());    }

 

補充下getSqlByBeetl如果要sql裡需要Map的話,如下參考:

/**     * 驗證編碼是否存在     * @param operatorid     * @param type     * @return boolean     * 描述:新增角色群組時operatorid為空白,修改角色群組時operatorid傳值     */    public boolean valiQbgjxwcqkxxno(String qbgjxwcqkxxno, String type){        Map<String, Object> param = new HashMap<String, Object>();        param.put("column", Jxwc.column_qbggyzfqkxxno);        param.put("table", Jxwc.table_name);        String sql = getSqlByBeetl(Jxwc.sqlId_select, param);        List<Jxwc> list = Jxwc.dao.find(sql,qbgjxwcqkxxno);        int size = list.size();        if("add".equals(type)){            if(size == 0){                return true;            }        }else{            if(size <= 1){                return true;            }        }                return false;    }

 

Collection介面是 List,Set,Queue介面的父介面,所以Collection圖方法都能操作下這三種集合。 Itertor介面

看集合主要成員圖可知Itertor介面不在圖上,但是他也是集合架構的成員,但是它與Map集合系列,C

ollection集合系列不同,它主要裝的是遍曆Collection集合裡的元素。Itertor對象也叫迭代器,依託Collection對象存在。提供遍曆Collection的統一編程介面。

 

主要的方法:

boolean hasNext() 要是被遍曆的集合還沒遍曆完,就返回true

Object next() 返回集合裡的下一個元素

void remove() 刪除上一次next()返回的元素

package Test01;   import java.util.Collection;import java.util.HashSet;import java.util.Iterator;  public class Test {      public static void main(String[] args) {        Collection  arr = new HashSet<>();        arr.add("a");        arr.add("b");        arr.add("C");//可以添加重複的對象        Iterator  iterator =arr.iterator();        while(iterator.hasNext()) {         String next =     (String) iterator.next();         System.out.println(next);         if(next.equals("C")) {             iterator.remove();         }          next ="修改迭代變數的值看看有沒影響";    //注意下        }           System.out.println(arr.toString());     }}

運行完發現“注意下”的地方本想改變集合裡的元素卻沒變。所以可得到:Iterator並不是得到集合本身的元素,而是得到元素的值而已,所以修改迭代變數的值並不會影響集合本身。

Iterator不像其他集合,沒有承裝對象的能力。如果他不依託集合存在,根本沒存在的價值。

想刪除集合元素,必須通過Iterator的remove() 刪除上一次next()返回的元素,不能集合自己remove(Object)

舉例,會發現異常

 

package Test01;   import java.util.Collection;import java.util.HashSet;import java.util.Iterator;  public class Test {      public static void main(String[] args) {        Collection  arr = new HashSet<>();        arr.add("a");        arr.add("b");        arr.add("C");//可以添加重複的對象        Iterator  iterator =arr.iterator();        while(iterator.hasNext()) {         String next =     (String) iterator.next();         System.out.println(next);         if(next.equals("b")) {             arr.remove(next);         }          next ="修改迭代變數的值看看有沒影響";        }           System.out.println(arr.toString());     }}

 

異常原因是 迭代器採用快速-失敗原則(fast-fail),一旦迭代過程中發現Collection集合中元素被修改,就引發異常。偶爾發現,如果剛剛代碼改成

if(next.equals("C")) {             arr.remove(next);         }

也不會異常,----只有刪除特定元素才會這樣,但是不該冒險去做。

foreach也能迭代訪問集合,但是注意,他得到的也不是集合元素本身,系統只是把集合元素的值賦給迭代變數而已,也同樣同上會引發Java ConcurrentModificationException異常。

如下代碼(錯誤示範)

 

package Test01;   import java.util.Collection;import java.util.HashSet;import java.util.Iterator;  public class Test {      public static void main(String[] args) {        Collection  arr = new HashSet<>();        arr.add("a");        arr.add("b");        arr.add("C");//可以添加重複的對象         for(Object a:arr) {         if(a.equals("b")) {             arr.remove(a);         }          }    }      }

 

 

Set集合

就像把對象隨意扔進罐子裡,無法記住元素的添加順序。Set某種程度就是Collection,方法沒有不同,只是行為稍微不同,(不允許重複元素),如果一定要往裡加兩個相同元素,添加失敗add()返回false; 

上面的Set的一些共同點,Hashset,TreeSet,EunmSet三個實作類別還各有特色。

依次介紹下

Hashset 

判斷Hashset 集合裡的兩個對象相等,過兩關,equal()比較相等,對象的hashcode()也相等

為什麼還得比較對象的hashcode()?

Hashset 集合收進一個對象時,會調用對象的hashcode()得到其Hashcode值來決定他的儲存位置。所以,即使是equal()比較相等的兩個對象,hashcode不同,存放在hashset裡的位置不同,依然能把這兩個對象添加成功。

注意:把對象裝進hashset時,如果要重寫equals方法,也得重寫hashcode 方法,因為equals()相等的兩對象hashcode 也是相同的。

提問:hashcode()對hashset是很重要的嗎?

答:hash演算法是快速尋找被檢索的對象。通過對象的hashcode定位集合裡的對象的儲存位置。定位該元素。對比下,數組是儲存一組元素最快的數組結構,數組通過索引找到它的組員,通過索引能計算元素在記憶體裡的儲存位置。

但是為嘛有了數組,還用hashset呢?數組也有局限性,索引是連續的,而且長度不可變。

hashset有了hashcode,所以能快速定位對象位置,而且任意增加對象。

重寫hashcode() 注意java.lang.Object中對hashCode的約定:

兩個對象通過equals()比較相等時,他們的hashcode 也應該是一樣的。

程式運行過程中,同一個對象多次調用hashcode方法返回應該是一樣的。

如果根據 equals(java.lang.Object) 方法,兩個對象不相等,那麼在兩個對象中的任一對象上調用 hashCode 方法不一定會產生不同的整數結果。但是,為不相等的對象產生不同整數結果可以提高雜湊表的效能。 實際上,由 Object 類定義的 hashCode 方法確實會針對不同的對象返回不同的整數。

 

向hashset裡添加了一個可變對象後時,要注意:如果後面的程式修改了這個可變對象的執行個體變數時,可能會導致他與集合裡的其他元素相同,即兩個對象equals返回true,hashcode也相同。導致hashSet不能正確操作那些元素。

補充瞭解下,可變對象:建立後,對象的屬性值可能會變,也就是說,建立後對象的hash值可能會改變。

舉例:對象MutableKey的鍵在建立時變數 i=10 j=20,雜湊值是1291。然後我們改變執行個體的變數值,該對象的鍵 i 和 j 從10和20分別改變成30和40。現在Key的雜湊值已經變成1931。顯然,這個對象的鍵在建立後發生了改變。所以類MutableKey是可變的。

下面代碼是hashset裡添加了一個可變對象例子,

可看出,hashset已經添加了幾個成員後,修改一個成員的執行個體變數,會得到裡面有相同的成員,因此是不對的。

 

但是,對最後一行,不能準確訪問成員這個。有點疑問,待解決。

package Test01;import java.util.HashSet;import java.util.Iterator;class mutClass{    public int count;    public  mutClass(int count) {        this.count =count;    }    public  boolean equals(Object obj) {        if(this == obj) {            return true;        }        if(obj != null && obj.getClass() == mutClass.class) {            mutClass m =(mutClass) obj;            return this.count == m.count;        }        return false;    }    public  int hashcode() {        return this.count;    }    public String toString() {        return "試試mutClass[count=" + count + "]";    }    }public class TestHashSet {   @SuppressWarnings("unchecked")public static void main(String[] args){       HashSet testHashSet =new HashSet();              mutClass a = new mutClass(3);       mutClass b = new mutClass(1);       mutClass c = new mutClass(-9);       mutClass d = new mutClass(9);       testHashSet.add(a);       testHashSet.add(b);       testHashSet.add(c);       testHashSet.add(d);        System.out.println("第一次"+testHashSet);        Iterator iterator =testHashSet.iterator();       mutClass first = (mutClass) iterator.next();       first.count=9;      /* testHashSet.remove(new mutClass(3));       testHashSet.remove(b);    //與上一行的區別*/       System.out.println("第二次"+testHashSet);        System.out.println(new mutClass(-9) == new mutClass(-9));       System.out.println("第四次"+testHashSet.contains(new mutClass(-9)));    }}

 hashset不能保證新增成員的順序,和自己的順序是一樣的,但是引入了一個LinkedHashSet子類,使得它能和hashset一樣,靠hashcode 找到他的儲存位置,又能維護新增成員的順序,內部靠一個鏈表實現,迭代訪問集合時有很好的效能。

Java集合(上)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.