Java常用物件API——集合(框架、Collection集合、List集合、Set集合)
集合框架
集合類
集合物件用於封裝特有資料,物件多了需要儲存,如果物件的個數不確定。 就使用集合容器進行儲存。
集合特點: 1,用於儲存物件的容器。 2,集合的長度是可變的。 3,集合中不可以儲存基本資料型別值。
集合容器因為內部的資料結構不同,有多種具體容器。 不斷的向上抽取,就形成了集合框架。
框架的頂層Collection介面:
Collection的常見方法:
1,新增。 boolean add(Object obj): boolean addAll(Collection coll):
2,刪除。 boolean remove(object obj): boolean removeAll(Collection coll); void clear();
3,判斷: boolean contains(object obj): boolean containsAll(Colllection coll); boolean isEmpty():判斷集合中是否有元素。
4,獲取: int size(): Iterator iterator():取出元素的方式:迭代器。 該物件必須依賴於具體容器,因為每一個容器的資料結構都不同。 所以該迭代器物件是在容器中進行內部實現的。 對於使用容器者而言,具體的實現不重要,只要通過容器獲取到該實現的迭代器的物件即可, 也就是iterator方法。
Iterator介面就是對所有的Collection容器進行元素取出的公共介面。 其實就是抓娃娃遊戲機中的夾子!
常用方法使用演示:
import java.util.ArrayList; import java.util.Collection; public class CollectionDemo { public static void main(String[] args) { Collection coll = new ArrayList(); // show(coll); Collection c1 = new ArrayList(); Collection c2 = new ArrayList(); show(c1,c2); } public static void show(Collection c1,Collection c2){ //給c1新增元素。 c1.add("abc1"); c1.add("abc2"); c1.add("abc3"); c1.add("abc4"); //給c2新增元素。 c2.add("abc1"); c2.add("abc2"); c2.add("abc3"); c2.add("abc4"); c2.add("abc5"); System.out.println("c1:"+c1); System.out.println("c2:"+c2); //演示addAll // c1.addAll(c2);//將c2中的元素新增到c1中。 //演示removeAll // boolean b = c1.removeAll(c2);//將兩個集合中的相同元素從呼叫removeAll的集合中刪除。 // System.out.println("removeAll:"+b); //演示containsAll // boolean b = c1.containsAll(c2); // System.out.println("containsAll:"+b); //演示retainAll boolean b = c1.retainAll(c2);//取交集,保留和指定的集合相同的元素,而刪除不同的元素。 //和removeAll功能相反 。 System.out.println("retainAll:"+b); System.out.println("c1:"+c1); } public static void show(Collection coll){ //1,新增元素。add. coll.add("abc1"); coll.add("abc2"); coll.add("abc3"); System.out.println(coll); //2,刪除元素。remove // coll.remove("abc2");//會改變集合的長度 //清空集合. // coll.clear(); System.out.println(coll.contains("abc3")); System.out.println(coll); } }
迭代器使用演示:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo {
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
coll.add("abc4");
// System.out.println(coll);
//使用了Collection中的iterator()方法。 呼叫集合中的迭代器方法,是為了獲取集合中的迭代器物件。
// Iterator it = coll.iterator();
// while(it.hasNext()){
// System.out.println(it.next());
// }
for(Iterator it = coll.iterator(); it.hasNext(); ){ //常用
System.out.println(it.next());
}
// System.out.println(it.next());
// System.out.println(it.next());
// System.out.println(it.next());
// System.out.println(it.next());
// System.out.println(it.next());//java.util.NoSuchElementException
}
}
執行結果 小結:it.next();用來取出集合中的下一個元素(it為某個集合物件) it.hasNext();用來判斷集合中是否還有下一個元素
Collection框架 |–List:有序(存入和取出的順序一致),元素都有索引(角標),元素可以重複。 |–Set:元素不能重複,無序。
List集合
特有的常見方法
有一個共性特點就是都可以操作角標 1,新增 void add(index,element); void add(index,collection);
2,刪除; Object remove(index): //返回值是被刪除的元素
3,修改: Object set(index,element);
4,獲取: Object get(index); int indexOf(object); int lastIndexOf(object); List subList(from,to);//包頭不包尾
由上看出,list集合可以完成對元素的增刪改查。
listIterator類
列表迭代器,它可以實現在迭代過程中完成對元素的增刪改查 舉例
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class ListDemo2 {
public static void main(String[] args) {
List list = new ArrayList();
// show(list);
list.add("abc1");
list.add("abc2");
list.add("abc3");
System.out.println("list:"+list);
ListIterator it = list.listIterator();//獲取列表迭代器物件
//它可以實現在迭代過程中完成對元素的增刪改查。
//注意:只有list集合具備該迭代功能.
while(it.hasNext()){
Object obj = it.next();
if(obj.equals("abc2")){
it.set("abc9");
//it.add("abc9");
}
}
// System.out.println("hasNext:"+it.hasNext());
// System.out.println("hasPrevious:"+it.hasPrevious());
while(it.hasPrevious()){ //逆序
System.out.println("previous:"+it.previous());
}
System.out.println("list:"+list);
/*Iterator it = list.iterator(); //這是異常舉例
while(it.hasNext()){
Object obj = it.next();//java.util.ConcurrentModificationException
//在迭代器過程中,不要使用集合操作元素,容易出現異常。
//可以使用Iterator介面的子介面ListIterator來完成在迭代中對元素進行更多的操作。
if(obj.equals("abc2")){
list.add("abc9");
}
else
System.out.println("next:"+obj);
}
System.out.println(list);
*/
}
public static void show(List list) {
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
Iterator it = list.iterator(); // 通用的取出方式
while(it.hasNext()){
System.out.println("next:"+it.next());
}
//list特有的取出元素的方式之一。
for(int x=0; x<list.size(); x++){
System.out.println("get:"+list.get(x));
}
}
}
List常用子類的特點
List: |–Vector:內部是陣列資料結構,是同步的。增刪,查詢都很慢! |–ArrayList:內部是陣列資料結構,是不同步的。替代了Vector。查詢的速度快。 |–LinkedList:內部是連結串列資料結構,是不同步的。增刪元素的速度很快。
Vector集合
陣列資料結構。增刪,查詢都很慢。
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
public class VectorDemo {
public static void main(String[] args) {
Vector v = new Vector();
v.addElement("abc1");
v.addElement("abc2");
v.addElement("abc3");
v.addElement("abc4");
Enumeration en = v.elements(); //返回此向量的列舉 此介面的功能與迭代器是重複的
while(en.hasMoreElements()){
System.out.println("nextelment:"+en.nextElement());
}
Iterator it = v.iterator(); //優先考慮Iterator介面,保證了閱讀性和簡單
while(it.hasNext()){
System.out.println("next:"+it.next());
}
}
}
LinkedList
連結串列資料結構,增刪元素的速度很快。
import java.util.Iterator;
import java.util.LinkedList;
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList link = new LinkedList();
link.addFirst("abc1"); //新增到表頭位置
link.addFirst("abc2");
link.addFirst("abc3");
link.addFirst("abc4");
// System.out.println(link);
// System.out.println(link.getFirst());//獲取第一個但不刪除。
// System.out.println(link.getFirst());
// System.out.println(link.removeFirst());//獲取元素但是會刪除。
// System.out.println(link.removeFirst());
while(!link.isEmpty()){
System.out.println(link.removeLast());
}
System.out.println(link);
// Iterator it = link.iterator();
// while(it.hasNext()){
// System.out.println(it.next());
// }
}
}
練習:堆疊與佇列
-
請使用LinkedList來模擬一個堆疊或者佇列資料結構。
-
堆疊:先進後出 First In Last Out FILO
-
佇列:先進先出 First In First Out FIFO
-
我們應該描述這樣一個容器,給使用提供一個容器物件完成這兩種結構中的一種。
package cn.itcast.p2.linkedlist.test; import java.util.LinkedList; public class DuiLie { //先進先出 private LinkedList link; public DuiLie() { link = new LinkedList(); //使用建構函式來進行初始化 } /** * 佇列的新增元素的功能。若改成棧,則addFirst即可 */ public void myAdd(Object obj) { link.addLast(obj); } public Object myGet() { return link.removeFirst(); } public boolean isNull() { return link.isEmpty(); } }
package cn.itcast.p2.linkedlist.test;
import java.util.ArrayList;
public class LinkedTest {
public static void main(String[] args) {
DuiLie dl = new DuiLie();
dl.myAdd("abc1");
dl.myAdd("abc2");
dl.myAdd("abc3");
dl.myAdd("abc4");
while(!dl.isNull()){
System.out.println(dl.myGet());
}
}
}
1.6版本新特性
LinkedList:
addFirst(); addLast(): jdk1.6 offerFirst(); offetLast();
getFirst();.//獲取但不移除,如果連結串列為空,丟擲NoSuchElementException. getLast(); jdk1.6 peekFirst();//獲取但不移除,如果連結串列為空,返回null. peekLast():
removeFirst();//獲取並移除,如果連結串列為空,丟擲NoSuchElementException. removeLast();` jdk1.6 pollFirst();//獲取並移除,如果連結串列為空,返回null. pollLast();
ArrayList
package cn.itcast.p3.arraylist.test;
import java.util.ArrayList;
import java.util.Iterator;
import cn.itcast.p.bean.Person; //這是一個已經定義過的類
public class ArrayListTest {
public static void main(String[] args) {
Person p1 = new Person("lisi1",21);
ArrayList al = new ArrayList();
al.add(p1);
al.add(new Person("lisi2",22));
al.add(new Person("lisi3",23));
al.add(new Person("lisi4",24));
Iterator it = al.iterator();
while(it.hasNext()){
// System.out.println(((Person) it.next()).getName()+"::"+((Person) it.next()).getAge()); //不能在一次迴圈語句中用兩次next
Person p = (Person) it.next();
System.out.println(p.getName()+"--"+p.getAge());
}
// al.add(5);//al.add(new Integer(5)); //自動裝箱
}
}
Set集合
Set:元素不可以重複,是無序。 Set介面中的方法和Collection一致。 常用子類特點: |–HashSet: 內部資料結構是雜湊表 ,是不同步的。 |–TreeSet:可以對Set集合中的元素進行排序。是不同步的。
HashSet
內部資料結構是雜湊表 ,是不同步的。
如何保證該集合的元素唯一性呢? 是通過物件的hashCode和equals方法來完成物件唯一性的。 如果物件的hashCode值不同,那麼不用判斷equals方法,就直接儲存到雜湊表中。 如果物件的hashCode值相同,那麼要再次判斷物件的equals方法是否為true。 如果為true,視為相同元素,不存。如果為false,那麼視為不同元素,就進行儲存。 記住:如果元素要儲存到HashSet集合中,必須覆蓋hashCode方法和equals方法。 一般情況下,如果定義的類會產生很多物件,比如人,學生,書,通常都需要覆蓋equals,hashCode方法。 建立物件判斷是否相同的依據。
演示:
package cn.itcast.p4.hashset.demo;
import java.util.HashSet;
import java.util.Iterator;
public class HashSetDemo {
/**
* @param args
*/
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add("hehe");
// hs.add("heihei");
hs.add("hahah");
hs.add("xixii");
hs.add("hehe"); //由於元素唯一性,無法再存入
Iterator it = hs.iterator();
while(it.hasNext()){
System.out.println(it.next()); 不保證有序性
}
}
}
HashSet儲存自定義物件
往hashSet集合中儲存Person物件(帶有姓名和年齡引數)。如果姓名和年齡相同,視為同一個人。視為相同元素。這需要讓Person物件自定義一個hashCode方法。
@Override
public int hashCode() { //自定義
return name.hashCode()+age*27;
}
@Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(!(obj instanceof Person))
throw new ClassCastException("型別錯誤");
// System.out.println(this+"....equals....."+obj);
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
test部分
import java.util.HashSet;
import java.util.Iterator;
import cn.itcast.p.bean.Person;
public class HashSetTest {
public static void main(String[] args) {
HashSet hs = new HashSet();
/*
* HashSet集合資料結構是雜湊表,所以儲存元素的時候,
* 使用的元素的hashCode方法來確定位置,如果位置相同,在通過元素的equals來確定是否相同。
*
*/
hs.add(new Person("lisi4",24));
hs.add(new Person("lisi7",27));
hs.add(new Person("lisi1",21));
hs.add(new Person("lisi9",29));
hs.add(new Person("lisi7",27)); //同一個人
Iterator it = hs.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println(p);
// System.out.println(p.getName()+"...."+p.getAge());
}
}
}
練習
定義功能去除ArrayList中的重複元素。
public class ArrayListTest2 {
public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add(new Person("lisi1",21));
al.add(new Person("lisi2",22));
al.add(new Person("lisi3",23));
al.add(new Person("lisi4",24));
al.add(new Person("lisi2",22));
al.add(new Person("lisi3",23));
System.out.println(al);
al = getSingleElement(al);
System.out.println(al.remove(new Person("lisi2",22)));
System.out.println(al);
}
public static ArrayList getSingleElement(ArrayList al) {
//1,定義一個臨時容器。
ArrayList temp = new ArrayList();
//2,迭代al集合。
Iterator it = al.iterator();
while(it.hasNext()){
Object obj = it.next();
//3,判斷被迭代到的元素是否在臨時容器存在。
if(!temp.contains(obj)){
temp.add(obj);
}
}
return temp;
}
}
當Person類中的equals方法沒有進行覆蓋時,執行結果如下: 當對Person類中的equals方法覆蓋時——
@Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(!(obj instanceof Person))
throw new ClassCastException("型別錯誤");
Person p = (Person)obj; //對於該物件,應該比較的是姓名與年齡
return this.name.equals(p.name) && this.age == p.age; }
執行結果如下: 由此可以得出結論:使用contains與remove方法時,都是依賴於該物件的equals方法去判斷是否存在相同物件的。 當Person的equals方法沒有被覆蓋時,那麼就繼承了Object類的equals方法,則比較的是引用型別的變數所指向的物件的地址,在本例下,即使兩個物件的引數相同,但是由於地址不同,則並不會被判定為相同物件。
LinkedHashSet
當需要保證唯一與有序兼顧時,使用這個子類就行了。
TreeSet
可以對Set集合中的元素進行排序。是不同步的。
判斷元素唯一性的方式:就是根據比較方法的返回結果是否是0,是0,就是相同元素,不存。
TreeSet對元素進行排序的方式一: 讓元素自身具備比較功能,就需要實現Comparable介面。覆蓋compareTo方法(自然排序)。 如果不按照物件中具備的自然順序進行排序,或物件中不具備自然順序。怎麼辦? 可以使用TreeSet集合第二種排序方式二: 讓集合自身具備比較功能,定義一個類實現Comparator介面,覆蓋compare方法。將該類物件作為引數傳遞給TreeSet集合的建構函式。
方式一:實現Comparable介面,覆蓋compareTo方法
//這是Person類的一部分
@Override
public int compareTo(Object o) {
Person p = (Person)o;
int temp = this.age-p.age;
return temp==0?this.name.compareTo(p.name):temp;
/* if(this.age>p.age) //有強轉,健壯性判斷
return 1;
if(this.age<p.age)
return -1;
else{
return this.name.compareTo(p.name);
}*/ 這是另一種寫法
Demo
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
/*
以Person物件年齡進行從小到大的排序。
*/
ts.add(new Person("zhangsan",28));
ts.add(new Person("lisi",21));
ts.add(new Person("zhouqi",29));
ts.add(new Person("zhaoliu",25));
ts.add(new Person("wangu",24));
Iterator it = ts.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
}
執行結果
方式二:Comparator比較器
覆蓋compare方法。
import java.util.Comparator;
import cn.itcast.p.bean.Person;
/**
* 建立了一個根據Person類的name進行排序的比較器。
*/
public class ComparatorByName implements Comparator {
@Override
public int compare(Object o1, Object o2) {
Person p1 = (Person)o1;
Person p2 = (Person)o2;
int temp = p1.getName().compareTo(p2.getName());
return temp==0?p1.getAge()-p2.getAge(): temp;
// return 1;//有序。
}
}
TreeSet ts = new TreeSet(new ComparatorByName()); 將比較器類物件作為引數傳遞給TreeSet集合的建構函式。
示例:對字串進行長度排序
這種情況是不能使用字串的自然排序,所以要用到比較器。
import java.util.Comparator;
public class ComparatorByLength implements Comparator { //比較器
@Override
public int compare(Object o1, Object o2) {
String s1 = (String)o1;
String s2 = (String)o2;
int temp = s1.length()-s2.length();
return temp==0? s1.compareTo(s2): temp;
}
}
/*
-
對字串進行長度排序。 */
import java.util.Iterator; import java.util.TreeSet; import cn.itcast.p5.comparator.ComparatorByLength; public class TreeSetTest { /** * @param args */ public static void main(String[] args) { TreeSet ts = new TreeSet(new ComparatorByLength()); ts.add("aaaaa"); ts.add("zz"); ts.add("nbaq"); ts.add("cba"); ts.add("abc"); Iterator it = ts.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } }