1. 程式人生 > >11、集合(1)

11、集合(1)

1、集合

介紹:集合,集合是java中提供的一種容器,可以用來儲存多個數據。出現意義:面嚮物件語言對事物的體現都是以物件的形式,所以為了方便對多個物件的操作,就對物件進行儲存,集合就是儲存物件最常用的一種方式。Java中的集合: JDK為我們提供了一套完整的容器類庫,這些容器可以用於儲存各種型別的物件,並且長度都是可變的,我們把這些類統稱為集合類,它們都位於java.util包中。

☆集合和陣列區別:陣列的長度是固定的。集合的長度是可變的。集合中儲存的元素必須是引用型別資料。

Collection概念:Collection是所有單列集合的直接或間接介面,其指定了所有集合應該具備的功能。集合體系如圖:在這裡插入圖片描述


☆List總結

  1. 所有的List中只能容納單個不同型別的物件組成的表,而不是Key-Value鍵值對。例如:[ tom,1,c ];
  2. 所有的List中可以有相同的元素,例如Vector中可以有 [ tom,koo,too,koo ];
  3. 所有的List中可以有null元素,例如[ tom,null,1 ];
  4. 基於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);
	}
}