11、集合(1)
1、集合
介紹:集合,集合是java中提供的一種容器,可以用來儲存多個數據。出現意義:面嚮物件語言對事物的體現都是以物件的形式,所以為了方便對多個物件的操作,就對物件進行儲存,集合就是儲存物件最常用的一種方式。Java中的集合: JDK為我們提供了一套完整的容器類庫,這些容器可以用於儲存各種型別的物件,並且長度都是可變的,我們把這些類統稱為集合類,它們都位於java.util包中。
☆集合和陣列區別:陣列的長度是固定的。集合的長度是可變的。集合中儲存的元素必須是引用型別資料。
Collection概念:Collection是所有單列集合的直接或間接介面,其指定了所有集合應該具備的功能。集合體系如圖:
☆List總結
- 所有的List中只能容納單個不同型別的物件組成的表,而不是Key-Value鍵值對。例如:[ tom,1,c ];
- 所有的List中可以有相同的元素,例如Vector中可以有 [ tom,koo,too,koo ];
- 所有的List中可以有null元素,例如[ tom,null,1 ];
- 基於Array的List(Vector,ArrayList)適合查詢,而LinkedList(連結串列)適合新增,刪除操作。
☆Set總結
6. Set實現的基礎是Map(HashMap);
7. Set中的元素是不能重複的,如果使用add(Object obj)方法新增已經存在的物件,則會覆蓋前面的物件
Collection通用方法:
boolean add(E e) //新增元素
boolean remove(Object o) //刪除元素
void clear() //清空集合
boolean contains(Object o) //判斷是否包含某元素
boolean isEmpty() //判斷是否為空
int size() //獲取集合長度
增強for迴圈:增強for迴圈是JDK1.5以後出來的一個高階for迴圈,專門用來遍歷陣列和集合的。它的內部原理其實是個Iterator迭代器,所以在遍歷的過程中,不能對集合中的元素進行增刪操作。增強for迴圈用來迭代集合或陣列。
☆格式:for(元素的資料型別 變數 : Collection集合or陣列){}
☆注意:新for迴圈必須有被遍歷的目標。目標只能是Collection或者是陣列。遍歷陣列時,如果僅為遍歷,可以使用增強for如果要對陣列的元素進行 操作,使用老式for迴圈可以通過角標操作。
迭代器:集合用來持有資料,一定會設計出對資料的增、刪、改、查四個常用方法,而查是集合中最常用的功能。Collection介面繼承了Iterable介面,具備了可迭代功能iterator方法,該方法用於迭代集合。所以,所有單列集合由於是Collection的直接或間接實現類,均具有該方法。而增強for迴圈讓迭代器迴圈訪問的方式更加簡便。
☆區別for迴圈:1、如果在for迴圈的過程中呼叫集合的remove()方法,就會導致併發修改異常 。因為迴圈過程中list.size()長度變小導致了錯誤。如果想在迴圈語句中刪除集合中的某個元素,就要用迭代器iterator的remove()方法。2、在ArrayList裡,for迴圈較快;在LinkedList裡,使用iterator較快。
迭代常規步驟:1、通過集合獲取這個集合的迭代器。 2、結合使用迭代器的hashNext與next完成集合迭代。
ArryList<String> list = new ArryList <String>();
list.add("i love java");
list.add("i like java");
Iterator<String> iterator = list.iterator();//返回迭代器
while (iterator.hasNext()) {
String string = iterator.next();
System.out.println(string);}
迭代集合元素圖解:
public class Demo {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("111");
c.add("追");
c.add(111);
Iterator iterator = c.iterator(); // Iterator 介面 指向 子類物件.
while(iterator.hasNext()){// 2.呼叫迭代器的方法,獲取集合中的元素.
Object next = iterator.next();
System.out.println(next);}
}
}
說明:遍歷之前,有一個指標指向初始位置,第一個元素的前面, hasNext,判斷是否在指標後面有元素,有返回true ,沒有返回false 。如果有 , 就可以通過 next() 獲取下一個元素了。
public class Demo {
public static void main(String[] args) {
Person s1 = new Person("顧慎為" , 20);
Person s2 = new Person("獨步王" , 59);
Collection<Person> c = new ArrayList<>();
c.add(s1);
c.add(s2);
System.out.println(c);
Iterator<Person> it = c.iterator();//獲取迭代器
while (it.hasNext()) {
Person p = it.next();
if(p.getAge() <59){
//c.remove(p);ConcurrentModificationException 併發修改異常 .
it.remove(); // 移除當前迭代的元素. (迭代器移除方法可以避免併發修改異常)
System.out.println(p.getName() +" --- "+ p.getAge());
}
}
}
class Person {
String name;
int age;
public Person(String n,int a){
this.name=n;
this.age=a;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
併發修改異常:迭代過程中併發修改異常的原因為迭代器中”記憶”的集合長度與集合中實際長度不同,而導致出現索引與實際元素不符甚至無限迴圈的情況發生。所以在使用Iterator時,避免類似操作,for迴圈底層為迭代器實現,所以也需要避免類似操作。有些迭代器避免了這樣的問題,如ListIterator,但該類並不通用也不常用,實際開發中很少使用,只需要簡單瞭解。
2、泛型
概述:泛型用來靈活地將資料型別應用到不同的類、方法、介面當中。將資料型別作為引數傳遞。泛型是資料型別的一部分,我們將類名與泛型合併一起看做資料型別。泛型的定義:定義泛型可以在類中預支地使用未知的型別。泛型的使用:一般在建立物件時,將未知的型別確定具體的型別。當沒有指定泛型時,預設型別為Object型別。常見應用:泛型類、泛型方法、泛型介面
含有泛型的類:
定義格式:修飾符 class 類名<代表泛型的變數> { }
//例如,API中的ArrayList集合
class ArrayList<E>{public boolean add(E e){ };public E get(int index){ }}
使用格式:建立物件時,確定泛型的型別。
ArrayList list = new ArrayList<>();
含有泛型的方法:
定義格式:修飾符 <代表泛型的變數> 返回值型別 方法名(引數){ }
//例如,API中的ArrayList集合中的方法:
public <T> T[] toArray(T[] a){ }//該方法,用來把集合元素儲存到指定資料型別的陣列中,返回已儲存集合元素的陣列
使用格式:呼叫方法時,確定泛型的型別。
ArrayList list = new ArrayList<>();
String[] arr = new String[100];
String[] result = list.toArray(arr);
含有泛型的介面:
定義格式:修飾符 interface介面名<代表泛型的變數> { }
//例如,API中的Iterator迭代器介面
public interface Iterator<E> {public abstract E next();}
使用格式:
1、定義類時確定泛型的型別
public final class Scanner implements Iterator { public String next(){ }}
2、始終不確定泛型的型別,直到建立物件時,確定泛型的型別
Collection list = new ArrayList<>();
Iterator it = list.iterator();//此時,變數E的值就是String型別。
泛型萬用字元:在JDK1.5出現前,使用Object代表任意型別,但在使用時,涉及到了強轉的麻煩。泛型替代了Object來代表任意型別。泛型在編譯時會擦除:泛型僅用來在編譯期限制、方便程式設計師的操作,實際上真正編譯後的.class中是沒有泛型的,其中仍然使用的為Obejct類,通過類似多型的方式完成任意某個型別的指定。當使用泛型類或者介面時,傳遞的資料中,泛型型別不確定,可以通過萬用字元<?>表示。但是一旦使用泛型的萬用字元後,只能使用Object類中的共性方法,集合中元素自身方法無法使用。
☆泛型優點:提高了程式的安全性;將執行期遇到的問題轉移到了編譯期;省去了型別強轉的麻煩。
/*
泛型萬用字元?,代表任意的資料型別
使用:呼叫方法時可以給予任意型別。參照Arraylist的構造方法
public ArrayList(Collection<? extends E> c)
? extends E代表只要是E型別的子類即可
? super E代表只要是E型別的父類即可
*/
public class Demo {
public static void main(String[] args) {
ArrayList<String> listB = new ArrayList<>();
listB.add("Trump");
//建立集合物件A時,給於另外一個集合物件B作為引數,則建立好的集合A中包含了集合B中的元素
ArrayList<Object> listA = new ArrayList<Object>(listB);
listA.add("Obama");
System.out.println(listA);
}
}