Java中ArrayList與順序表的概念與使用實例
前言
通過前面的博客我們已經大致瞭解瞭關於Java的基本知識,而下面的幾篇博客我們著重開始對於數據結構的知識進行學習,這篇博客我們就瞭解關於順序表和ArrayList的相關知識,從名字上我們就可以看到ArrayList是數組鏈表,也就是我們總說的順序表。這是Java內置的,因此不需要我們寫,這也方便瞭程序員的使用。那麼面我們就來瞭解一下ArrayList順序表的相關知識。
在學習順序表之前呢,我們需要瞭解幾個概念。
泛型(Generic)
泛型的引入
問題: 我們在之前學習順序表的時候,隻能保存int類型的元素,如果現在我們需要保存Person類型對象的引用順序表,那麼我們該如何解決呢?
回答:
- 首先,我們在學習多態過程中已知一個前提,基類的引用可以指向子類的對象。
- 其次,我們也已知Object是 java 中所有類的祖先類。
那麼,解決這個問題我們就想到一個辦法,我們將順序表數組種元素類型定義為Object類型,這樣我們的Object類型的引用可以指向int類型的對象,也可以指向Person類型的對象。舉個例子:
public class MyArrayList { private Object[] array; // 保存順序表的元素,即 Object 類型的引用 private int size; // 保存順序表內數據個數 public void add(Object o) { 尾插 } public Object get(int index) { 獲取 index 位置的元素 } ... }
現在的 MyArrayList 雖然可以做到添加任意類型的引用到其中瞭,但遇到以下代碼就會產生問題。
Person person = (Person)books.get(0); // 將 Object 類型轉換為 Person 類型,需要類型轉換才能成功 // 這裡編譯正確,但運行時會拋出異常 ClassCastException
此時的book對象的get()方法的返回值是Object類型因此我們需要強制轉化為Person類型才可以賦值給person對象,但是這隻是編譯上通過,但是運行仍會報錯,因此引入瞭泛型這個概念。
泛型的基本概念
泛型分為兩類:
- 泛型類
- 泛型方法
什麼是泛型類呢?我們來看一個例子:
public class MyArrayList<E> { private E[] array; private int size; ... }
在這個MyArrayList類中,我們可以看到後面跟瞭一個尖括號,這就是泛型的標志。有以下幾點需要註意:
- 尖括號 <> 是泛型的標志。
- E 是類型變量(Type Variable),變量名一般要大寫。
- E 在定義時是形參,代表的意思是 MyArrayList 最終傳入的類型,但現在還不知道。
也就是說我們在用這個類創建對象時,我們可以在類的尖括號中告訴編譯器你使用的是什麼對象。比如:
// 定義瞭一個元素是 Book 引用的 MyArrayList MyArrayList<Book> books = new MyArrayList<Book>(); books.add(new Book()); // 會產生編譯錯誤,Person 類型無法轉換為 Book 類型 books.add(new Person()); // 不需要做類型轉換 Book book = book.get(0); // 不需要做類型轉換 // 會產生編譯錯誤,Book 類型無法轉換為 Person 類型 Person person = book.get(0);
我們可以看到,MyArrayList存放的是Book類型的引用,這是編譯器就可以達到類似Object的效果,存儲Book類型的對象,如果在裡面又想放入Person類型的對象就會報錯。
總結
- 泛型是為瞭解決某些容器、算法等代碼的通用性而引入,並且能在編譯期間做類型檢查。
- 泛型利用的是 Object 是所有類的祖先類,並且父類的引用可以指向子類對象的特定而工作。
- 泛型是一種編譯期間的機制,即 MyArrayList< Person > 和MyArrayList< Book > 在運行期間是一個類型。
- 泛型是 java 中的一種合法語法,標志就是尖括號 <>。
包裝類(Wrapper Class)
包裝類的引入
我們知道Object引用可以指向任意類型的對象,但是8種基本數據類型又不是對象,那麼泛型就無法對這8種基本數據類型失效瞭。因此為瞭解決這個問題java 引入瞭一類特殊的類,即這 8 種基本數據類型的包裝類,在使用過程中,會將類似int這樣的值包裝到一個對象中去。
基本數據類型與包裝類的對應關系
基本數據類型 | 包裝類 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
基本就是類型的首字母大寫,除瞭 Integer 和 Character。
ArrayList與順序表
ArrayList簡介
簡單瞭解瞭泛型和包裝類的知識,下面我們就正式學習ArrayList的相關知識。
在集合框架中,ArrayList是一個普通的類,實現瞭List接口,具體框架圖如下:
說明:
- ArrayList實現瞭RandomAccess接口,表明ArrayList支持隨機訪問。
- ArrayList實現瞭Cloneable接口,表明ArrayList是可以clone的。
- ArrayList實現瞭Serializable接口,表明ArrayList是支持序列化的。
- 和Vector不同,ArrayList不是線程安全的,在單線程下可以使用,在多線程中可以選擇Vector或者CopyOnWriteArrayList。
- ArrayList底層是一段連續的空間,並且可以動態擴容,是一個動態類型的順序表。
ArrayList使用
ArrayList的構造
方法 | 解釋 |
---|---|
ArrayList() | 無參構造 |
ArrayList(Collection<? extends E> c) | 利用其他 Collection 構建 ArrayList |
ArrayList(int initialCapacity) | 指定順序表初始容量 |
舉個例子:
public static void main(String[] args) { // ArrayList創建,推薦寫法 // 構造一個空的列表 List<Integer> list1 = new ArrayList<>(); // 構造一個具有10個容量的列表 List<Integer> list2 = new ArrayList<>(10); list2.add(1); list2.add(2); list2.add(3); // list2.add("hello"); // 編譯失敗,List<Integer>已經限定瞭,list2中隻能存儲整形元素 // list3構造好之後,與list中的元素一致 ArrayList<Integer> list3 = new ArrayList<>(list2); // 避免省略類型,否則:任意類型的元素都可以存放,使用時將是一場災難 List list4 = new ArrayList(); list4.add("111"); list4.add(100); }
ArrayList常見方法
方法 | 解釋 |
---|---|
boolean add(E e) | 尾插 e |
void add(int index, E element) | 將 e 插入到 index 位置 |
boolean addAll(Collection<? extends E> c) | 尾插 c 中的元素 |
E remove(int index | 刪除 index 位置元素 |
boolean remove(Object o) | 刪除遇到的第一個 o |
E get(int index) | 獲取下標 index 位置元素 |
E set(int index, E element) | 將下標 index 位置元素設置為 element |
void clear() | 清空 |
boolean contains(Object o) | 判斷 o 是否在線性表中 |
int indexOf(Object o) | 返回第一個 o 所在下標 |
int lastIndexOf(Object o) | 返回最後一個 o 的下標 |
List subList(int fromIndex, int toIndex) | 截取部分 list |
代碼示例:
public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("JavaSE"); list.add("JavaWeb"); list.add("JavaEE"); list.add("JVM"); list.add("測試課程"); System.out.println(list); // 獲取list中有效元素個數 System.out.println(list.size()); // 獲取和設置index位置上的元素,註意index必須介於[0, size)間 System.out.println(list.get(1)); list.set(1, "JavaWEB"); System.out.println(list.get(1)); // 在list的index位置插入指定元素,index及後續的元素統一往後搬移一個位置 list.add(1, "Java數據結構"); System.out.println(list); // 刪除指定元素,找到瞭就刪除,該元素之後的元素統一往前搬移一個位置 list.remove("JVM"); System.out.println(list); // 刪除list中index位置上的元素,註意index不要超過list中有效元素個數,否則會拋出下標越界異常 list.remove(list.size()-1); System.out.println(list); // 檢測list中是否包含指定元素,包含返回true,否則返回false if(list.contains("測試課程")){ list.add("測試課程"); } // 查找指定元素第一次出現的位置:indexOf從前往後找,lastIndexOf從後往前找 list.add("JavaSE"); System.out.println(list.indexOf("JavaSE")); System.out.println(list.lastIndexOf("JavaSE")); // 使用list中[0, 4)之間的元素構成一個新的ArrayList返回 List<String> ret = list.subList(0, 4); System.out.println(ret); list.clear(); System.out.println(list.size()); }
運行結果:
ArrayList的遍歷
ArrayList 可以使用三方方式遍歷:for循環+下標、foreach、使用迭代器
代碼示例:
public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); // 使用下標+for遍歷 for (int i = 0; i < list.size(); i++) { System.out.print(list.get(i) + " "); } System.out.println(); // 借助foreach遍歷 for (Integer integer : list) { System.out.print(integer + " "); } System.out.println(); //使用迭代器 Iterator<Integer> it = list.listIterator(); while(it.hasNext()){ System.out.print(it.next() + " "); } System.out.println(); }
運行結果:
關於ArrayList順序表的相關知識就是這麼多,ArrayList使用起來是比較簡單的,但是細節上也是非常多的,而且還有一些其他的方法,我們可以通過源碼分析來看如何使用.
總結
到此這篇關於Java中ArrayList與順序表的文章就介紹到這瞭,更多相關Java ArrayList與順序表內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Java集合框架入門之泛型和包裝類
- Java中關於泛型、包裝類及ArrayList的詳細教程
- java集合collection接口與子接口及實現類
- Java ArrayList中存放引用數據類型的方式
- Java泛型最全知識總結