欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java集合定義與用法實例總結(jié)【Set、List與Map】

 更新時間:2018年08月27日 10:24:25   作者:喜歡特別冷的冬天下著雪  
這篇文章主要介紹了Java集合定義與用法,結(jié)合實例形式總結(jié)分析了Java集合中Set、List和Map相關(guān)概念、功能、用法及操作注意事項,需要的朋友可以參考下

本文實例講述了Java集合定義與用法。分享給大家供大家參考,具體如下:

java集合大體可分為三類,分別是Set、List和Map,它們都繼承了基類接口Collection,Collection接口定義了眾多操作集合的基本方法,如下:

為了訪問Collection集合,不得不去了解Iterator接口。該接口很簡單,主要用于定義訪問集合的方法,如下:

所以上述的三大類子集合必定都繼承了上面2個接口。其中Set集合要求元素不重復,且內(nèi)部無序,所以訪問時只能根據(jù)元素值來訪問;List內(nèi)部為動態(tài)數(shù)組,支持有序,元素也可重復,所以往往有index;Map所代表的集合是具有Key-Value的映射關(guān)系的集合,如哈希表。

1. Set

1.1 Set不可添加相同元素

import java.util.Collection;
import java.util.HashSet;
public class TestSet {
  @SuppressWarnings({ "rawtypes", "unchecked" })
  public static void main(String[] args) {
    Collection c1 = new HashSet();
    Person p = new Person();
    c1.add(p);
    c1.add(p);
    System.out.println(c1);
    Collection c2 = new HashSet();
    String str1 = new String("123");
    String str2 = new String("123");
    c2.add(str1);
    c2.add(str2);
    System.out.println(c2);
  }
}
class Person {
  public Person() {
  }
  public Person(String name) {
    this.name = name;
  }
  public String name;
}

運行輸出:

[demo.Person@1db9742]
[123]

第一次添加了倆次p對象,集合不會重復添加,所以輸出了[Person@1db9742],這很合理。但是第二次明明new了兩個字符串,str1和str2的引用肯定是不同的,那為什么程序還是會認為是相同的元素呢。查找add(E e)的源碼,找到了其中的關(guān)鍵部分,如下

public boolean add(E e) {
  return map.put(e, PRESENT)==null;
 }
 public V put(K key, V value) {
  if (key == null)
   return putForNullKey(value);
  int hash = hash(key.hashCode());
  int i = indexFor(hash, table.length);
  for (Entry<K,V> e = table[i]; e != null; e = e.next) {
   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++;
  addEntry(hash, key, value, i);
  return null;
 }

這一句

if (e.hash == hash && ((k = e.key) == key || key.equals(k)))

表明,當兩個對象的哈希值相等并且對象的equals方法返回真時,則認為兩個對象是相同的,并不會進行后面的addEntry操作,即不會添加至集合。

這也就難怪String str1=new String("123")String str2=new String("123");被認為是同一個對象了,因為String在做equals的時候恰好很特殊,只要值相等,則euqals就返回真。

為了測試源碼是否真的是這么執(zhí)行的,改寫程序如下:

import java.util.Collection;
import java.util.HashSet;
public class TestSet {
  @SuppressWarnings({ "rawtypes", "unchecked" })
  public static void main(String[] args) {
    Collection c1 = new HashSet();
    c1.add(new A());
    c1.add(new A());
    c1.add(new B());
    c1.add(new B());
    c1.add(new C());
    c1.add(new C());
    System.out.println(c1);
  }
}
class A {
  @Override
  public boolean equals(Object obj) {
    return true;
  }
  @Override
  public int hashCode() {
    return 1;
  }
}
class B {
  @Override
  public int hashCode() {
    return 1;
  }
}
class C {
  @Override
  public boolean equals(Object obj) {
    return true;
  }
}

輸出:

[demo.A@1, demo.B@1, demo.B@1, demo.C@1db9742, demo.C@106d69c]

可以看到,B和C的對象都沒有被集合認為是同一個對象,而A類中重寫的哈希值和equals永遠相等,導致A類new出的匿名對象也是相等的,故只添加了一個。

1.2 Set不可修改元素的值

import java.util.Collection;
import java.util.Iterator;
import java.util.HashSet;
public class TestSet {
  @SuppressWarnings({ "rawtypes", "unchecked" })
  public static void main(String[] args) {
    Collection coll = new HashSet();
    coll.add(new Person("f"));
    coll.add(new Person("l"));
    coll.add(new Person("y"));
    System.out.println(coll);// a
    Iterator it = coll.iterator();// b
    while (it.hasNext()) {
      Person p = (Person) it.next();
      if (p.name.equals("f")) {
        p = new Person();// c
      }
    }
    Iterator it1 = coll.iterator();// d
    while (it1.hasNext()) {
      Person p = (Person) it1.next();
      System.out.println(p.name);
    }
    System.out.println(coll);
  }
}
class Person {
  public Person() {
  }
  public Person(String name) {
    this.name = name;
  }
  public String name;
}

運行輸出:

[demo.Person@52e922, demo.Person@1db9742, demo.Person@106d69c]
y
f
l
[demo.Person@52e922, demo.Person@1db9742, demo.Person@106d69c]

代碼輸出表明,HashSet集合的元素并不是有序的,另外在代碼c處取出了元素后,為該元素重新賦值,而后輸出發(fā)現(xiàn)集合并沒有改變,這說明iterator迭代器在提供next的方法里應該是類似于copy的技術(shù),目的就是防止在遍歷set集合的時候元素被改變。

2. List

List作為Collection的子接口,自然可以調(diào)用父接口的基本方法,但由于List集合元素是有序的,所以List接口在父接口的基礎(chǔ)上又增加了些方法。這些方法的作用與類父接口類似,只是都會增加一個index參數(shù)做為索引。

List中最常用的就是ArrayList,它在Vector的基礎(chǔ)上做了許多改進,下面代碼將展示List的基本操作用法:

import java.util.List;
import java.util.ArrayList;
import java.util.ListIterator;
public class TestList {
  @SuppressWarnings({ "rawtypes", "unchecked" })
  public static void main(String[] args) {
    // 向list中添加不同類型的元素,會自動裝箱
    List list = new ArrayList();
    list.add(1);
    list.add("123");
    list.add(3.14f);
    // 列表元素:[1, 123, 3.14]
    System.out.println("列表元素:" + list);
    // 清除列表
    list.clear();
    list.add("我");
    list.add("們");
    list.add("交");
    list.add("個");
    list.add("朋");
    list.add("友");
    list.add("吧");
    // 列表元素:[我, 們, 交, 個, 朋, 友, 吧]
    System.out.println("列表元素:" + list);
    List sub1 = list.subList(0, list.size() / 2);
    // 子列表元素:[我, 們, 交]
    System.out.println("子列表元素:" + sub1);
    // 從list中刪除sub
    sub1.removeAll(list);
    // 列表元素:[個, 朋, 友, 吧]
    System.out.println("列表元素:" + list);
    // 添加至頭
    List sub2 = new ArrayList();
    sub2.add("我");
    sub2.add("們");
    sub2.add("交");
    System.out.println("子列表元素:" + sub2);
    // 在list中添加sub2
    list.addAll(0, sub2);
    System.out.println("列表元素:" + list);
    // 遍歷操作
    ListIterator iter = list.listIterator();
    System.out.println("--正向遍歷--");
    while (iter.hasNext()) {
      System.out.println(iter.next());
    }
    System.out.println("--反向遍歷--");
    while (iter.hasPrevious()) {
      System.out.println(iter.previous());
    }
  }
}

運行輸出:

列表元素:[1, 123, 3.14]
列表元素:[我, 們, 交, 個, 朋, 友, 吧]
子列表元素:[我, 們, 交]
列表元素:[個, 朋, 友, 吧]
子列表元素:[我, 們, 交]
列表元素:[我, 們, 交, 個, 朋, 友, 吧]
--正向遍歷--







--反向遍歷--






List就像是一個動態(tài)且元素類型可不一的數(shù)組,它不僅具有iterator迭代器,而且還有l(wèi)istIterator,后者就像數(shù)組一樣,支持正向和反向遍歷。

3. Map

Map是具有映射關(guān)系的集合,key做為主鍵,可以索引到唯一的value,key和value都可以是對象。如果單獨取出Map里的所有值的話,Map看起來就像是Set,而又由于它較之Set又具有索引功能,所以又似乎有些List的影子。實際上,Map的key必須實現(xiàn)equals和hashCode方法,這也就解釋了為什么可以將一個對象的引用做為key了(實際上是計算這個對象的hashCode做為主鍵),因此不能將同一個對象的引用存入某一個Map中。HashSet實現(xiàn)了Set接口,ArrayList實現(xiàn)了List接口,那么單從命名上就能得知,HashMap肯定實現(xiàn)了Map接口,Map接口的功能如下,

在HashSet和ArrayList都有一個訪問迭代器的方法iterator(),在Set接口中卻沒有,畢竟Set是key-value組合,取而代之的是一個keySet()方法,用以返回一個實現(xiàn)了Set接口的對象,從而又可以進行iterator的操作。

基本操作如下:

import java.util.HashMap;
import java.util.Iterator;
public class TestMap {
  @SuppressWarnings({ "rawtypes", "unchecked" })
  public static void main(String[] args) {
    HashMap hash = new HashMap();
    hash.put("1", "我");
    hash.put("2", "們");
    // 主鍵可為null,但只能有一個null值的主鍵
    hash.put(null, null);
    // 值可以為null,可以有很多個值為null
    hash.put("3", null);
    hash.put("4", null);
    System.out.println("直接遍歷:" + hash);
    System.out.println("----keySey遍歷----:");
    for (Object key : hash.keySet()) {
      System.out.println("key:" + key + " value:" + hash.get(key));
    }
    System.out.println("----iterator遍歷----:");
    Iterator iter = hash.keySet().iterator();
    while (iter.hasNext()) {
      String key = (String) iter.next();
      System.out.println("key:" + key + " value:" + hash.get(key));
    }
  }
}

輸出:

直接遍歷:{null=null, 1=我, 2=們, 3=null, 4=null}
----keySey遍歷----:
key:null value:null
key:1 value:我
key:2 value:們
key:3 value:null
key:4 value:null
----iterator遍歷----:
key:null value:null
key:1 value:我
key:2 value:們
key:3 value:null
key:4 value:null

HashMap可以有空key,但是只能有一個,,這符合唯一主鍵的原則,并且若主鍵重復了,則會覆蓋之前的相同主鍵。而值卻沒有限制,有多少個null都可以。此外,在使用HashMap的時候還需要注意下面兩點:

1.HashMap是非線程安全的,而Hashtable是線程安全的。

對于各種集合的各種操作,其實可以依賴于Collections類,該類提供了許多靜態(tài)操作集合的方法,其中就可以將一個普通集合封裝為線程安全的集合,如下

Collection c=Collections.synchronized(new ArrayList());

2.了解HashMap的性能

HashMap利用每一個key的哈希值,去為value找尋存儲位置。這個存儲位置往往被稱為“桶”,當哈希值唯一時,那么一個桶中就只有一個對象,這時情況最理想,然而若非正常情況下(比如重寫hashCode強制返回相等),那么一個桶能就有放多個對象,這時性能最差。

上面說道,HashMap與Set、List在某方面都很相似,做為一個強大的集合,它的內(nèi)部自然也有會動態(tài)開辟內(nèi)存的操作。所有就有了下面幾個參數(shù),

  • capacity(容量):在初始化HashMap時將會有一個默認值(好象是10吧),隨著集合的大小也會自身調(diào)整。
  • size(元素個數(shù)):有多少個元素size就是多少。
  • load factor(負載因子):load factor=size/capacity,取值0~1。

當負載因子很大時,如有90個元素,而集合的容量為100,因子就是0.9,這樣情況非常不利于查詢操作,因為put和get操作會遍歷大量的元素,時間復雜度無形就會增加,但在內(nèi)存開銷上確實是比較節(jié)省的,因為集合不會反復的創(chuàng)建,因為每一次擴充集合的操作,就意味著要將原始元素重新插入到新的集合中去,性能開銷是很大的。

而當負載因子很小時,查詢效率將會非常高(因為遍歷少),但是卻在內(nèi)部進行了許多次開辟內(nèi)存的操作。

因此,在系統(tǒng)中,要根據(jù)實際需求正確把握HashMap的用法,如一開始建立集合的時候就知道這個集合非常大,那么就有必要在初始化的時候就指明capacity,不應該使用默認值,這樣效率能高點;相反只有少量集合元素時,不應該在創(chuàng)建的時候指定很大的capacity,這明顯是在浪費內(nèi)存。

更多關(guān)于java算法相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Java數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Java操作DOM節(jié)點技巧總結(jié)》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總

希望本文所述對大家java程序設(shè)計有所幫助。

相關(guān)文章

  • SpringMVC之簡單的增刪改查示例(SSM整合)

    SpringMVC之簡單的增刪改查示例(SSM整合)

    本篇文章主要介紹了SpringMVC之簡單的增刪改查示例(SSM整合),這個例子是基于SpringMVC+Spring+Mybatis實現(xiàn)的。有興趣的可以了解一下。
    2017-03-03
  • jmeter中beanshell的用法小結(jié)

    jmeter中beanshell的用法小結(jié)

    本文主要介紹了jmeter中beanshell的用法小結(jié),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-05-05
  • spring依賴注入知識點分享

    spring依賴注入知識點分享

    在本篇文章里小編給大家整理的是關(guān)于spring依賴注入知識點以及相關(guān)代碼內(nèi)容,需要的朋友們學習下。
    2019-11-11
  • SpringSecurity 測試實戰(zhàn)

    SpringSecurity 測試實戰(zhàn)

    這篇文章主要介紹了SpringSecurity 測試實戰(zhàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-11-11
  • ElasticSearch 動態(tài)映射實戰(zhàn)詳解

    ElasticSearch 動態(tài)映射實戰(zhàn)詳解

    這篇文章主要為大家介紹了ElasticSearch 動態(tài)映射實戰(zhàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • spring boot教程之全局處理異常封裝

    spring boot教程之全局處理異常封裝

    這篇文章主要給大家介紹了關(guān)于spring boot教程之全局處理異常封裝的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用spring boot具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-09-09
  • 如何自定義hibernate validation注解示例代碼

    如何自定義hibernate validation注解示例代碼

    Hibernate Validator 是 Bean Validation 的參考實現(xiàn) . Hibernate Validator 提供了 JSR 303 規(guī)范中所有內(nèi)置 constraint 的實現(xiàn),下面這篇文章主要給大家介紹了關(guān)于如何自定義hibernate validation注解的相關(guān)資料,需要的朋友可以參考下
    2018-04-04
  • Java/Spring項目的包開頭為什么是com詳解

    Java/Spring項目的包開頭為什么是com詳解

    這篇文章主要介紹了Java/Spring項目的包開頭為什么是com的相關(guān)資料,在Java中包命名遵循域名反轉(zhuǎn)規(guī)則,即使用公司的域名反轉(zhuǎn)作為包的前綴,以確保其全球唯一性和避免命名沖突,這種規(guī)則有助于邏輯分層、代碼可讀性提升和標識代碼來源,需要的朋友可以參考下
    2024-10-10
  • 學生視角帶你了解Java內(nèi)部類

    學生視角帶你了解Java內(nèi)部類

    說起內(nèi)部類這個詞,想必很多人都不陌生,但是又會覺得不熟悉。原因是平時編寫代碼時可能用到的場景不多,用得最多的是在有事件監(jiān)聽的情況下,并且即使用到也很少去總結(jié)內(nèi)部類的用法。今天我們就來一探究竟
    2022-03-03
  • Java實現(xiàn)辦公文檔在線預覽功能

    Java實現(xiàn)辦公文檔在線預覽功能

    java實現(xiàn)辦公文件在線預覽功能是一個大家在工作中也許會遇到的需求,這篇文章就教大家如何實現(xiàn)這一功能,感興趣的小伙伴可以了解一下
    2021-12-12

最新評論