導讀:祖傳挖墳派學習方法(寶兒姐友情支持)
第一部分 List簡介
第二部分 何為ArrayList
第三部分 代碼示例
第四部分 吹牛
如果你急需想搞清楚一些問題可以先看這里的總結 再后續看文章
(1)ArrayList是線程不安全的
(2)對ArrayList里面對象的使用方法 在第三部分代碼示例中 越有可能在開發中用到的方法 比如List轉換MAP 都比較靠后
第一部分 List簡介
如果你有參閱過 JDK 1.8 API中對於LIST的描述那么 你一定在文中有看到過這句話 This interface is a member of the Java Collections Framework.(此接口是Java集合框架的成員。)
這句話為我們帶來了兩個提示 首先List是一個接口 其次list是collection接口的子接口,collection是集合的父類型接口 ,定義了所有集合的通用方法 。 翻閱api 我找到了關於list繼承關系的結構介紹
觀察繼承關系 得出如下結論:
一 : E是泛型 意味着 list<E>該方法在調用時可以接收不同類型的參數。可以根據傳遞給泛型方法的參數類型 .
二: List的父類有兩個 第一個是collection 第二個是Iterable collection通過上面鋪墊我們有所了解 。 Iterable(迭代器)我這里簡短的描述下(是提供一種方法對一個容器對象中的各個元素進行訪問,而又不暴露該對象容器的內部細節。)
三:(所有已知的實現類)這里我們看到了 許多但是今天要講的重點在ArrayList這個實現類上 (list是個接口 如果你要new必須要有個實現類)
將上面一二點 匯聚成一段Java代碼:
public interface List<E> extends Collection<E>
這段代碼位於java.util.List.java類中 是包含所有List調用的方法
目前已知情報匯總:
(一):List是一個接口,而ArrayList是List接口的一個實現類。
(二):ArrayList類繼承並實現了List接口。
(三):List接口不能被構造,也就是我們說的不能創建實例對象,但是我們可以為List接口創建一個指向自己的對象引用,而ArrayList實現類的實例對象就在這充當了這個指向List接口的對象引用。
所以現在我應該要來弄清楚實現List接口的對象 "ArrayList"
第二部分:何為ArrayList
翻閱 JDK api 我找到了關於ArrayList繼承關系的結構
觀察繼承關系 得出如下結論:
(一):ArrayList 繼承了AbstractList,實現了List。它是一個數組隊列,提供了相關的添加、刪除、修改、遍歷等功能。
(二):ArrayList 實現了RandmoAccess接口,即提供了隨機訪問功能。RandmoAccess是java中用來被List實現,為List提供快速訪問功能的。在ArrayList中,我們即可以通過元素的序號快速獲取元素對象;這就是快速隨機訪問。稍后,我們會比較List的“快速隨機訪問”和“通過Iterator迭代器訪問”的效率。
(三):ArrayList 實現了Cloneable接口,即覆蓋了函數clone(),能被克隆。
(四):ArrayList 實現java.io.Serializable接口,這意味着ArrayList支持序列化,能通過序列化去傳輸。
繼續看下去 JDK API中開頭有一段對ArrayList的描述
翻譯:
列表接口的可調整大小的數組實現。實現所有可選的列表操作,並允許所有元素,包括空元素。除了實現列表接口之外,這個類還提供了一些方法來操作內部用於存儲列表的數組的大小。(這個類大致相當於vector,只是它不同步。) 這里的不同步指的是線程不同步和Vector不同,ArrayList中的操作不是線程安全的!所以,建議在單線程中才使用ArrayList,而在多線程中可以選擇Vector或者CopyOnWriteArrayList。 關於list線程不同步的測試代碼 地址:https://www.cnblogs.com/WuXuanKun/p/5556999.html (感謝這位仁兄的博客)
對上面的小總結的一個匯合結論 :
ArrayList 是一個數組隊列,相當於 動態數組。與Java中的數組相比,它的容量能動態增長。它 提供了相關的添加、刪除、修改、遍歷等功能。它繼承於AbstractList,實現了List, RandomAccess, Cloneable, java.io.Serializable這些接口。 此外 ArrayList支持序列化,能通過序列化去傳輸. ArrayList中的操作不是線程安全的
第三部分 代碼示例
第一步在Java類里面創建List
List<String> list = new ArrayList<>();
我們調查一下這個new ArrayList 在java.util.ArrayList.java類中 我找到了這樣一段代碼,如下:
/** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
這便是我們new的真實的ArrayList了 通過注釋我們發現 我們new的 Arrayslist 其默認長度為10
繼續調查這個 elementData 還是在java.util.ArrayList.java類中 我找到了 關於elementData 的定義
/** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. */ transient Object[] elementData; // non-private to simplify nested class access
/** * Increases the capacity of this <tt>ArrayList</tt> instance, if * necessary, to ensure that it can hold at least the number of elements * specified by the minimum capacity argument. * * @param minCapacity the desired minimum capacity */ public void ensureCapacity(int minCapacity) { int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) // any size if not default element table ? 0 // larger than default for default empty table. It's already // supposed to be at default size. : DEFAULT_CAPACITY; if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } }
是不是有種恍然大悟的感jio 原來ArrayList的老祖宗是一個Object的數組而觀察DEFAULTCAPACITY_EMPTY_ELEMENTDATA進行的操作我們發現它為上面的Object數組 提供了進行動態操作的能力 這樣從JDK源碼中,我們驗證了我們上面在第二部分的總結里面說到 ArrayLis其實是一個動態數組.
總結:ArrayList底層其實就是一個Object類型的動態數組,並且通過注釋也可以得知,我們在進行new操作時其初始化的長度為10。
說了這么多我們來看看list 能使用ArrayList進行那些操作(以往博客的重頭戲來了)先看看他為我們提供了那些方法
所下示例代碼均來自 博客園仁兄 “西城墨客” 所屬博客 地址:https://www.cnblogs.com/epeter/p/5648026.html
目錄
- list中添加,獲取,刪除元素;
- list中是否包含某個元素;
- list中根據索引將元素數值改變(替換);
- list中查看(判斷)元素的索引;
- 根據元素索引位置進行的判斷;
- 利用list中索引位置重新生成一個新的list(截取集合);
- 對比兩個list中的所有元素;
- 判斷list是否為空;
- 返回Iterator集合對象;
- 將集合轉換為字符串;
- 將集合轉換為數組;
- 集合類型轉換;
- 去重復;
- List轉換MAP
- List分組
- List 遍歷
1.list中添加,獲取,刪除元素;
添加方法是:.add(e); 獲取方法是:.get(index); 刪除方法是:.remove(index); 按照索引刪除; .remove(Object o); 按照元素內容刪除;

