Java 容器在實際項目中的應用


前言:在java開發中我們離不開集合數組等,在java中有個專有名詞:“容器” ,下面會結合Thinking in Java的知識和實際開發中業務場景講述一下容器在Web項目中的用法。可結合圖片代碼了解Java中的容器

 備注 :這個地方 ,參考於朝向遠方的博客Java容器詳解 ,既然前人總結的這么好,我就直接拿來用,在這里更注重在實際開發中的例子,感謝那些總結的前輩們,辛苦了。

簡單的數組例子

  Thinking in Java 中並沒有把數組歸為Java的容器,實際上數組的確不是Java獨有的c++ ,c都有數組。但是,在web開發時我還是把數組歸類到容器中,因為他們說白了都是在做相同的事情

另外還有一個細節點就是:我翻遍了我開發過的項目,但是很驚訝的發現,這么多項目里直接用數組存儲對象極為少見。想想也是,java是面向對象的,而數組對java總歸是有點偏底層。

珍惜這來之不易的demo吧: 

public Map<String, String> getDimValue() {
if (this.dimValue != null)
return dimValue;
this.dimValue = new HashMap<String, String>();
if (this.dim != null && this.dim.length() != 0) {
String[] strDims = this.dim.split(",");//可以用截取的方式,得到String[]
for (String s : strDims) {
String[] dims = s.split("\\:");
this.dimValue.put(dims[0], dims[1]);//數組訪問通過下標,但是注意 最多到array[array.length-1],越界直接拋出異常,和c++不一樣
}
}
return this.dimValue;
}

 數組(array)是最常見的數據結構。數組是相同類型元素的有序集合,並有固定的大小(可容納固定數目的元素)。數組可以根據下標(index)來隨機存取(random access)元素。在內存中,數組通常是一段連續的存儲單元。

 Java支持數組這一數據結構。我們需要說明每個數組的類型和大小,java利用byte[] 可以表示blob字段,存放圖片,xml,json等。String[]則可以用來存一些字符串,id, code等。 

//web項目中倒是常用 byte[]來存放blob字段等
@Type(type = "org.springframework.orm.hibernate3.support.BlobByteArrayType")
private byte[] globals;

   在說明類型時,在類型說明(String)后面增加一個[],來說明是一個數組。使用new創建容器時,需要說明數組的大小;或者是 直接 int a = {1,2,3} 這樣直接用{}同時初始化。  

數組可以通過遍歷的形式轉為其他容器類型,但是其他類型可以通過 toArray()快速轉為數組(下文中會說到Arrays這個工具類可以把數組轉為List)

第一個分支:Collection

    在開發中,Collection最常用的就是兩個類: Set和List。因為同屬於一個Collection下,相互轉化方便,調用的方法也類似。(collection Api

 Java中常用方法接口:

* boolean add(Object obj): 添加對象,集合發生變化則返回true
* Iterator iterator():返回Iterator接口的對象
* int size()
* boolean isEmpty()
* boolean contains(Object obj)
* void clear()
* <T> T[] toArray(T[] a)

 上述接口參照於:wishyouhappy的博客:java容器總結

1:List集合

   具體可以查看list中文文檔,文檔中清楚的描述到List<E>是一個實現了 Collection的接口,而我們可以直接用List 聲明對象(接口可以直接聲明一個對象)。容器的引用為List類型,但容器的實現為ArrayList類。這里是將接口與實現類分離。事實上,同一種抽象數據結構(ADT)都可以有多種實施方法(比如棧可以實施為數組和鏈表)。這樣的分離允許我們更自由的選擇ADT的實施方式(參考於Java容器詳解)

  java中較為常用的 ArrayList,LinkedList, 集合中的元素可以相等,是有順序的 

 1 public class Test {
2 public static void main(String[] args) {
3 List<String> list = new ArrayList<String>();
4 //添加單個元素
5 for(String s1:"hehe wo shi lao da".split(" ")){
6 list.add(s1);
7 }
8 //添加多個元素
9 list.addAll(Arrays.asList("nan dao ni bu xin?".split(" ")));//Arrays是一個工具類,可以幫助我們少些遍歷代碼
10 System.out.println(list.toString());//list重寫了toString方法,輸出list中每一個元素
11 //修改位置為i的元素
12 for(int i = 0; i<list.size();i++){
13 list.set(i, "u");
14 }
15 System.out.println(list.toString());
16 list.removeAll(Arrays.asList(new String[]{"u"}));//這個地方為了測試 我初始化了一個字符數組 new String[]{"u"}
17 System.out.println(list.toString());18
19 }
20 }

 

 上邊的代碼只是為了說明 list的主要用途,實際上開發中可能用不到這么多,比較常用的也就 

  • add()方法加入新的元素
  • get()方法可以獲取容器中的元素,傳遞一個整數下標作為參數
  • remove()方法可以刪除容器中的元素,傳遞一個整數下標作為參數。(有另一個remove(),傳遞元素自身作為參數)
  • size()方法用來返回容器中元素的總數。
  • toString() 多用於調試代碼是,查看list中的內容
  • addAll() 添加一個相同類型的list

List中 還有一個實習類 LinkedList 比較常用,它可以用來做隊列 的實現,也可以變相完成棧的工作。

主要方法有:

  •   get(int index):返回此列表中指定位置處的元素。
  •     getFirst():返回此列表的第一個元素。
  •     getLast():返回此列表的最后一個元素。
  •     indexOf(Object o):返回此列表中首次出現的指定元素的索引,如果此列表中不包含該元素,則返回 -1。
  •     lastIndexOf(Object o):返回此列表中最后出現的指定元素的索引,如果此列表中不包含該元素,則返回 -1。
  •  remove():獲取並移除此列表的頭(第一個元素)
  •  removeFirst():移除並返回此列表的第一個元素
  •  removeLast():移除並返回此列表的最后一個元素

ListedList采用的是鏈式存儲。鏈式存儲就會定一個節點Node。包括三部分前驅節點、后繼節點以及data值。所以存儲存儲的時候他的物理地址不一定是連續的

具體內容可參照java提高篇(二二)---LinkedList   下面列出了linkedList的部分源碼(不建議一開始就看)

View Code

 2:Set集合

集合(set)也是元素的集合。集合中不允許有等值的元素,集合的元素沒有順序:

我們用Set多數時候是利用它的特性,沒有重復的元素,例如:

2.1 HashSet:HashSet查詢速度比較快,但是存儲的元素是隨機的並沒有排序 

public class Test
{
public static void main(String[] args)
{
Set<Integer> s1 = new HashSet<Integer>();
s1.add(4);
s1.add(5);
s1.add(4);
s1.remove(5);
System.out.println(s1);
System.out.println(s1.size());
}
}

我們可以用它去過濾重復數據,Set 可以輕松的轉為List,因為構造方法傳入參數是Collection<? extends E> c   

1 Set<String> set = new HashSet<String>();
2 set.add("h");
3 set.add("h");
4 List<String> fromSets = new ArrayList<String>(set);
5 System.out.println(fromSets.toString());
6 Set<String> s1 = new HashSet<String>(fromSets);
7 System.out.println(s1.toString());

 這個地方,非常有意思的是,HashSet中竟然持有的是HashMap,利用HashMap存取數據

   public HashSet(Collection<? extends E> c) {
map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}

  HashSet只有add方法,沒有get方法(這和list稍微不同)。但是HashSet 實現了Iterator<Eiterator()。可以通過Iterator遍歷,具體可以查看Set中文文檔

2.2:TreeSet

TreeSet是將元素存儲紅-黑樹結構中,所以存儲的結果是有順序的

public static void main(String[] args){
Random random=new Random(47);
Set<Integer> intset=new TreeSet<Integer>();
for (int i=0;i<10000;i++){
intset.add(random.nextInt(30));
}
System.out.print(intset);
}

3:collection中的Iterator

Iterator的官方文檔,一般Set想要取元素只能通過迭代器,而list也可以用迭代器(一般都是用get)

public class Test
{
public static void main(String[] args)
{
List<Integer> l1 = new ArrayList<Integer>();
l1.add(4);
l1.add(5);
l1.add(2);
Iterator i = l1.iterator();
while(i.hasNext()) {
System.out.println(i.next());
}
}
}

 Collection可以用foreach,因為其實現了Iterator接口

public class IteratorClass {
public Iterator<String> iterator(){
return new Itr();
}
private class Itr implements Iterator<String>{
protected String[] words=("Hello Java").split(" ");
private int index=0;
public boolean hasNext() {
return index<words.length;
}
public String next() {
return words[index++];
}
public void remove() {
}
}
}

 

foreach循環最終也會轉化為Iterator遍歷 (Iterator it=iterator;iterators.hasNext();)

Iterator iterators=new IteratorClass().iterator();
for (Iterator it=iterator;iterators.hasNext();) {
System.out.println(iterators.next());
}
while (iterators.hasNext()){
System.out.println(iterators.next());
}

下面說一下Java中極容易出錯的點:

  for 循環查找集合中某個元素並刪除:極容易出現java.util.ConcurrentModificationException 

List<String> list = new ArrayList<String>();
list.addAll(Arrays.asList("nan dao ni bu xin?".split(" ")));
for(String st:list){
System.out.println(st);
if(st.equals("ni")){
list.remove(st);
}
}

 解決方式是將數組轉化為Iterator,然后利用it.remove();刪除數組中的元素

 public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("a");
list.add("bb");
list.add("a22");
Iterator<String> it=list.iterator();
//去除數組中"a"的元素
while(it.hasNext()){
String st=it.next();
if(st.equals("a")){
it.remove();
}
}
}

 第二個分支:Map

    在web項目中,Map是非常常用的,當然在很多時候,Map會被一些包裝類給替代掉(這實際上是敏捷開發中提到用vo替換map).但是Map還是無法阻擋的容器一哥。

 Java中常用的方法接口

* Object get(Object key)
* Object put(Object key, Object value)
* Set keySet() : returns the keys set Set<K> keySet()
* Set entrySet(): returns mappings set Set<Map.Entry<K,V>> entrySet()
* containsKey()
* containsValue()

   Map是鍵值對的集合。Map中的每個元素是一個鍵值對,即一個鍵(key)和它對應的對象值(value)。對於Map容器,我們可以通過鍵來找到對應的對象。

哈希表是Map常見的一種實現方式,也是實際開發中用的最廣泛的 (HashMap),想要具體了解HashMap的原理,可以參考 hashmap實現原理淺析

public class Test
{
public static void main(String[] args)
{
Map<String, Integer> m1 = new HashMap<String, Integer>();
m1.put("Vamei", 12);
m1.put("Jerry", 5);
m1.put("Tom", 18);
System.out.println(m1.get("Vamei"));
}
}

 在Map中,我們使用put()方法來添加元素,用get()方法來獲得元素。  

Map還提供了下面的方法,來返回一個Collection:

  • keySet()  將所有的鍵轉換為Set
  • values()  將所有的值轉換為List
  • containsKey驗證主要是否存在、containsValue驗證值是否存在
  • entrySet獲取鍵值對。 

 總結:

    java中有一些工具類來幫助我們處理容器相關的內容。比如Arrays,java中的一些類都有用到這些工具類

ArrayList源碼中的clone方法 

   /**
* Returns a shallow copy of this <tt>ArrayList</tt> instance. (The
* elements themselves are not copied.)
*
* @return a clone of this <tt>ArrayList</tt> instance
*/
public Object clone() {
try {
ArrayList<E> v = (ArrayList<E>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}

 ArrayList源碼中的 toArray()方法

  public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}

 如果你對Arrays這個工具類有興趣,可以看一下源碼,它最終調用到了本地方法(折疊起來,是不希望給讀者帶來困惑)

View Code

Arrays的一些其他方法:

  •  sort():  對傳入的集合排序 (具體算法可以參考Java Arrays.sort源代碼解析
  •  aslist(): 把數組轉為List
  •  binarySearch():二分查找數組
  •  deepToString():把二維數組轉為String
  •  fill():快速填充數組

再比如Collections:

  可以參考thinking in java之Collections工具類的使用

View Code

   max():取集合的最大元素

  subList():截取list

  addAll():添加集合

 有興趣的可以去看一下源碼,我覺得非常有幫助

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com