------Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! -------
集合框架 Collection java.util(interface)
集合 只能存儲引用類型,存儲對象,不存儲基本類型,長度可變
數組 存儲基本類型,存儲對象,長度固定
集合中存儲的都是引用類型的元素,那麼引用類型變量實際上存儲的是對象的“地址”,所以實際上集合只存儲了元素對象在堆中的地址,而並不是將對象本身存入了集合中。
Collection 接口
是層次結構中的根接口,定義了集合相關的操作方法。
其有兩個子接口:List(可重複集)和Set(不可重複集)
元素是否重複,取決於元素的equals() 比較的結果
成員方法:
boolean add(E e) // 添加元素
boolean remove(E e) // 移除第一次出現的指定元素
void clear() // 清空集合
boolean contains(Object o) // 判斷是否包含指定對象
boolean isEmpty() // 判斷集合是否爲空
int size() // 返回集合的大小(容量),即集合中存儲元素的個數
boolean addAll(Collection c) // 添加指定集合中的所有元素
boolean removeAll(Collection c) // 移除指定集合中包含的所有元素
boolean containsAll(Collection c) // 判斷是否包含指定集合的所有元素
boolean retainAll(Collection c) // 保留與指定集合中相同的元素(獲取交集)
Object[] toArray() // 集合 --> 數組,可以實現集合的遍歷
Iterator<E> iterator() // 獲取迭代器,集合專用的遍歷方式
* 迭代器迭代結合,泛型跟隨集合
Iterator 迭代器
集合專用遍歷方式,做集合中元素的獲取
集合頂層接口Collection中,定義了一個抽象方法Iterator<E> iterator(),返回值是接口類型,返回的是該接口的實現類對象。
迭代器接口的實現類是集合容器的內部類,Collection下面所有的實現類,都會重寫該方法。比如 ArrayList 實現 List 接口,而 List 繼承自Collection。
迭代器類的成員方法:
boolean hasNext() // 判斷集合中是否還有下一個元素
<E> next() // 獲取迭代的下一個元素
void remove() // 移除本次迭代後迭代器返回的最後一個元素
迭代器的刪除方法是在原集合中刪除元素
ConcurrentModificationException
在使用迭代器遍歷集合時,不能通過集合的remove() 方法刪除集合元素,否則會拋出併發更改異常,可以通過迭代器自身提供的remove() 方法刪除通過next() 迭代出的元素。
在調用remove() 方法前必須通過迭代器的next() 方法迭代過元素,那麼刪除的就是這個元素。並且不能再次調用remove() 方法,除非再次調用next() 後方可再次調用。
使用迭代器接口的兩種方式,一般使用 while 循環
Iterator iterator = collection.iterator();
// 調用迭代器接口方法判斷集合中有沒有下一個元素
while (iterator.hasNext()) {
// 調用迭代器接口方法獲取出集合中的元素
Object object = iterator.next();
System.out.println(object);
}
for (Iteratoriterator = collection.iterator(); iterator.hasNext();){
Object object = iterator.next();
System.out.println(object);
}
增強型for循環
since JDK1.5,只用於遍歷集合或數組,也稱新循環
格式:
for(元素類型 變量名 : 集合或數組) {
循環體
}
好處:減少代碼量,方便做遍歷;弊端:不能改動數組或集合中的元素
增強for循環並非新的語法,而是在編譯過程中,編譯器會將新循環轉換爲迭代器模式。所以新循環本質上是迭代器。
遍歷集合的 3 種方式:迭代器,增強 for 循環,普通for 循環(size() + get())
List 接口 繼承 Collection 接口
特點:有序集合,存取有序,有索引,允許重複
成員方法
void add(int index, E element) // 向指定索引處添加元素
E remove(int index) // 移除指定索引處的元素並返回該元素
E get(int index) // 獲取指定索引上的元素
E set(int index, E element) // 替換指定索引上的元素並返回之前的元素
ListIterator<E> listIterator() // 獲取迭代器
int lastIndexOf(Object o) // 返回指定元素出現的最後一個位置的索引
List<E> subList(int fromIndex, inttoIndex) // 獲取子List
--------------------------------------------------------------------
importjava.util.ArrayList;
importjava.util.List;
/*
* 證明 subList 獲取的 List 與原 List 佔用相同的存儲空間,對子 List 的操作會影響原 List
*/
public classSubListDemo {
public static void main(String[] args) {
List<Integer> list = newArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
System.out.println("list " +list);
// list [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
List<Integer> subList =list.subList(3, 8);
System.out.println("subList " +subList);
// sublist [3, 4, 5, 6, 7]
// subList 獲得的 List 和原 List 佔有相同的數據空間
for (int i = 0; i < subList.size();i++) {
subList.set(i, subList.get(i) * 10);
}
System.out.println("changedsubList" + subList);
// changedsublist [30, 40, 50, 60, 70]
System.out.println("unchangedlist" + list);
// unchangedlist [0, 1, 2, 30, 40, 50,60, 70, 8, 9]
list.subList(3, 8).clear(); // 可以用於刪除連續元素
System.out.println(list);
// [0, 1, 2, 8, 9]
}
}
ListIterator 列表迭代器
允許按任一方向遍歷列表,迭代期間可以修改列表
void add(E e)
booleanhasNext() // 正向遍歷
boolean hasPrevious() // 逆向遍歷
E next() // 返回列表中的下一個元素
int nextIndex() // 返回返回下一個索引
E previous() // 返回列表中的前一個元素
int previousIndex() // 返回前一個索引
void remove() // 移除本次迭代後迭代器返回的最後一個元素
void set(E e) // 替換此次迭代後迭代器返回的最後一個元素
對 List 集合進行正向遍歷和逆向遍歷
List list= newArrayList<>();
list.add("www");
list.add("itcast.");
list.add("cn");
// 調用集合方法,獲取ListIterator接口的實現類對象
ListIteratoriterator=list.listIterator();
while (iterator.hasNext()) {
Objectobject= (Object) iterator.next();
if ("www".equals(object)) {
// 調用迭代器的方法
// 添加元素到迭代到元素的下一個位置
// iterator.add("0807Java");// 添加和修改不能在同一次迭代中
// 修改迭代到的元素
iterator.set("www.");
}
}
//迭代器指針到了最後,不能再次獲取,出現沒有元素被取出異常
// 逆向遍歷逆向遍歷之前要先做一次正向遍歷
while (iterator.hasPrevious()) {
Objectobject= (Object) iterator.previous();
System.out.print(object + " "); // cn itcast. www.
}
泛型機制 Generic since JDK5
泛型在集合中的應用
泛型的本質是參數化類型。在類、接口和方法的定義過程中,所操作的數據類型被傳入的參數指定,強制集合必須存儲指定的數據類型,保證程序的安全性。
Java泛型機制廣泛的應用在集合框架中,所有的集合類型都帶有泛型參數,這樣在創建集合時可以指定放入集合中元素的類型。Java編譯器可以據此進行類型檢查,這樣可以減少代碼在運行時出現錯誤的可能性。
集合類<存儲的數據類型> 變量名 = new 集合類<存儲的數據類型>();
好處:減少代碼量,避免類型強制轉換,安全問題由運行時期提前到了編譯時期。
Java中的泛型是僞泛型,只在編譯時期有效,編譯後的class文件中沒有泛型,編譯手段。
ArrayList類的定義中,<E> 中的 E 爲泛型參數(理解爲變量名,相當於定義了一個變量,負責接收數據類型),在創建對象時可以將類型作爲參數傳遞,此時,類定義所有的 E 將被替換成傳入的參數。
*注意:集合存儲八種基本類型,泛型必須寫包裝類;迭代器迭代結合,泛型跟隨集合
泛型類、泛型方法
package cn.itcast;
/*
* 自定義泛型類
* 自己寫的類上,加上泛型<變量>
*
* 定義成員變量,也是泛型
*
* E 變量,等待建立此類對象的時候,由調用者指定他的數據類型
*/
class GenericClass<E> {
private E e;
/*
* 泛型方法
* 方法參數上,使用了一個和類上一樣的泛型
* 創建類的對象的時候,直接指定數據類型
*
* 方法上泛型需要單獨的定義,定義在方法的聲明上
* 創建類的對象同時,不能指定方法上泛型,調用者調用方法時直接指定
*
* 靜態方法參數上的泛型,不能和類上的泛型一樣
* 原因:靜態不能直接調用非靜態
*/
publicvoid show(E e) {
System.out.println(e);
}
public <W> void function(W w){
System.out.println(w);
}
publicstatic <C> void method(C c){
System.out.println(c);
}
public E getE() {
returne;
}
publicvoid setE(E e) {
this.e = e;
}
}
publicclassGenericDefine {
publicstaticvoid main(String[] args) {
GenericClass<Integer>genericClass= newGenericClass<Integer>();
genericClass.setE(123);
Integerinteger= genericClass.getE();
System.out.println(integer);
GenericClass<String>genericClass2= newGenericClass<String>();
genericClass2.setE("abc");
Stringstring= genericClass2.getE();
System.out.println(string + 1);
System.out.println("--------------");
genericClass2.show("傳智播客");
}
}
泛型接口
package cn.itcast;
/*
* 泛型接口
* 接口上定義泛型,接口中方法全抽象,實現類
* 在使用上兩種使用方式:
* 實現類實現接口,不理會泛型
* 實現類實現接口,同時也實現接口上的泛型
*/
interface Inter<T> {
publicabstractvoid show(T t);
}
// 定義接口的實現類,實現接口,不理會接口上的泛型
// 泛型的指定,實現類沒有做,讓調用者來指定數據類型
class InterImpl<T> implements Inter<T> {
@Override
publicvoid show(T t) {
System.out.println(t);
}
}
// 定義接口的實現類,實現接口的同時,也實現泛型 -- 不靈活
class InterImpl2 implements Inter<String>{
@Override
publicvoid show(String t) {
System.out.println(t);
}
}
publicclassGenericInterfaceDemo {
publicstaticvoid main(String[] args) {
Inter<Integer>in = newInterImpl<Integer>();
in.show(123);
Inter<String>in2= newInterImpl<String>();
in2.show("itcast");
}
}
泛型的限定:泛型通配符 <?>
? extends E (向下限定,E及其子類) ? super E (向上限定,E及其父類)
線性表
List接口是Collection的子接口,用於定義線性表數據結構,可以將List理解爲存放對象的數組,只不過其元素個數可以動態的增加或減少。
List接口的兩個常用實現類爲 ArrayList 和 LinkedList,分別用動態數組和鏈表的方式實現了List接口。
List 三個子類的特點
共同特點:有序,索引,重複。
ArrayList 和 LinkedList在性能上有一定的差別。
ArrayList 更適合於隨機訪問,而LinkedList 更適合於插入和刪除。
ArrayList 底層數據結構是可變數組,元素查詢速度快,增刪慢
線程不安全,不同步,運行速度快
默認容量 10,增長率50%
LinkedList 底層數據結構是雙向鏈表,元素查詢速度慢,增刪快
線程不安全,不同步,運行速度快
存儲和迭代器代碼,和 ArrayList 完全一樣
Vector 底層數據結構是可變數組,元素查詢速度快,增刪慢
線程安全,同步,運行速度慢
默認容量 10,增長率 100%
Vector 類特有方法:
void addElement(E obj) // 將指定的組件添加到向量的末尾,容量+1
E elementAt(int index) // 返回指定索引處的組件
Enumeration elements() // 返回此向量的組件的枚舉
LinkedList 類特有方法:
void addFirst(E e) voidaddLast(E e);
E getFirst() EgetLast()
E removeFirst() EremoveLast()
去除集合中存儲的重複元素
package cn.itcast;
importjava.util.ArrayList;
importjava.util.Iterator;
/*
* 去除集合中字符串的重複值 -- 去除數組中重複元素
* 去除集合中自定義對象的重複值(需要重寫自定義對象的equals()方法)
* ArrayList集合實現,List允許重複
* (String 類重寫了equals() 方法,建立了自己的比較方式)
* 如果原集合中元素沒有出現在新集合中,將該元素存儲到新集合中
* 遍歷完畢,新集合保存的就是去掉重複後的元素
* 將原集合的引用指向新集合
*/
public classArrayListTest {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("www");
list.add(".itcast");
list.add(".cn");
list.add("www");
list.add(".itheima");
list.add(".com");
list = removeSame(list);
System.out.println(list); // [www, .itcast, .cn, .itheima,.com]
}
// 返回的是去重複之後的新集合
public static ArrayList<String>removeSame(ArrayList<String> arrayList) {
// 創建新集合,保存去重複之後的元素
ArrayList<String> newList = newArrayList<String>();
// 迭代原集合
Iterator<String> iterator = arrayList.iterator();
while (iterator.hasNext()) {
// 接收迭代元素的結果
String string = iterator.next();
// 判斷新集合中是否包含該元素,沒有則添加進去
if (!newList.contains(string)) {
newList.add(string);
}
}
return newList;
}
}
LinkedList 模擬棧數據結構的集合
package cn.itcast;
import java.util.LinkedList;
/*
* LinkedList集合,模擬數據結構棧
*
* 將LinkedList集合中的功能封裝起來,調用者不直接面對集合,只能從外部調用
* 表現爲先添加的元素後被取出,存儲和取出的順序是相反的
*/
publicclassLinkedListTest {
publicstaticvoid main(String[] args) {
LinkedListToollist= newLinkedListTool();
list.add(0);
list.add(1);
list.add(2);
list.add(3);
// 當列表不爲空時,刪除元素並返回
while (!list.isEmpty()) {
System.out.println(list.remove());
}
}
}
// 自定義功能,封裝LinkedList類功能
class LinkedListTool {
// 定義成員變量
privateLinkedList<Object> list;
// 構造方法用於新建對象
public LinkedListTool() {
list = newLinkedList<Object>();
}
// 添加元素到列表結尾
publicvoid add(Object object) {
list.add(object);
}
// 判斷列表是否爲空
publicboolean isEmpty() {
returnlist.isEmpty();
}
// 從列表結尾刪除元素並返回
public Object remove() {
returnlist.removeLast();
}
}
List 集合 < == > 數組
List 轉換爲數組(集合轉成數組,帶有泛型)
Object[] toArray()
<T>T[] toArray(T[] a)
List<String>strings = new ArrayList<>();
strings.add("www");
strings.add(".itcast");
strings.add("cn");
String[] str = strings.toArray(newString[strings.size()]);
// 傳入一個指定類型的數組,該數組的元素類型應與集合的元素類型一致。
// 返回值則是轉換後的數組,該數組會保存集合中所有的元素
for (inti = 0; i< str.length; i++){
System.out.print(str[i] + " ");
}
數組轉換爲 List
Arrays 類中提供了一個靜態方法 asList,使用該方法我們可以將一個數組轉換爲對應的 List 集合。其方法定義爲: static <T> List<T> asList<T… a>
注意:返回的 List的集合元素類型由傳入的數組的元素類型決定;返回的集合不能對其增刪元素,否則會拋出異常,並且對集合的元素進行修改會影響數組對應的元素。
String[] strArr = { "www", ".itcast", ".cn" };
List<String>list =Arrays.asList(strArr); // fixed-size list
System.out.println(list); // [www, .itcast, .cn]
// 當前集合 list 的實際類型爲 java.util.Array$ArrayList
//而不是 List 接口的實現類 java.util.ArrayList,所以不支持對其添加或刪除元素
// list.add("IT"); // 會拋出 UnsupportedOperationException
System.out.println(list.getClass().getName());
list.set(0, "3w"); // 可以修改元素
// 對集合元素的修改會影響原數組
System.out.print("String[] ");
for (String string : strArr) {
System.out.print(string + " ");
}
System.out.println();
// 如果想要添加元素,可以用如下方式:
List<String>list2= newArrayList<>();
list2.addAll(Arrays.asList(strArr));
System.out.println(list2); // [3w, .itcast, .cn]
list2.add("0807JavaSE");
System.out.println(list2); // [3w, .itcast, .cn, 0807JavaSE]
可變參數 since JDK5
如果定義方法的時候,參數類型明確但個數不明確,可使用可變參數
格式:修飾符返回值類型方法名(數據類型...變量名) {}
可變參數方法傳遞,傳遞實際參數,數量沒有限制
注意:一個方法中只能寫 1 個可變參數,如果有多個參數可變參數只能放在最後
package cn.itcast.arguments;
publicclassVarArgumentsDemo {
publicstaticvoid main(String[] args) {
intsum = getSum(0, 1,2, 3, 4, 5);
System.out.println(sum);
}
publicstaticint getSum(int...is){
intsum = 0;
// 傳遞參數的個數,就是數組的長度
// 如果不傳遞任何參數,可變參數的數組的長度就是 0
// for(int i = 0; i < is.length; i++) {
// sum+= is[i];
// }
for (inti : is) {
sum += i;
}
returnsum;
}
}
l 獲取10個1-20之間的隨機數,要求不能重複
package cn.itcast.test;
importjava.util.ArrayList;
import java.util.List;
importjava.util.Random;
/*
* 獲取10個1-20之間的隨機數,要求不能重複
*/
public class ListTest {
public static void main(String[] args) {
Random r = new Random();
List<Integer> list = new ArrayList<Integer>();
while (true) {
// 獲取隨機數
int num = r.nextInt(20) + 1;
// 判斷隨機數如果不在集合中,就存儲到集合
if (!list.contains(num)) {
list.add(num);
// 判斷集合容量爲10就退出循環
if (list.size() == 10) {
break;
}
}
}
for (Integer integer : list) {
System.out.println(integer);
}
}
}
l 鍵盤錄入多個數據,以0結束,要求在控制檯輸出這多個數據中的最大值
package cn.itcast.test;
importjava.util.ArrayList;
import java.util.List;
importjava.util.Scanner;
/*
* 鍵盤錄入多個數據,以0結束
* 在控制檯輸出最大值:
* 利用數組,將集合轉成數組
* 1.升序排序,獲取最後一個元素
* 2.獲取數組中的最大值
*
*/
public classListScannerTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
List<Integer> list = new ArrayList<Integer>();
while (true) {
int num = sc.nextInt();
if (num == 0) {
break;
}
// 數據存儲到集合中
list.add(num);
}
sc.close();
// System.out.println(list);
// 將集合轉成數組
Integer[] integers = list.toArray(new Integer[list.size()]);
// 選擇排序
for (int i = 0; i < integers.length; i++) {
for (int j = i + 1; j < integers.length; j++) {
if (integers[i] > integers[j]) {
int temp = integers[i];
integers[i] = integers[j];
integers[j] = temp;
}
}
}
// 輸出數組中的最後一個索引
System.out.println(integers[integers.length - 1]);
// 求數組最值思想
// int max = list.get(0);
// for (Integer integer : integers) {
// if (integer > max)
// max = integer;
// }
// System.out.println(max);
}
}
List 排序
Collections.sort() 方法實現排序
Collections 是集合的工具類,提供很多便於操作集合的方法。
void sort(List<T>list) // 該方法的作用是對給定的集合元素進行自然排序