首先呢,給大家講一下集合的由來(lái):java的思想是面向?qū)ο笏枷?,如果想統(tǒng)一的管理所有的對(duì)象,就涉及到用容器來(lái)儲(chǔ)存對(duì)象,而對(duì)象數(shù)組是可以存儲(chǔ)對(duì)象的,但是數(shù)組有一個(gè)缺點(diǎn)就是長(zhǎng)度固定,為了突破這一限制 ,集合就應(yīng)運(yùn)而生了。
數(shù)組和集合的優(yōu)缺點(diǎn)
長(zhǎng)度:數(shù)組固定,集合可變;
內(nèi)容:集合只能存儲(chǔ)引用類型,數(shù)組可以存儲(chǔ)基本類型和引用類型。
集合體系
單列集合頂層接口
Collection
|-List有序(存入和取出順序相同) 存入的元素可以重復(fù) 有索引 可以通過(guò)索引來(lái)操作元素
|-ArrayList 數(shù)組結(jié)構(gòu)
|-LinkedList 鏈表結(jié)構(gòu)
|-Vector 數(shù)組結(jié)構(gòu)
|-Set 無(wú)序(存入和取出順序不同) 存入的元素不可以重復(fù)
|-HashSet 哈希算法
|-TreeSet 二叉樹(shù)算法
雙列集合
Map
|-HashMap
|-TreeMap
Collection
常用方法:
boolean add(E e):向集合中添加元素e,添加成功返回true,添加失敗返回false(List集合永遠(yuǎn)添加成功 Set集合就有可能添加失敗因?yàn)镾et集合會(huì)去掉重復(fù)元素)
boolean remove(Object o):刪除集合中的元素o,刪除成功則true,刪除失敗則false
void clear():清空集合里面的元素
boolean contains(Object o):集合是否包含元素o,如果包含返回true,如果不包含返回false
boolean isEmpty():判斷集合是否為空
int size():集合的長(zhǎng)度
集合的長(zhǎng)度:c.size();
字符串長(zhǎng)度:s.length();
數(shù)組的長(zhǎng)度:arr.length;
代碼演示:
public static void main(String[] args) {
Collection c = new ArrayList(); //父類引用指向子類對(duì)象
boolean b1 = c.add("abc"); //添加一個(gè)字符串
boolean b2 = c.add(true); //自動(dòng)裝箱new Boolean(true);
boolean b3 = c.add(100); //自動(dòng)裝箱new Integer(100);
boolean b4 = c.add(new Student("張三",23)); //添加一個(gè)自定義對(duì)象
boolean b5 = c.add("abc"); //添加一個(gè)重復(fù)的字符串
System.out.println(b1); //true
System.out.println(b2); //true
System.out.println(b3); //true
System.out.println(b4); //true
System.out.println(b5); //true
System.out.println(c);//[abc, true, 100, Student [name=張三, age=23], abc]
//ArrayList的父類重寫(xiě)了Object的toString()
Collection c1 = new ArrayList(); //父類引用指向子類對(duì)象
c1.add("a");
c1.add("b");
c1.add("c");
c1.add("d");
c1.remove("b"); //刪除指定元素
System.out.println(c1); //[a, c, d]
System.out.println(c1.contains("b")); //false 判斷是否包含
System.out.println(c1.contains("c")); //true 判斷是否包含
System.out.println(c1.size()); //3 長(zhǎng)度為3
System.out.println(c1.isEmpty()); //false 不為空
c1.clear(); //清空集合 //清空集合
System.out.println(c1); //[]
}
Object[] toArray():集合轉(zhuǎn)數(shù)組 (可以用來(lái)遍歷)
代碼演示:
public static void main(String[] args) {
Collection c = new ArrayList();
c.add(new Student("張三", 23)); //自動(dòng)類型提升:Object obj = new Student("張三",23);
c.add(new Student("李四", 24));
c.add(new Student("王五", 25));
c.add(new Student("趙六", 26));
Object[] arr = c.toArray(); //將集合轉(zhuǎn)換成數(shù)組
for (int i = 0; i < arr.length; i++) {
Student s = (Student)arr[i]; //向下轉(zhuǎn)型
System.out.println(s.getName() + "..." + s.getAge());
}
}
不常用的帶All的方法
boolean addAll(Collection c):添加 c里面的所有元素
boolean removeAll(Collection c):刪除交集
boolean containsAll(Collection c):是否全部包含
boolean retainAll(Collection<?> c):取交集
迭代器 Iterator
迭代器的原理
Iterator是個(gè)接口,是通過(guò)集合里面的內(nèi)部類實(shí)現(xiàn)的。迭代器是對(duì)集合進(jìn)行遍歷,而每一個(gè)集合內(nèi)部的存儲(chǔ)結(jié)構(gòu)都是不同的,所以每一個(gè)集合存和取都是不一樣,那么就需要在每一個(gè)類中定義hasNext()和next()方法。這樣做是可以的,但是會(huì)讓整個(gè)集合體系過(guò)于臃腫,迭代器是將這樣的方法向上抽取出接口,然后在每個(gè)類的內(nèi)部定義自己迭代方式,這樣做的好處有二:第一、規(guī)定了整個(gè)集合體系的遍歷方式都是hasNext()和next()方法;第二、代碼有底層內(nèi)部實(shí)現(xiàn),使用者不用管怎么實(shí)現(xiàn)的,會(huì)用即可。
代碼演示:
public static void main(String[] args) {
Collection c = new ArrayList();
c.add(new Student("張三", 23)); //Object obj = new Student("張三",23);
c.add(new Student("李四", 24));
c.add(new Student("王五", 25));
c.add(new Student("趙六", 26));
//獲取迭代器
Iterator it = c.iterator();
while(it.hasNext()) {
System.out.println(((Student)it.next()).getName()+" "+
((Student)it.next()).getAge());//如果這樣寫(xiě)的話 打印結(jié)果為 zhangsan 14 并且報(bào)錯(cuò)java.util.NoSuchElementException 因?yàn)閚ext()方法調(diào)用一次,指針就往后走一次
Student s = (Student)it.next(); //所以一般while循環(huán)里面 就出現(xiàn)一次next(),如果想使用多次 請(qǐng)用一個(gè)變量接受next()方法的返回值
System.out.println(s.getName()+" "+s.getAge());
}
}
List接口
List的特有方法
void add(int index,E element);在指定的index位置插入element元素
E remove(int index);刪除index位置上的元素
E get(int index);獲取指定index位置上的元素??梢杂脕?lái)遍歷List集合,而且這種遍歷方式是List特有的遍歷方式
E set(int index,E element);把集合中index位置上的元素用element元素替換
concurrentModificationException:并發(fā)修改異常
原因:在用迭代器遍歷集合的時(shí)候,我們通過(guò)集合改變了元素,而迭代器是通過(guò)集合得到的,集合發(fā)生了改變,而迭代器還是通過(guò)原來(lái)的集合得到的,所以產(chǎn)生了并發(fā)修改異常。
解決:
- 通過(guò)迭代器遍歷集合的時(shí)候,我們通過(guò)迭代器來(lái)改變集合元素,而這時(shí)候原來(lái)Iterator沒(méi)有添加元素的方法,所以就用ListIterator,因?yàn)長(zhǎng)istIterator里面有add方法
- 通過(guò)普通for循環(huán)來(lái)遍歷集合的時(shí)候,用集合來(lái)改變?cè)?/li>
代碼演示:
public static void main(String[] args) {
List list = new ArrayList();
list.add("a"); //Object obj = new String();
list.add("b");
list.add("world");
list.add("c");
list.add("d");
list.add("e");
//報(bào)并發(fā)修改異常原因:
Iterator it = list.iterator(); //獲取迭代器
while(it.hasNext()) { //判斷集合中是否有元素
String str = (String)it.next(); //向下轉(zhuǎn)型
if("world".equals(str)) {
//遍歷的同時(shí)在用集合調(diào)用add方法增加元素,并發(fā)修改ConcurrentModificationException
list.add("javaee");
}
}
//解決方案一
ListIterator lit = list.listIterator();//獲取迭代器(List集合特有的)可以通過(guò)hasPrevious()和previous()來(lái)往前遍歷
while(lit.hasNext()) {
String str = (String)lit.next();//向下轉(zhuǎn)型
if("world".equals(str)) {
lit.add("javaee"); //遍歷的同時(shí)用迭代器調(diào)用add方法添加元素就沒(méi)問(wèn)題
}
}
//解決方案二
for (int i = 0; i < list.size(); i++) { //通過(guò)普通for循環(huán)來(lái)遍歷集合的時(shí)候,用集合來(lái)改變?cè)? String str = (String)list.get(i);
if("world".equals(str)){
list.add("javaee");
}
}
System.out.println(list);
}
ArrayList
基本上都是從List實(shí)現(xiàn)的方法,因此沒(méi)有特有的方法。
案例:ArrayList去除集合中字符串的重復(fù)值(字符串的內(nèi)容相同)
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("c");
list.add("c");
list.add("c");
ArrayList newList = getSingle(list);
System.out.println(newList);
}
/*
* 分析:
* 1,創(chuàng)建新集合
* 2,根據(jù)傳入的集合(老集合)獲取迭代器
* 3,遍歷老集合
* 4,通過(guò)新集合判斷是否包含老集合中的元素,如果包含就不添加,如果不包含就添加
*/
public static ArrayList getSingle(ArrayList list) {
ArrayList newList = new ArrayList<>(); //1,創(chuàng)建新集合
Iterator it = list.iterator(); //2,根據(jù)傳入的集合(老集合)獲取迭代器
while(it.hasNext()) { //3,遍歷老集合
Object obj = it.next(); //記錄住每一個(gè)元素
if(!newList.contains(obj)) { //如果新集合中不包含老集合中的元素
newList.add(obj); //將該元素添加
}
}
return newList;
}
LinkedList
public void addFirst(E e)將指定元素插入此列表的開(kāi)頭。
public void addLast(E e)將指定元素添加到此列表的結(jié)尾。
public E removeFirst()移除并返回此列表的第一個(gè)元素。
public E removeLast()移除并返回此列表的最后一個(gè)元素。
public E getFirst()返回此列表的第一個(gè)元素。
public E getLast()返回此列表的最后一個(gè)元素。
代碼演示:
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.addFirst("a");
list.addFirst("b");
list.addFirst("c");
list.addFirst("d");
list.addLast("e");
System.out.println(list.getFirst()); //d
System.out.println(list.getLast()); //e
System.out.println(list.removeFirst()); //d
System.out.println(list.removeLast()); //e
System.out.println(list); //[c, b, a]
}
棧和隊(duì)列:
棧: 先進(jìn)后出
隊(duì)列: 先進(jìn)先出
Vector
jdk1.0出現(xiàn)1.2并入到List體系,后來(lái)被ArrayList替代,所以了解即可。
附:
數(shù)組結(jié)構(gòu):查詢快 增刪慢
鏈表結(jié)構(gòu):查詢慢 增刪快List的三個(gè)兒子的特點(diǎn)
ArrayList:查詢快 增刪慢 不安全 效率高
LinkedList:查詢慢 增刪快 不安全 效率高
Vector:查詢快 增刪慢 安全 效率低
好了集合部分就先說(shuō)到這了,想了解更多學(xué)習(xí)知識(shí),請(qǐng)關(guān)注微信公眾號(hào)“阿Q說(shuō)”,獲取更多學(xué)習(xí)資料吧!你也可以后臺(tái)留言說(shuō)出你的疑惑,阿Q將會(huì)在后期的文章中為你解答。每天學(xué)習(xí)一點(diǎn)點(diǎn),每天進(jìn)步一點(diǎn)點(diǎn)。