List<String> person=new ArrayList<>(); person.add("jackie"); //索引為0 //.add(e) person.add("peter"); //索引為1 person.add("annie"); //索引為2 person.add("martin"); //索引為3 person.add("marry"); //索引為4 person.remove(3); //.remove(index) person.remove("marry"); //.remove(Object o) String per=""; per=person.get(1); System.out.println(per); ////.get(index) for (int i = 0; i < person.size(); i++) { System.out.println(person.get(i)); //.get(index) }
2.list中是否包含某個元素;
方法:.contains(Object o); 返回true或者false

List<String> fruits=new ArrayList<>(); fruits.add("蘋果"); fruits.add("香蕉"); fruits.add("桃子"); //for循環遍歷list for (int i = 0; i < fruits.size(); i++) { System.out.println(fruits.get(i)); } String appleString="蘋果"; //true or false System.out.println("fruits中是否包含蘋果:"+fruits.contains(appleString)); if (fruits.contains(appleString)) { System.out.println("我喜歡吃蘋果"); }else { System.out.println("我不開心"); }
3.list中根據索引將元素數值改變(替換);
注意 .set(index, element); 和 .add(index, element); 的不同;

String a="白龍馬", b="沙和尚", c="八戒", d="唐僧", e="悟空"; List<String> people=new ArrayList<>(); people.add(a); people.add(b); people.add(c); people.set(0, d); //.set(index, element); //將d唐僧放到list中索引為0的位置,替換a白龍馬 people.add(1, e); //.add(index, element); //將e悟空放到list中索引為1的位置,原來位置的b沙和尚后移一位 //增強for循環遍歷list for(String str:people){ System.out.println(str); }
4.list中查看(判斷)元素的索引;
注意:.indexOf(); 和 lastIndexOf()的不同;

List<String> names=new ArrayList<>(); names.add("劉備"); //索引為0 names.add("關羽"); //索引為1 names.add("張飛"); //索引為2 names.add("劉備"); //索引為3 names.add("張飛"); //索引為4 System.out.println(names.indexOf("劉備")); System.out.println(names.lastIndexOf("劉備")); System.out.println(names.indexOf("張飛")); System.out.println(names.lastIndexOf("張飛"));
5.根據元素索引位置進行的判斷;

if (names.indexOf("劉備")==0) { System.out.println("劉備在這里"); }else if (names.lastIndexOf("劉備")==3) { System.out.println("劉備在那里"); }else { System.out.println("劉備到底在哪里?"); }
6.利用list中索引位置重新生成一個新的list(截取集合);
方法: .subList(fromIndex, toIndex); .size() ; 該方法得到list中的元素數的和

List<String> phone=new ArrayList<>(); phone.add("三星"); //索引為0 phone.add("蘋果"); //索引為1 phone.add("錘子"); //索引為2 phone.add("華為"); //索引為3 phone.add("小米"); //索引為4 //原list進行遍歷 for(String pho:phone){ System.out.println(pho); } //生成新list phone=phone.subList(1, 4); //.subList(fromIndex, toIndex) //利用索引1-4的對象重新生成一個list,但是不包含索引為4的元素,4-1=3 for (int i = 0; i < phone.size(); i++) { // phone.size() 該方法得到list中的元素數的和 System.out.println("新的list包含的元素是"+phone.get(i)); }
7.對比兩個list中的所有元素;
//兩個相等對象的equals方法一定為true, 但兩個hashcode相等的對象不一定是相等的對象

//1.<br>if (person.equals(fruits)) { System.out.println("兩個list中的所有元素相同"); }else { System.out.println("兩個list中的所有元素不一樣"); } //2. if (person.hashCode()==fruits.hashCode()) { System.out.println("我們相同"); }else { System.out.println("我們不一樣"); }
8.判斷list是否為空;
//空則返回true,非空則返回false

if (person.isEmpty()) { System.out.println("空的"); }else { System.out.println("不是空的"); }
9.返回Iterator集合對象;
System.out.println("返回Iterator集合對象:"+person.iterator());
1+0.將集合轉換為字符串;

String liString=""; liString=person.toString(); System.out.println("將集合轉換為字符串:"+liString);
11.將集合轉換為數組;

System.out.println("將集合轉換為數組:"+person.toArray());
12.集合類型轉換;

//1.默認類型 List<Object> listsStrings=new ArrayList<>(); for (int i = 0; i < person.size(); i++) { listsStrings.add(person.get(i)); } //2.指定類型 List<StringBuffer> lst=new ArrayList<>(); for(String string:person){ lst.add(StringBuffer(string)); }
13.去重復;

List<String> lst1=new ArrayList<>(); lst1.add("aa"); lst1.add("dd"); lst1.add("ss"); lst1.add("aa"); lst1.add("ss"); //方法 1. for (int i = 0; i <lst1.size()-1; i++) { for (int j = lst1.size()-1; j >i; j--) { if (lst1.get(j).equals(lst1.get(i))) { lst1.remove(j); } } } System.out.println(lst1); //方法 2. List<String> lst2=new ArrayList<>(); for (String s:lst1) { if (Collections.frequency(lst2, s)<1) { lst2.add(s); } } System.out.println(lst2);
完整代碼:

package MyTest01; import java.util.ArrayList; import java.util.List; public class ListTest01 { public static void main(String[] args) { //list中添加,獲取,刪除元素 List<String> person=new ArrayList<>(); person.add("jackie"); //索引為0 //.add(e) person.add("peter"); //索引為1 person.add("annie"); //索引為2 person.add("martin"); //索引為3 person.add("marry"); //索引為4 person.remove(3); //.remove(index) person.remove("marry"); //.remove(Object o) String per=""; per=person.get(1); System.out.println(per); ////.get(index) for (int i = 0; i < person.size(); i++) { System.out.println(person.get(i)); //.get(index) } //list總是否包含某個元素 List<String> fruits=new ArrayList<>(); fruits.add("蘋果"); fruits.add("香蕉"); fruits.add("桃子"); //for循環遍歷list for (int i = 0; i < fruits.size(); i++) { System.out.println(fruits.get(i)); } String appleString="蘋果"; //true or false System.out.println("fruits中是否包含蘋果:"+fruits.contains(appleString)); if (fruits.contains(appleString)) { System.out.println("我喜歡吃蘋果"); }else { System.out.println("我不開心"); } //list中根據索引將元素數值改變(替換) String a="白龍馬", b="沙和尚", c="八戒", d="唐僧", e="悟空"; List<String> people=new ArrayList<>(); people.add(a); people.add(b); people.add(c); people.set(0, d); //.set(index, element) //將d唐僧放到list中索引為0的位置,替換a白龍馬 people.add(1, e); //.add(index, element); //將e悟空放到list中索引為1的位置,原來位置的b沙和尚后移一位 //增強for循環遍歷list for(String str:people){ System.out.println(str); } //list中查看(判斷)元素的索引 List<String> names=new ArrayList<>(); names.add("劉備"); //索引為0 names.add("關羽"); //索引為1 names.add("張飛"); //索引為2 names.add("劉備"); //索引為3 names.add("張飛"); //索引為4 System.out.println(names.indexOf("劉備")); System.out.println(names.lastIndexOf("劉備")); System.out.println(names.indexOf("張飛")); System.out.println(names.lastIndexOf("張飛")); //根據元素索引位置進行的判斷 if (names.indexOf("劉備")==0) { System.out.println("劉備在這里"); }else if (names.lastIndexOf("劉備")==3) { System.out.println("劉備在那里"); }else { System.out.println("劉備到底在哪里?"); } //利用list中索引位置重新生成一個新的list(截取集合) List<String> phone=new ArrayList<>(); phone.add("三星"); //索引為0 phone.add("蘋果"); //索引為1 phone.add("錘子"); //索引為2 phone.add("華為"); //索引為3 phone.add("小米"); //索引為4 //原list進行遍歷 for(String pho:phone){ System.out.println(pho); } //生成新list phone=phone.subList(1, 4); //.subList(fromIndex, toIndex) //利用索引1-4的對象重新生成一個list,但是不包含索引為4的元素,4-1=3 for (int i = 0; i < phone.size(); i++) { // phone.size() 該方法得到list中的元素數的和 System.out.println("新的list包含的元素是"+phone.get(i)); } //對比兩個list中的所有元素 //兩個相等對象的equals方法一定為true, 但兩個hashcode相等的對象不一定是相等的對象 if (person.equals(fruits)) { System.out.println("兩個list中的所有元素相同"); }else { System.out.println("兩個list中的所有元素不一樣"); } if (person.hashCode()==fruits.hashCode()) { System.out.println("我們相同"); }else { System.out.println("我們不一樣"); } //判斷list是否為空 //空則返回true,非空則返回false if (person.isEmpty()) { System.out.println("空的"); }else { System.out.println("不是空的"); } //返回Iterator集合對象 System.out.println("返回Iterator集合對象:"+person.iterator()); //將集合轉換為字符串 String liString=""; liString=person.toString(); System.out.println("將集合轉換為字符串:"+liString); //將集合轉換為數組,默認類型 System.out.println("將集合轉換為數組:"+person.toArray()); ////將集合轉換為指定類型(友好的處理) //1.默認類型 List<Object> listsStrings=new ArrayList<>(); for (int i = 0; i < person.size(); i++) { listsStrings.add(person.get(i)); } //2.指定類型 List<StringBuffer> lst=new ArrayList<>(); for(String string:person){ lst.add(StringBuffer(string)); } } private static StringBuffer StringBuffer(String string) { return null; } }
14:List轉換Map (示例代碼來自:https://www.cnblogs.com/yangweiqiang/p/6934671.html) 感謝這位小火紙
隨便來個Java類 添加一個List 測試數據
List<Apple> appleList = new ArrayList<>();//存放apple對象集合 Apple apple1 = new Apple(1,"蘋果1",new BigDecimal("3.25"),10); Apple apple12 = new Apple(1,"蘋果2",new BigDecimal("1.35"),20); Apple apple2 = new Apple(2,"香蕉",new BigDecimal("2.89"),30); Apple apple3 = new Apple(3,"荔枝",new BigDecimal("9.99"),40); appleList.add(apple1); appleList.add(apple12); appleList.add(apple2); appleList.add(apple3);
id為key,apple對象為value,可以這么做:ps 此方法只適用於JDK1.8+
/** * List -> Map * 需要注意的是: * toMap 如果集合對象有重復的key,會報錯Duplicate key .... * apple1,apple12的id都為1。 * 可以用 (k1,k2)->k1 來設置,如果有重復的key,則保留key1,舍棄key2 */ Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1,k2)->k1));
15:List分組
List里面的對象元素,以某個屬性來分組,例如,以id分組,將id相同的放在一起:
//List 以ID分組 Map<Integer,List<Apple>> Map<Integer, List<Apple>> groupBy = appleList.stream().collect(Collectors.groupingBy(Apple::getId)); System.err.println("groupBy:"+groupBy); {1=[Apple{id=1, name='蘋果1', money=3.25, num=10}, Apple{id=1, name='蘋果2', money=1.35, num=20}], 2=[Apple{id=2, name='香蕉', money=2.89, num=30}], 3=[Apple{id=3, name='荔枝', money=9.99, num=40}]}
16:list遍歷

List<String> list = new ArrayList<String>(); list.add("aaa"); list.add("bbb"); list.add("ccc"); 方法一: 超級for循環遍歷 for(String attribute : list) { System.out.println(attribute); } 方法二: 對於ArrayList來說速度比較快, 用for循環, 以size為條件遍歷: for(int i = 0 ; i < list.size() ; i++) { system.out.println(list.get(i)); } 方法三: 集合類的通用遍歷方式, 從很早的版本就有, 用迭代器迭代 Iterator it = list.iterator(); while(it.hasNext()) { System.ou.println(it.next); }