java List/ArrayList 解惑


 

導讀:祖傳挖墳派學習方法(寶兒姐友情支持)

  第一部分  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 

目錄

 

  1. list中添加,獲取,刪除元素;
  2. list中是否包含某個元素;
  3. list中根據索引將元素數值改變(替換);
  4. list中查看(判斷)元素的索引;
  5. 根據元素索引位置進行的判斷;
  6. 利用list中索引位置重新生成一個新的list(截取集合);
  7. 對比兩個list中的所有元素;
  8. 判斷list是否為空;
  9. 返回Iterator集合對象;
  10. 將集合轉換為字符串;
  11. 將集合轉換為數組;
  12. 集合類型轉換;
  13. 去重復;
  14. List轉換MAP
  15. List分組
  16. 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)
            }
View Code

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("我不開心");
            }
View Code

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);
            }
View Code

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("張飛"));
View Code

5.根據元素索引位置進行的判斷;

if (names.indexOf("劉備")==0) {
    System.out.println("劉備在這里");
}else if (names.lastIndexOf("劉備")==3) {
    System.out.println("劉備在那里");
}else {
    System.out.println("劉備到底在哪里?");
}
View Code

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));
            }
View Code

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("我們不一樣");
}
View Code

8.判斷list是否為空;

//空則返回true,非空則返回false

if (person.isEmpty()) {
    System.out.println("空的");
}else {
    System.out.println("不是空的");
}
View Code

9.返回Iterator集合對象;

System.out.println("返回Iterator集合對象:"+person.iterator());

1+0.將集合轉換為字符串;

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

11.將集合轉換為數組;

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

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));
}
View Code

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);
View Code

完整代碼:

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;
    }
 
 
    }
View Code

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);
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM