思維導圖
Collection接口
容器:顧名思義,從字面上的理解就是能夠容納很多東西的器皿;
- 我們已經有各種各樣的變量了,難道那個就不是容器了嗎?
- 及時變量不夠,我們還有數組呢?
- 解答:一個人事管理系統,我們可以通過new很多個name變量來解決,但是如果這個系統有成千上萬個人呢?那我們是不是需要new成千上萬個name呢?當然不是,這樣也太可怕了。那有人會說,我們可以定義一個數組呢,但問題是你知道這個數組需要多大嗎?太大浪費內存空間,太小不夠裝怎麼辦?所有就有了容器這個概念的產生。
- 容器就是一個你需要多大就給你多大
數組與容器的區別:
數組元素既可以是基本類型的值,也可以是對象,而集合裏面只能保存對象(實際上保存的是引用類型的變量——。
本章重點(2136):二張圖,一個類,三個知識點,六個接口
一張圖:
- JDK所提供的容器API位於java.util包中;
- java的集合主要由兩個接口派生而成:Collection和Map,Collection和Map是java集合框架的根接口,這兩個接口又包含了一些子接口或實現類。
容器API的類圖結構如下:Collection體系集合:Set(無序集合)、List(有序集合)、Queue(隊列實現)
Map體系集合:用於保存具有映射關係的數據(共同的特徵是:都是鍵值對形式,通常鍵不可重複,值可以重複)
小結:可以將java中的集合分成三大類
一、Set(罐子):無順序不可重複——根據元素本身訪問
二、List(數組):有順序可變長度——根據元素索引訪問
三、Map(罐子):每項數據兩個值——根據元素Key訪問
Collection接口定義了存取一組對象的方法,其子接口set和list分別定義了存儲的方式:
- set中的數據對象沒有順序且可以重複;
- list中的數據對象有順序且可以重複;
- map接口定義了存儲鍵值映射對的方法。
Collection接口中所定義的方法:(容器跟生活生活中的容器無異,無非都是添加、刪除、清空、判斷容器是否爲空)
Boolean add(Object o) |
向集合裏添加一個元素,改變則返回true |
Boolean addAll(Object c) |
向集合c裏的所有元素添加到指定集合,指定集合改變返回true |
Void clear() |
清除集合裏所有元素,集合長度變爲0 |
Boolean contains(Object o) |
返回集合裏是否包含指定元素 |
Boolean containsAll(Object 哦) |
返回集合裏是否包含集合c裏的所有元素 |
Boolean isEmpty() |
返回集合是否爲空,集合長度爲0時返回true,否則返回false |
Boolean remove(Object o) |
刪除集合裏指定元素o,有多個o時只刪除一個符合條件的,返回true |
Iterator iterator() |
返回一個iterator對象,用於遍歷集合裏的元素 |
Boolean removeAll(Collection c) |
從集合中刪除集合c包含的所有元素,如果刪除一個或一個以上返回true |
Boolean retainAll(Collection c) |
從集合中刪除集合c裏面不包含的元素,如該操作改變了調用該方法的集合,則該方法返回true |
Int size() |
該方法返回集合元素的個數 |
Object[] toArray() |
該方法把集合轉換成一個數組,所有集合元素都變成了對應的數組元素 |
實例代碼:
import java.util.*;
public class TestCollection{
@SuppressWarnings("unchecked")
public static void main(String[] args){
Collection c = new ArrayList();
c.add("Hello");
c.add(new Name("f1","11"));
c.add(new Integer(100));
System.out.println(c.size());
System.out.println(c);
}
}
class Name{
private String firstName,lastName;
public Name(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public String toString(){
return firstName + "" + lastName;
}
}
輸出結果:
異常解決:
原因:這個是1.5以後的版本纔會有這個警告提示,主要是警告用戶沒有使用泛型來限制集合裏的元素類型
解決:可以在class類裏面加上這句代碼就可以了或者不用管他。
@SuppressWarnings("unchecked")
Collection方法舉例:
- 容器類對象再調用remove、contains等方法時需要比較對象是否相等,這個會涉及到對象類類型的equals方法和hashCode方法;對於自定義的類型需要重寫equals和hashCode方法實現自定義的對象相等規則。
- 注意:相等的對象應該具有相等hash codes。
- 增加Name類的equals和hashCode方法如下:
實例代碼:
import java.util.*;
public class TestCollection{
@SuppressWarnings("unchecked")
public static void main(String[] args){
Collection c = new HashSet();
c.add("Hello");
c.add(new Name("f1","11"));
c.add(new Integer(100));
c.remove("Hello");
c.remove(new Integer(100));
System.out.println(c.remove(new Name("f1","11")));
System.out.println(c);
}
}
class Name{
private String firstName,lastName;
public Name(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public String toString(){
return firstName + "" + lastName;
}
public boolean equals(Object obj){
if(obj instanceof Name){
Name name = (Name)obj;
return(firstName.equals(name.firstName)) && (lastName.equals(name.lastName));
}
return super.equals(obj);
}
public int hashCode(){
return firstName.hashCode();
}
}
輸出結果:如果沒有添加equals和hashCode方法時無法移除f1和11的
添加這兩個方法後的結果如下:
Iterator接口
- Iterator接口是Collection接口的父接口,因此Collection集合也可以直接調用該方法;
- Collection系列集合、Map系列集合主要用於盛裝其他對象,而Iterator主要用於遍歷Collection集合中的元素;
- 所有實現Collection接口的容器類都有一個Iterator方法用以返回一個實現了Iterator接口的對象;
- Iterator對象稱作迭代器,用以方便的實現對容器內元素的遍歷操作;
- Iterator接口定義瞭如下方法:
- Boolean hasNext();//判斷遊標右邊是否有元素
- Object next();//返回遊標右邊的元素並將遊標移動到下一個位置
- Void remove();//刪除遊標左面的元素,在執行完next之後該操作只執行一次。
- Void forEachRemaining(Consumer action)java8新增
實例代碼:
import java.util.*;
public class TestCollection{
@SuppressWarnings("unchecked")
public static void main(String[] args){
Collection c = new HashSet();
c.add(new Name("f1","11"));
c.add(new Name("f2","12"));
c.add(new Name("f3","13"));
Iterator i = c.iterator();
while(i.hasNext()){
Name n = (Name)i.next();
System.out.println(n.getFirstName()+" ");
}
}
}
class Name{
private String firstName,lastName;
public Name(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public String toString(){
return firstName + "" + lastName;
}
public boolean equals(Object obj){
if(obj instanceof Name){
Name name = (Name)obj;
return(firstName.equals(name.firstName)) && (lastName.equals(name.lastName));
}
return super.equals(obj);
}
public int hashCode(){
return firstName.hashCode();
}
}
輸出結果:
Iterator對象的remove方法時在迭代過程中刪除元素的唯一的安全方法
實例代碼:
import java.util.*;
public class TestCollection{
@SuppressWarnings("unchecked")
public static void main(String[] args){
Collection c = new HashSet();
c.add(new Name("f111","1111"));
c.add(new Name("f2222","12"));
c.add(new Name("f3","11113"));
for(Iterator i = c.iterator();i.hasNext();){
Name n = (Name)i.next();
if(name.getFirstName().length()<3){
i.remove();
}
}
System.out.println(c);
}
}
class Name{
private String firstName,lastName;
public Name(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public String toString(){
return firstName + "" + lastName;
}
public boolean equals(Object obj){
if(obj instanceof Name){
Name name = (Name)obj;
return(firstName.equals(name.firstName)) && (lastName.equals(name.lastName));
}
return super.equals(obj);
}
public int hashCode(){
return firstName.hashCode();
}
}
Set接口
- set接口是collection的子接口,set接口沒有提供額外的方法,但實現set接口的容器類中的元素是沒有順序的,而且不可用重複;
- set容器可以與數學中的集合的概念相對應;
- Jdk API中的所提供的set容器類有HashSet,TreeSet等。
實例代碼:
import java.util.*;
public class TestCollection{
@SuppressWarnings("unchecked")
public static void main(String[] args){
Set c = new HashSet();
c.add("hello");
c.add("world");
c.add(new Name("f1","f2"));
c.add(new Integer(100));
c.add(new Name("f1",",f2"));
c.add("hello");
System.out.println(c);
}
}
class Name{
private String firstName,lastName;
public Name(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public String toString(){
return firstName + "" + lastName;
}
public boolean equals(Object obj){
if(obj instanceof Name){
Name name = (Name)obj;
return(firstName.equals(name.firstName)) && (lastName.equals(name.lastName));
}
return super.equals(obj);
}
public int hashCode(){
return firstName.hashCode();
}
}
輸出結果:
List接口
- list接口是collection的子接口,實現list接口的容器類中的元素是有順序的,而且可以重複;
- list容器中的元素都對應一個整數型的序列號記載其在容器中的位置,可以根據序號存取容器中的元素;
- jdk所提供的list容器類有ArrayList(數組),linkedlist(鏈表)等
實例代碼:
import java.util.*;
public class TestList{
@SuppressWarnings("unchecked")
public static void main(String[] args){
List l1 = new LinkedList();
for(int i=0;i<=5;i++){
l1.add("a" + i);
}
System.out.println(l1);
l1.add(3,"a100");
System.out.println(l1);
l1.set(6,"a200");
System.out.println(l1);
System.out.println((String)l1.get(2)+"");
System.out.println(l1.indexOf("a3"));
l1.remove(1);
System.out.println(l1);
}
}
輸出結果:
List常用算法
一個類
- 類java.util.Collections提供了一些靜態方法實現了基於List容器的一些常用算法。
- void sort(List)對list容器內的元素排序;
- void shuffle(List)對list容器內的對象進行隨機排序;
- void reverse(List)對list容器內的對象進行你排序;
- void fill(List,Object)用一個特定的對象重寫整個list容器;
- void copy(List dest,List src)將src List容器內容拷貝到dest List容器;
- int binarySearch(List,Object)對於順序的List容器,採用折半查找的方法查找特定的對象
Comparable 接口
- 問題:上面的算法根據什麼確定容器中對象的大小順序?
- 所有可以排序的類都實現了java.lang.Comparable接口,Comparable接口中只有一個方法:public int compareTo(Object obj);該方法:返回0表示this==obj;返回正數表示this>obj;返回負數表示this<obj
- 實現了comparable接口的類通過實現comparaTo方法從而確定該類對象的排序方式。
如何選擇數據結構:
衡量標準:讀的效率和改的效率
- Array讀快改慢
- Linked改快讀慢
- Hash兩者之間
Map接口
- 實現Map接口的類用來存儲鍵值對;
- Map 接口的實現有HashMap和TreeMap等;
- Map類中存儲的鍵值對通過建來表示,所以鍵值不能重複(說的是equals)。
1 |
void clear( ) 從此映射中移除所有映射關係(可選操作)。 |
2 |
boolean containsKey(Object k) 如果此映射包含指定鍵的映射關係,則返回 true。 |
3 |
boolean containsValue(Object v) 如果此映射將一個或多個鍵映射到指定值,則返回 true。 |
4 |
Set entrySet( ) 返回此映射中包含的映射關係的 Set 視圖。 |
5 |
boolean equals(Object obj) 比較指定的對象與此映射是否相等。 |
6 |
Object get(Object k) 返回指定鍵所映射的值;如果此映射不包含該鍵的映射關係,則返回 null。 |
7 |
int hashCode( ) 返回此映射的哈希碼值。 |
8 |
boolean isEmpty( ) 如果此映射未包含鍵-值映射關係,則返回 true。 |
9 |
Set keySet( ) 返回此映射中包含的鍵的 Set 視圖。 |
10 |
Object put(Object k, Object v) 將指定的值與此映射中的指定鍵關聯(可選操作)。 |
11 |
void putAll(Map m) 從指定映射中將所有映射關係複製到此映射中(可選操作)。 |
12 |
Object remove(Object k) 如果存在一個鍵的映射關係,則將其從此映射中移除(可選操作)。 |
13 |
int size( ) 返回此映射中的鍵-值映射關係數。 |
14 |
Collection values( ) 返回此映射中包含的值的 Collection 視圖。 |
實例代碼:(含自動打包和解包)
import java.util.*;
public class TestMap{
@SuppressWarnings("unchecked")
public static void main(String[] args){
Map m1 = new HashMap();
Map m2 = new HashMap();
m1.put("one",1);
m1.put("two",2);
m1.put("three",3);
m2.put("A",1);
m2.put("B",2);
System.out.println(m1.size());
System.out.println(m1.containsKey("one"));
System.out.println(m2.containsValue(1));
if(m1.containsKey("two")){
int i = (Integer)m1.get("two");
System.out.println(i);
}
Map m3 = new HashMap(m1);
m3.putAll(m2);
System.out.println(m3);
}
}
輸出結果:
實例代碼:
import java.util.*;
public class TestArgsWords{
private static final Integer ONE = new Integer(1);
@SuppressWarnings("unchecked")
public static void main(String[] args){
Map m = new HashMap();
for(int i=0;i<args.length;i++){
Integer freq = (Integer)m.get(args[i]);
m.put(args[i],(freq==null ? ONE : new Integer(freq.intValue()+1)));
}
System.out.println(m.size()+"distinct words detected:");
System.out.println(m);
}
}
輸出結果:
實例代碼:(採用打包解包的形式寫)
import java.util.*;
public class TestArgsWords{
private static final Integer ONE = new Integer(1);
@SuppressWarnings("unchecked")
public static void main(String[] args){
Map m = new HashMap();
for(int i=0;i<args.length;i++){
//Integer freq = (Integer)m.get(args[i]);
int freq = (Integer)m.get(args[i])==null ? 0 : (Integer)m.get(args[i]);
//m.put(args[i],(freq==null ? ONE : new Integer(freq.intValue()+1)));
m.put(args[i],freq == 0 ? ONE : freq + 1);
}
System.out.println(m.size()+"distinct words detected:");
System.out.println(m);
}
}
輸出結果:
泛型
java集合的缺點是——把一個對象丟進集合裏面之後,集合就會忘記這個對象的數據類型,當再次取出該對象時,該對象的編譯類型就變成了Object類型(運行時類型沒有變)。
java集合被設計成這樣主要是因爲設計者不知道我們會用集合來裝什麼類型的對象,所以設計成了可以裝任何類型的對象。
因此存在兩個問題:
一、集合對元素的類型沒有任何的限制,如果我只想裝Dog對象,程序可以輕易的將Cat對象丟進去;
二、將對象丟進集合時,集合丟失了對象的狀態信息,集合只知道他裝的是Object,因此取來的時候需要強制轉換。
所謂泛型:就是允許在定義類、接口、方法時使用類型形參,這個類型形參將在聲明變量、創建對象、調用方法時動態的指定。
實例代碼:
import java.util.*;
public class BasicGeneric{
@SuppressWarnings("unchecked")
public static void main(String[] args){
List<String> c = new ArrayList<String>();
c.add("aaa");
c.add("bbb");
c.add("ccc");
for(int i=0;i<c.size();i++){
String s = c.get(i);
System.out.println(s);
}
Collection<String> c2 = new HashSet<String>();
c2.add("aaa");
c2.add("bbb");
c2.add("ccc");
for(Iterator<String> it = c2.iterator();it.hasNext();){
String s = it.next();
System.out.println(s);
}
}
}
class MyName implements Comparable<MyName>{
int age;
public int compareTo(MyName mn){
if(this.age > mn.age)return 1;
else if(this.age < mn.age)return -1;
else return 0;
}
}
輸出結果: