package com.rayNotes;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.TreeSet;
import org.junit.Test;
/**
* 原文地址:http://blog.csdn.net/yerenyuan_pku/article/details/53915999
* 集合入門綜述
* @author ray
*
*/
@SuppressWarnings({"unchecked","rawtypes"})
public class CollectionTest {
/**
* TODO 6、 set接口
* - Set集合不允許存儲重複元素,而且不保證元素是有序的
* (存入和取出的順序有可能一致[有序],也有可能不一致[無序])。
* - Set集合的功能和Collection的是一致的,
* 所以Set集合取出的方法只要一個,那就是迭代器。
* - HashSet
* 此類實現Set接口,由哈希表(實際上是一個HashMap實例)支持。
* 它不保證set的迭代順序,特別是它不保證該順序恆久不變。
* 此類允許使用null元素。
* 總結:
* - 保證元素唯一性的方式依賴於hashCode()與equals()方法
* - HashSet集合不能保證元素的迭代順序與元素存儲順序相同
*
* - LinkedHashSet
* 具有可預知迭代順序的Set接口的哈希表和鏈接列表實現。
* 此實現與HashSet的不同之外在於,後者維護着一個運行於所有條目的雙重鏈接列表。
* 總結:
* - 一個特殊的Set集合,而且是有序的,底層是一個雙向鏈表
*
* - TreeSet
* - Set接口中常用的類
* - TreeSet是線程不同步的,可以對Set集合中的元素進行排序。
* 底層數據結構是二叉樹(也叫紅黑樹),
* 保證元素唯一性的依據是:compareTo()方法return 0。
* - TreeSet對集合中的元素進行排序的方式有兩種
* - TreeSet排序的第一種方式:
* !!! --讓元素自身具備比較性。
* 元素需要實現 **Comparable接口,覆蓋compareTo()方法**。
* 這種方式也稱爲元素的自然順序,或者也叫默認順序。
* - TreeSet排序的第二種方式: 《 比較器更爲靈活,自然排序通常都作爲元素的默認排序。》
* 當元素自身不具備比較性時,或者具備的比較性不是所需要的,
* 這時就需要讓集合自身具備比較性。在集合一初始化時,就具備比較方式.
* 即:
* 定義一個比較器實現Comparator接口,覆蓋compare方法,
* 將Comparator接口的對象作爲參數傳遞給TreeSet集合的構造函數。
*
*
* - Hashset是如何保證元素的唯一性的呢?
* —— 是通過元素的兩個方法,hashCode()和equals()來完成的。
* 即元素必須覆蓋hashCode()和equals()方法,
* 覆蓋hashCode()方法是爲了根據元素自身的特點確定哈希值,
* 覆蓋equals()方法是爲了解決哈希值的衝突
*
*/
/**
*
*/
@Test
public void treeSetTest02() {
// - 自定義比較器
// 當元素自身不具備比較性時,或者具備的比較性不是所需要的,這時就需要讓容器自身具備比較性。
// 定義一個比較器,將比較器對象作爲參數傳遞給TreeSet集合的構造函數。
Set set1 = new TreeSet(new ComparatorByName());
set1.add(new Student("b", 6));
set1.add(new Student("e", 2));
set1.add(new Student("d", 1));
set1.add(new Student("c", 4));
set1.add(new Student("a", 5));
for (Iterator it = set1.iterator(); it.hasNext();) {
Student stu = (Student) it.next();
System.out.println(stu.getName() + "::" + stu.getAge());
}
}
@Test
public void treeSetTest01() {
// - 讓元素自身具備比較性。
Set set = new TreeSet();
set.add(new Student("b", 6));
set.add(new Student("e", 2));
set.add(new Student("d", 1));
set.add(new Student("c", 4));
set.add(new Student("a", 5));
set.add(new Student("e", 2));// 比較出來發現是0,不存
set.add(new Student("b", 1));
// 3,只能用迭代器取出
for (Iterator it = set.iterator(); it.hasNext();) {
Student stu = (Student) it.next();
System.out.println(stu.getName() + "::" + stu.getAge());
}
}
@Test
public void linkedHashSetTest01() {
Set set = new LinkedHashSet();
set.add("abc");
set.add("def");
set.add("ray");
// set.forEach(action);
// set.retainAll(set);//只保留交集,將c1和c2不同的元素從c1中刪除,保留c1中和c2相同的元素
/**
* 將一個順序執行的流轉變成一個併發的流只要調用 parallel()方法
*/
// set.parallelStream();
/**
* TODO 可拆分迭代器Spliterator
* 它和Iterator一樣也是用於遍歷數據源中的元素,但是他是爲並行執行而設計的。
* java8 所有數據結構都實現了 這個接口, 一般情況不需要自己寫實現代碼。
* 但是瞭解它的實現方式會讓你對並行流的工作原理有更深的瞭解。
*/
// set.spliterator();
for(Iterator it= set.iterator();it.hasNext();) {
System.out.println(it.next());
}
}
@Test
public void hashSetTest01() {
/**
* 練習,往HashSet中存儲學生對象(姓名,年齡)。同姓名,同年齡視爲同一個人,不存。
- 解:HashSet中存放自定義類型元素時,
需要重寫對象中的hashCode和equals方法,建立自己的比較方式,
才能保證HashSet集合中的對象唯一。
*/
// 1,創建容器對象
Set set = new HashSet();
// 2,存儲學生對象
set.add(new Student("xiaoqiang", 20));
set.add(new Student("wangcai", 27));
set.add(new Student("xiaoming", 22));
set.add(new Student("xiaoqiang", 20));
set.add(new Student("daniu", 24));
set.add(new Student("wangcai", 27));//如果Student 中不實現hash和equals方法,則無法判斷
// 3,獲取所有學生
for (Iterator it = set.iterator(); it.hasNext();) {
Student stu = (Student) it.next();
System.out.println(stu.getName() + "::" + stu.getAge());
}
}
/**
* - TODO 4、List集合存儲數據的結構
* List接口下有很多個集合,它們存儲元素所採用的結構方式是不同的,
* 這樣就導致了這些集合有它們各自的特點,供給我們在不同的環境下進行使用。
* - 數據存儲的常用結構有:堆棧、隊列、數組、鏈表。我們分別來了解一下
* - 堆棧
* - 先進後出
* - 棧的入口、出口都是棧的頂端位置。 <!--茶杯堆棧-->
* - 壓棧:就是存元素。
即把元素存儲到棧的頂端位置,棧中已有元素依次向棧底方向移動一個位置。
* - 彈棧:取元素
即把棧的頂端位置元素取出,棧中已有元素依次向棧頂方向移動一個位置。
* - 隊列
* - 先進先出
* - 隊列的入口、出口各佔一側。<!--水管隊列-->
* - 數組
* - 查找元素快 :通過索引可以快速訪問指定位置的元素
* - 增刪元素慢 :
* - 指定索引位置增加元素:
需要創建一個新數組,將指定新元素存儲在指定索引位置,
再把原數組元素根據索引,複製到新數組對應索引的位置上。
* - 指定索引位置刪除元素:
需要創建一個新數組,把原數組元素根據索引,
複製到新數組對應索引的位置,原數組中指定索引位置元素不復制到新數組中。
* - 鏈表
* - 多個節點:<!--環環相扣-->
* (它是由兩部分組成,數據域[存儲的數值]+指針域[存儲的地址])之間,
* 通過地址進行連接
* - 查找元素慢:
* - 想查找某個元素,需要通過連接的節點,依次向後查找指定元素。
* - 增刪元素快:
* - 增加元素:只需要修改連接下個元素的地址即可。
* - 刪除元素:只需要修改連接下個元素的地址即可。
*
* - TODO 5、List接口具體子類介紹
* - List
* - ArrayList:
* 底層的數據結構使用的是數組結構。
* - 特點:查詢速度很快,但是增刪稍慢。
* 線程不同步,並且替換了Vector。
* - LinkedList:
* 底層使用的是鏈表數據結構。
* - 特點:增刪速度很快,查詢稍慢,
* 並且是線程不同步的。
* - Vector:
* 底層是數組數據結構,數組是可變長度的
* (不斷的new新數組並將原數組元素複製到新數組中)。
* - 特點:線程同步,增刪和查詢速度都慢!並且被ArrayList替代了。
*
*
*/
@Test
public void linkedListTest01() {
/**
* - addFirst();→offerFirst();
addLast();→offerLast();
- getFirst();→peekFirst();
getLast();→peekLast();
- 獲取元素,但不刪除元素。如果集合中沒有元素,會返回null。
- removeFirst();→pollFirst();
removeLast();→pollLast();
- 獲取元素,但是元素被刪除。如果集合中沒有元素,會返回null。
*/
LinkedList link = new LinkedList();
link.addFirst("abc1");
link.add("abc2");
link.addFirst("abc3");
link.offerFirst("abc4");
System.out.println(link);
// 獲取元素,但不刪除元素。如果集合中沒有元素,會返回null。
System.out.println("link.peek():"+link.peek());
System.out.println("link.peekFirst():"+link.peekFirst());
// 獲取元素,但是元素被刪除。如果集合中沒有元素,會返回null。
System.out.println("link.removeFirst():"+link.removeFirst());
System.out.println("link.removeFirst():"+link.removeFirst());
// 倒序 取出link中所有元素
while (!link.isEmpty()) {
System.out.print("----"+link.removeLast());
// 正序 取出
// System.out.print("----"+link.removeFirst());
}
}
@Test
public void arrayListTest01() {
List list = new ArrayList();
/**
* 練習:定義功能,請除去ArrayList集合中的重複元素 */
list.add("abc1");
list.add("abc4");
list.add("abc2");
list.add("abc1");
list.add("abc4");
list.add("abc4");
list.add("abc2");
list.add("abc1");
list.add("abc4");
list.add("abc2");
System.out.println(list);
singleElement(list);//
System.out.println(list);
}
/**
* 練習 :去除ArrayList集合中重複的自定義元素。
* 將自定義對象作爲元素存到ArrayList集合中,
* 並去除重複元素。比如:存人對象。同姓名同年齡,視爲同一個人,爲重複元素。*/
@Test
public void arrayListTest02() {
Person p1 = new Person("fir",1);
Person p2 = new Person("sec",2);
Person p3 = new Person("list1",13);
Person p4 = new Person("list1",13);
List list = new ArrayList();
list.add(p1);
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
System.out.println(list);
// remove底層用的也是equals()
list.remove(new Person("fir",1));
singleElement(list);
System.out.println(list);
}
private void singleElement(List list) {
List itlist = new ArrayList();
for(ListIterator it = list.listIterator();it.hasNext();) {
Object obj = (Object) it.next();
// 通過arrayListTest02()可以看出 contains()底層用的是equals()
if(!itlist.contains(obj))
itlist.add(obj);
}
list.clear();
list.addAll(itlist);
}
/**
* - 3、List接口
* - 它是一個元素存取有序的集合。注意:有序指的是存入的順序和取出的順序一致。
* 例如,存元素的順序是11、22、33,那麼集合中元素的存儲就是按照11、22、33的順序完成的。
* - 它是一個帶有索引的集合。
* 通過索引就可以精確的操作集合中的元素(與數組的索引是一個道理)。
* - 集合中可以有重複的元素。
* 通過元素的equals方法,來比較是否爲重複的元素。
*
* - List接口中的特有方法上,
* 它的特有方法都是圍繞索引定義的。
*/
@Test
public void listTest() {
List al = new ArrayList();
al.add("java01");
al.add("java02");
al.add("java03");
//在指定位置添加元素
al.add(1, "java09");
sop(al);
//修改元素
al.set(2, "java007");
//刪除指定位置的元素
al.remove(0);
//通過角標獲取元素
al.get(1);
//返回列表中第一次出現的指定元素的索引
System.out.println("al.indexOf(\"java03\") : "+al.indexOf("java03"));
sop(al);
System.out.println("al="+al);
//--------返回列表中指定的部分視圖------這個好用
List sub = al.subList(1, 3);
System.out.println("sub="+sub);
/**
* ------------------------------------蠻重要的-----------------------------------------
* TODO 3、Iterator --- 再解釋
* - 在迭代時,只能用迭代器的方法操作元素,
* 可是Iterator的方法是有限的,
* 只能對元素進行判斷,取出,刪除的操作,
* 如果想要其他的操作如添加,修改等,
* 就需要使用其子接口listIterator——List集合特有的迭代器(listIterator)。
* 該接口只能通過List集合的listIterator()獲取。
*/
for(ListIterator it = al.listIterator();it.hasNext();) {
Object obj = it.next();
if(obj.equals("java007")) {
it.add("abcdefg");
}
}
System.out.println("al="+al);
}
/**
* - TODO 2、Iterator
* Iterator的初步解釋:
* 把取出方式定義在了集合的內部,
* 這樣取出方式就可以直接訪問集合內部的元素,
* 那麼取出方式就被定義成了內部類。
* 而每一個容器的數據結構不同,所以取出的動作細節也不一樣,
* 但是都有共性內容——判斷和取出,
* 那麼可以將這些共性抽取,那麼這些內部類都符合一個規則,該規則就是Iterator。
* - 如何獲取集合的取出對象呢?
* - 答:通過一個對外提供的方法:
* Iterator iterator()
* ——獲取集合中元素上迭代功能的迭代器對象
* (迭代器:具備着迭代功能的對象,而迭代器對象不需要new,直接通過iterator()方法獲取即可)。
* - Iterator接口中有如下2個重要方法:
* - boolean hasNext():
* 看看還有沒有被獲取到的元素。
* 如果沒有就返回false,如果有就返回true。
* - E next():
* 獲取當前光標下的元素,然後再將光標往下移一行。光標初始值是0,
* 而且每調用一次next()方法,光標都會往下移一行。
*/
@Test
public void iteratorTest() {
Collection al = new ArrayList();
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
// 開發時,這樣寫
for(
Iterator it = al.iterator();it.hasNext();) {
it.remove();
System.out.println(it.next());
// al.add("errorTest");
/**
* - 運行上述代碼發生了異常——java.util.ConcurrentModificationException
* [併發修改異常],這是什麼原因呢?
* - 原因:
* - 在使用迭代器或者增強for循環遍歷集合的時候,
* 再調用集合的方法修改集合的長度(添加和刪除 ),
* 就會發生併發修改異常。
* 也可以這樣說:
* - 在迭代過程中,使用了集合的方法對元素進行操作,
* 會導致迭代器並不知道集合中的變化,容易引發數據的不確定性。
* - 注意:併發修改異常是由next()方法拋出的。
*/
}
}
/**
* - 1、 集合中的最大接口——Collection
*/
@Test
public void test01() {
Collection c1 = new ArrayList();
/**
* 注意:
* - add方法的參數類型是Object,以便於接受任意類型。
* - 集合中存儲的都是對象的引用(地址)。
*/
c1.add("abc1");
c1.add("abc2");
c1.add("abc3");
/**
* - 注意:刪除元素會改變集合的長度
*/
c1.remove("abc2");
// coll.clear();//清空集合
System.out.println("abc1是否存在:"+c1.contains("abc1"));
System.out.println("集合是否爲空?"+c1.isEmpty());
/**
* - Collection接口中帶all的方法。兩個集合的互相操作
*/
Collection c2 = new ArrayList();
c2.add("abc2");
c2.add("abc3");
c2.add("abc5");
c1.addAll(c2);//往coll中添加coll2
boolean b = c1.containsAll(c2);
System.out.println("b = " + b);
c1.removeAll(c2);//移除交集
c1.retainAll(c2); //只保留交集,將c1和c2不同的元素從c1中刪除,保留c1中和c2相同的元素
}
@SuppressWarnings("unused")
private void sop(Collection c) {
for(Iterator it = c.iterator();it.hasNext();) {
System.out.println(it.next());
}
}
}
class Person{
/**
* 對Person類進行描述,將數據封裝到人對象中。
定義容器對象,將多個Person對象存儲到集合中。
去除同姓名同年齡的Person對象(重複元素)。
取出集合中的Person對象
*/
private String name;
private int age;
public Person() {}
public Person(String name, int age) {this.name = name;this.age = age;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
public boolean equals(Object obj) {
if(obj==this) {return true;}
if(!(obj instanceof Person)) {throw new ClassCastException("classtypeError");}
Person p = (Person) obj;
return (this.name.equals(p.name)) && (this.getAge()==p.getAge());
}
@Override
public String toString() {
return "Person [name="+name+", age="+age+"]";
}
}
// 滿足TreeSet的exercise,實現Comparable接口,實現compareTo()方法
@SuppressWarnings("rawtypes")
class Student implements Comparable{
/**
* 練習,往HashSet中存儲學生對象(姓名,年齡)。同姓名,同年齡視爲同一個人,不存。
解:HashSet中存放自定義類型元素時,需要重寫對象中的hashCode和equals方法,
建立自己的比較方式,才能保證HashSet集合中的對象唯一。
*/
private String name;
private int age;
public Student() {}
public Student(String name, int age) {super();this.name = name;this.age = age;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
/** 覆蓋hashCode方法,根據對象自身的特點定義哈希值。
*/
public int hashCode() {
final int NUMBER = 13;
return name.hashCode() + age * NUMBER; // 儘量減小哈希衝突
}
/**
* 還需要定義對象自身判斷內容相同的依據,覆蓋equals()方法。
*/
public boolean equals(Object obj) {
if (this == obj) {return true;}
if (!(obj instanceof Student)) {
throw new ClassCastException("類型錯誤");
}
Student stu = (Student) obj;
return this.name.equals(stu.name) && this.age == stu.age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Object o) {
Student stu = (Student) o;
// 驗證TreeSet集合的add()方法調用了compareTo()方法
// System.out.println("Student.compareTo():"+this.name + ":" + this.age + "......" + stu.name + ":" + stu.age) ;
// if(this.age > stu.age)
// return 1;
// if(this.age < stu.age)
// return -1;
//升序排序,如果 需要降序,加個負號
return this.age-stu.age==0 ? this.name.compareTo(stu.name) : this.age-stu.age;
}
}
/**
* TODO 自定義一個比較器,用來對學生對象按照姓名進行升序排序
* @author li ayun
*
*/
class ComparatorByName /*extends Object 繼承Object類覆蓋了equals()方法*/ implements Comparator {
@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student) o1;
Student s2 = (Student) o2;
int temp = s1.getName().compareTo(s2.getName());
return temp == 0 ? s1.getAge() - s2.getAge() : temp;
}
}
API之Collection集合
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.