官术网_书友最值得收藏!

任務1 查詢標題

關鍵步驟如下。

  • 創建集合對象,并添加數據。
  • 統計新聞標題總數量。
  • 輸出新聞標題名稱。

1.1.1 認識集合

開發應用程序時,如果想存儲多個同類型的數據,可以使用數組來實現;但是使用數組存在如下一些明顯缺陷:

  • 數組長度固定不變,不能很好地適應元素數量動態變化的情況。
  • 可通過數組名.length獲取數組的長度,卻無法直接獲取數組中實際存儲的元素個數。
  • 數組采用在內存中分配連續空間的存儲方式存儲,根據元素信息查找時效率比較低,需要多次比較。

從以上分析可以看出數組在處理一些問題時存在明顯的缺陷,針對數組的缺陷,Java提供了比數組更靈活、更實用的集合框架,可大大提高軟件的開發效率,并且不同的集合可適用于不同應用場合。

Java集合框架提供了一套性能優良、使用方便的接口和類,它們都位于java.util包中,其主要內容及彼此之間的關系如圖1.1所示。

0

圖1.1 Java集合框架圖

從圖1.1中可以看出,Java的集合類主要由Map接口和Collection接口派生而來,其中Collection接口有兩個常用的子接口,即List接口和Set接口,所以通常說Java集合框架由3大類接口構成(Map接口、List接口和Set接口)。本章講解的主要內容就是圍繞這3大類接口進行的。

注意

虛線框表示接口或者抽象類,實線框表示開發中常用的實現類。

1.1.2 List接口

Collection接口是最基本的集合接口,可以存儲一組不唯一、無序的對象。List接口繼承自Collection接口,是有序集合。用戶可使用索引訪問List接口中的元素,類似于數組。List接口中允許存放重復元素,也就是說List可以存儲一組不唯一、有序的對象。

List接口常用的實現類有ArrayList和LinkedList。

1. 使用ArrayList類動態存儲數據

針對數組的一些缺陷,Java集合框架提供了ArrayList集合類,對數組進行了封裝,實現了長度可變的數組,而且和數組采用相同的存儲方式,在內存中分配連續的空間,如圖1.2所示,所以,經常稱ArrayList為動態數組。但是它不等同于數組,ArrayList集合中可以添加任何類型的數據,并且添加的數據都將轉換成Object類型,而在數組中只能添加同一數據類型的數據。

0

圖1.2 ArrayList存儲方式示意圖

ArrayList類提供了很多方法用于操作數據,如表1-1中列出的是ArrayList類的常用方法。

表1-1 ArrayList類的常用方法

0

示例1

使用ArrayList常用方法動態操作數據。

實現步驟如下。

(1)導入ArrayList類。

(2)創建ArrayList對象,并添加數據。

(3)判斷集合中是否包含某元素。

(4)移除索引為0的元素。

(5)把索引為1的元素替換為其他元素。

(6)輸出某個元素所在的索引位置。

(7)清空ArrayList集合中的數據。

(8)判斷ArrayList集合中是否包含數據。

關鍵代碼:

0

在示例1中,① 的代碼調用ArrayList的無參構造方法,創建集合對象。常用的ArrayList類的構造方法還有一個帶參數的重載版本,即ArrayList(int initialCapacity),它構造一個具有指定初始容量的空列表。

② 的代碼將list集合中索引為0的元素刪除,list集合的下標是從0開始,也就是刪除了“張三豐”,集合中現有元素為“郭靖”和“楊過”。

③ 的代碼將list集合中索引為1的元素替換為“黃蓉”,即將“楊過”替換為“黃蓉”,集合中現有元素為“郭靖”和“黃蓉”。

④ 的代碼是使用for循環遍歷集合,輸出集合中的所有元素。list.get(i)取出集合中索引為i的元素,并強制轉換為String類型。

⑤ 的代碼為輸出元素“小龍女”所在的索引位置,因集合中沒有該元素,所以輸出結果為-1。

⑥ 的代碼是使用增強for循環遍歷集合,輸出集合中的所有元素。增強for循環的語法在Java基礎課程中講過,這里不再贅述。可以看出,遍歷集合時使用增強for循環比普通for循環在寫法上更加簡單方便,而且不用考慮下標越界的問題。

⑦ 的代碼用來判斷list集合是否為空,因為前面執行了list.clear()操作,所以集合已經為空,輸出為true。

注意

① 調用ArrayList類的add(Object obj)方法時,添加到集合當中的數據將被轉換為Object類型。

② 使用ArrayList類之前,需要導入相應的接口和類,代碼如下:

import java.util.ArrayList;
import java.util.List;

示例2

使用ArrayList集合存儲新聞標題信息(包含ID、名稱、創建者),輸出新聞標題的總數量及每條新聞標題的名稱。

實現步驟如下。

(1)創建ArrayList對象,并添加數據。

(2)獲取新聞標題的總數。

(3)遍歷集合對象,輸出新聞標題名稱。

關鍵代碼:

//創建新聞標題對象,NewTitle為新聞標題類
NewTitle car=new NewTitle(1, "汽車", "管理員");
NewTitle test=new NewTitle(2, "高考", "管理員");
//創建存儲新聞標題的集合對象
List newsTitleList=new ArrayList();
//按照順序依次添加新聞標題
newsTitleList.add(car);
newsTitleList.add(test);
//獲取新聞標題的總數
System.out.println("新聞標題數目為:"+newsTitleList.size()+"條");
//遍歷集合對象
System.out.println("新聞標題名稱為:");
for(Object obj:newsTitleList){
      NewTitle title=(NewTitle)obj;
      System.out.println(title.getTitleName());
} 

輸出結果如圖1.3所示。

0

圖1.3 輸出新聞標題信息

在示例2中,ArrayList集合中存儲的是新聞標題對象。在ArrayList集合中可以存儲任何類型的對象。其中,代碼List newsTitleList=new ArrayList();是將接口List的引用指向實現類ArrayList的對象。在編程中將接口的引用指向實現類的對象是Java實現多態的一種形式,也是軟件開發中實現低耦合的方式之一,這樣的用法可以大大提高程序的靈活性。隨著編程經驗的積累,開發者對這個用法的理解會逐步加深。

ArrayList集合因為可以使用索引來直接獲取元素,所以其優點是遍歷元素和隨機訪問元素的效率比較高。但是由于ArrayList集合采用了和數組相同的存儲方式,在內存中分配連續的空間,因此在添加和刪除非尾部元素時會導致后面所有元素的移動,這就造成在插入、刪除等操作頻繁的應用場景下使用ArrayList會導致性能低下。所以數據操作頻繁時,最好使用LinkedList存儲數據。

2. 使用LinkedList類動態存儲數據

LinkedList類是List接口的鏈接列表實現類。它支持實現所有List接口可選的列表的操作,并且允許元素值是任何數據,包括null。

LinkedList類采用鏈表存儲方式存儲數據,如圖1.4所示,優點在于插入、刪除元素時效率比較高,但是LinkedList類的查找效率很低。

0

圖1.4 LinkedList類存儲示意圖

它除了包含ArrayList類所包含的方法外,還提供了表1-2所示的一些方法,可以在LinkedList類的首部或尾部進行插入、刪除操作。

表1-2 LinkedList類的常用方法

0

示例3

使用LinkedList集合存儲新聞標題(包含ID、名稱、創建者),實現獲取、添加及刪除頭條和末條新聞標題信息功能,并遍歷集合。

實現步驟如下。

(1)創建LinkedList對象,并添加數據。

(2)添加頭條和末條新聞標題。

(3)獲取頭條和末條新聞標題信息。

(4)刪除頭條和末條新聞標題。

關鍵代碼:

//創建多個新聞標題對象
NewTitle car=new NewTitle(1, "汽車", "管理員");
NewTitle medical=new NewTitle(2, "醫學", "管理員"); 
NewTitle fun=new NewTitle(3, "娛樂", "管理員");
NewTitle gym=new NewTitle(4, "體育", "管理員");
//創建存儲新聞標題的集合對象并添加數據
LinkedList newsTitleList=new LinkedList(); 
newsTitleList.add(car);
newsTitleList.add(medical);
//添加頭條新聞標題和末條新聞標題
newsTitleList.addFirst(fun);
newsTitleList.addLast(gym);
System.out.println("頭條和末條新聞已添加");
//獲取頭條以及最末條新聞標題
NewTitle first=(NewTitle) newsTitleList.getFirst();
System.out.println("頭條的新聞標題為:"+first.getTitleName());
NewTitle last=(NewTitle) newsTitleList.getLast();
System.out.println("排在最后的新聞標題為:"+last.getTitleName());
//刪除頭條和末條新聞標題
newsTitleList.removeFirst();
newsTitleList.removeLast();
System.out.println("頭條和末條新聞已刪除");
System.out.println("遍歷所有新聞標題:");
for(Object obj:newsTitleList){
     NewTitle newTitle=(NewTitle)obj;
     System.out.println("新聞標題名稱:"+newTitle.getTitleName());
}

輸出結果如圖1.5所示。

0

圖1.5 使用LinkedList存儲并操作新聞標題信息

除了表1-2中列出的LinkedList類提供的方法外,LinkedList類和ArrayList類所包含的大部分方法是完全一樣的,這主要是因為它們都是List接口的實現類。由于ArrayList采用和數組一樣的連續的順序存儲方式,當對數據頻繁檢索時效率較高,而LinkedList類采用鏈表存儲方式,當對數據添加、刪除或修改比較多時,建議選擇LinkedList類存儲數據。

1.1.3 Set接口

1. Set接口概述

Set接口是Collection接口的另外一個常用子接口,Set接口描述的是一種比較簡單的集合。集合中的對象并不按特定的方式排序,并且不能保存重復的對象,也就是說Set接口可以存儲一組唯一、無序的對象。

Set接口常用的實現類有HashSet。

2. 使用HashSet類動態存儲數據

假如現在需要在很多數據中查找某個數據,LinkedList類就無需考慮了,它的數據結構決定了它的查找效率低下。如果使用ArrayList類,在不知道數據的索引且需要全部遍歷的情況下,效率一樣很低下。為此Java集合框架提供了一個查找效率高的集合類HashSet。HashSet類實現了Set接口,是使用Set集合時最常用的一個實現類。HashSet集合的特點如下。

  • 集合內的元素是無序排列的。
  • HashSet類是非線程安全的。
  • 允許集合元素值為null。

表1-3中列舉了HashSet類的常用方法。

表1-3 HashSet類的常用方法

0

示例4

使用HashSet類的常用方法存儲并操作新聞標題信息,并遍歷集合。

實現步驟如下。

(1)創建HashSet對象,并添加數據。

(2)獲取新聞標題的總數。

(3)判斷集合中是否包含汽車新聞標題。

(4)移除對象。

(5)判斷集合是否為空。

(6)遍歷集合。

關鍵代碼:

//創建多個新聞標題對象
NewTitle car=new NewTitle(1, "汽車", "管理員");
NewTitle test=new NewTitle(2, "高考", "管理員");
//創建存儲新聞標題的集合對象
Set newsTitleList=new HashSet();
//按照順序依次添加新聞標題
newsTitleList.add(car);
newsTitleList.add(test);
//獲取新聞標題的總數
System.out.println("新聞標題數目為:"+newsTitleList.size()+"條");
//判斷集合中是否包含汽車新聞標題
System.out.println("汽車新聞是否存在:"+newsTitleList.contains(car)); //輸出true
newsTitleList.remove(test);  //移除對象
System.out.println("汽車對象已刪除");
System.out.println("集合是否為空:"+newsTitleList.isEmpty());   //判斷是否為空
//遍歷所有新聞標題
System.out.println("遍歷所有新聞標題:");
for(Object obj:newsTitleList){
     NewTitle title=(NewTitle)obj;
     System.out.println(title.getTitleName());
}

輸出結果如圖1.6所示。

0

圖1.6 使用HashSet類存儲并操作新聞標題信息

注意

使用HashSet類之前,需要導入相應的接口和類,代碼如下:

import java.util.Set;
import java.util.HashSet;

在示例4中,通過增強for循環遍歷HashSet,前面講過List接口可以使用for循環和增強for循環兩種方式遍歷。使用for循環遍歷時,通過get()方法取出每個對象,但HashSet類不存在get()方法,所以Set接口無法使用普通for循環遍歷。其實遍歷集合還有一種比較常用的方式,即使用Iterator接口。

1.1.4 Iterator接口

1. Iterator接口概述

Iterator接口表示對集合進行迭代的迭代器。Iterator接口為集合而生,專門實現集合的遍歷。此接口主要有如下兩個方法:

  • hasNext():判斷是否存在下一個可訪問的元素,如果仍有元素可以迭代,則返回true。
  • next():返回要訪問的下一個元素。

凡是由Collection接口派生而來的接口或者類,都實現了iterate()方法,iterate()方法返回一個Iterator對象。

2. 使用Iterator遍歷集合

下面通過示例來學習使用迭代器Iterator遍歷Arraylist集合。

示例5

使用Iterator接口遍歷ArrayList集合。

實現步驟如下。

(1)導入Iterator接口。

(2)使用集合的iterate()方法返回Iterator對象。

(3)while循環遍歷。

(4)使用Iterator的hasNext()方法判斷是否存在下一個可訪問的元素。

(5)使用Iterator的next()方法返回要訪問的下一個元素。

關鍵代碼:

public static void main(String[] args){
     ArrayList list=new ArrayList();
     list.add("張三");
     list.add("李四");
     list.add("王五");
     list.add(2, "杰倫");
     System.out.println("使用Iterator遍歷,分別是:");
     Iterator it=list.iterator(); //獲取集合迭代器Iterator
     while(it.hasNext()){   //通過迭代器依次輸出集合中所有元素的信息
          String name=(String)it.next();
          System.out.println(name);
     }
}

輸出結果:

使用Iterator遍歷,分別是:
張三
李四
杰倫
王五

示例5中是以ArrayList為例使用Iterator接口,其他由Collection接口直接或間接派生的集合類,如已經學習的LinkedList、HashSet等,同樣可以使用Iterator接口進行遍歷,遍歷方式與示例5遍歷ArrayList集合的方式相同。例如,將示例5改為使用Iterator對象遍歷,關鍵代碼如下。

//使用Iterator遍歷HashSet集合
while(iterator.hasNext()){
    NewTitle title=(NewTitle) iterator.next();
    System.out.println(title.getTitleName());
}

1.1.5 Map接口

1. Map接口概述

Map接口存儲一組成對的鍵(key)——值(value)對象,提供key到value的映射,通過key來檢索。Map接口中的key不要求有序,不允許重復。value同樣不要求有序,但允許重復。表1-4中列舉了Map接口的常用方法。

表1-4 Map接口的常用方法

0

Map接口中存儲的數據都是鍵——值對,例如,一個身份證號碼對應一個人,其中身份證號碼就是key,與此號碼對應的人就是value。

2. 使用HashMap類動態存儲數據

最常用的Map實現類是HashMap,其優點是查詢指定元素效率高。

示例6

使用HashMap類存儲學生信息,要求可以根據英文名檢索學生信息。

實現步驟如下。

(1)導入HashMap類。

(2)創建HashMap對象。

(3)調用HashMap對象的put()方法,向集合中添加數據。

(4)輸出學員個數。

(5)輸出鍵集。

(6)判斷是否存在“Jack”這個鍵,如果存在,則根據鍵獲取相應的值。

(7)判斷是否存在“Rose”這個鍵,如果存在,則根據鍵獲取相應的值。

關鍵代碼:

//創建學員對象
Student student1=new Student("李明", "男");
Student student2=new Student("劉麗", "女");
//創建保存“鍵——值對”的集合對象
Map students=new HashMap();
//把英文名稱與學員對象按照“鍵——值對”的方式存儲在HashMap中
students.put("Jack", student1);
students.put("Rose", student2);
//輸出學員個數
System.out.println("已添加"+students.size()+"個學員信息");
//輸出鍵集
System.out.println("鍵集:"+students.keySet());
String key="Jack";
//判斷是否存在“Jack”這個鍵,如果存在,則根據鍵獲取相應的值
if(students.containsKey(key)){
 Student student=(Student)students.get(key);
 System.out.println("英文名為"+key+"的學員姓名:"+student.getName());
}
String key1="Rose";
//判斷是否存在“Rose”這個鍵,如果存在,則刪除此鍵——值對
if(students.containsKey(key1)){
 students.remove(key1);
 System.out.println("學員"+key1+"的信息已刪除");
}

輸出結果如圖1.7所示。

0

圖1.7 使用HashMap類存儲并檢索學生信息

注意

① 數據添加到HashMap集合后,所有數據的數據類型將轉換為Object類型,所以從其中獲取數據時需要進行強制類型轉換。

② HashMap類不保證映射的順序,特別是不保證順序恒久不變。

遍歷HashMap集合時可以遍歷鍵集和值集。

示例7

改進示例6,遍歷所有學員的英文名及學員詳細信息。

實現步驟如下。

(1)遍歷鍵集。

(2)遍歷值集。

關鍵代碼:

//創建學員對象
Student student1=new Student("李明", "男");
Student student2=new Student("劉麗", "女");
//創建保存“鍵——值對”的集合對象
Map students=new HashMap();
//把英文名稱與學員對象按照“鍵——值對”的方式存儲在HashMap中
students.put("Jack", student1);
students.put("Rose", student2);
//輸出英文名
System.out.println("學生英文名:");
for(Object key:students.keySet()){
      System.out.println(key.toString());
}
//輸出學生詳細信息
System.out.println("學生詳細信息:");
for(Object value:students.values()){
      Student student=(Student)value;
      System.out.println("姓名:"+student.getName()+",性別:"+student.getSex());
}

輸出結果如圖1.8所示。

0

圖1.8 使用HashMap集合遍歷學生英文名及詳細信息

在示例7中,使用增強for循環遍歷HashMap集合的鍵集和值集,當然也可以使用前面的普通for循環或者迭代器Iterator來遍歷,視個人習慣而選擇。

0

Map補充案例

1.1.6 Collections類

Collections類是Java提供的一個集合操作工具類,它包含了大量的靜態方法,用于實現對集合元素的排序、查找和替換等操作。

注意

Collections和Collection是不同的,前者是集合的操作類,后者是集合接口。

1. 對集合元素排序與查找

排序是針對集合的一個常見需求。要排序就要知道兩個元素哪個大哪個小。在Java中,如果想實現一個類的對象之間比較大小,那么這個類就要實現Comparable接口。此接口強行對實現它的每個類的對象進行整體排序。這種排序被稱為類的自然排序,類的compareTo()方法被稱為它的自然比較方法。此方法用于比較此對象與指定對象的順序,如果該對象小于、等于或大于指定對象,則分別返回負整數、零或正整數。

compareTo()方法的定義語法格式如下。

int compareTo(Object obj);

其中:

  • 參數:obj即要比較的對象;
  • 返回值:負整數、零或正整數,根據此對象是小于、等于還是大于指定對象返回不同的值。

實現此接口的對象列表(和數組)可以通過Collections.sort()方法(和Arrays.sort()方法)進行自動排序。示例8通過實現Comparable接口對集合進行排序。

示例8

學生類Student實現了Comparable接口,重寫了compareTo()方法,通過比較學號實現對象之間的大小比較。

實現步驟如下。

(1)創建Student類。

(2)添加屬性學號number(int)、姓名name(String)和性別gender(String)。

(3)實現Comparable接口、compareTo()方法。

關鍵代碼:

public class Student implements Comparable{
            private int number=0;   //學號
            private String name="";   //姓名
            private String gender="";   //性別
            public int getNumber(){
                  return number;
            }
            public void setNumber(int number){
                  this.number=number;
            }
            public String getName(){
                  return name;
            }
            public void setName(String name){
                  this.name=name;
            }
            public String getGender(){
                  return gender;
            }
            public void setGender(String gender){
                  this.gender=gender;
            }
            public int compareTo(Object obj){
              Student student=(Student)obj;
              //如果學號相同,那么兩者就是相等的
              if(this.number==student.number){  
                  return 0; 
              //如果這個學生的學號大于傳入學生的學號
              }else if(this.number>student.getNumber()){ 
                  return 1;
              //如果這個學生的學號小于傳入學生的學號
              }else{ 
                  return -1;
              }
            }
}

元素之間可以比較大小之后,就可以使用Collections類的sort()方法對元素進行排序操作了。前面介紹過List接口和Map接口,Map接口本身是無序的,所以不能對Map接口做排序操作;但是List接口是有序的,所以可以對List接口進行排序。注意List接口中存放的元素,必須是實現了Comparable接口的元素才可以。

示例9

使用Collections類的靜態方法sort()和binarySearch()對List集合進行排序與查找。

實現步驟如下。

(1)導入相關類。

(2)初始化數據。

(3)遍歷排序前集合并輸出。

(4)使用Collections類的sort()方法排序。

(5)遍歷排序后集合并輸出。

(6)查找排序后某元素的索引。

關鍵代碼:

//省略聲明Student對象代碼
public static void main(String[] args){
      Student student1=new Student();
            student1.setNumber(5);
            Student student2=new Student();
            student2.setNumber(2);
            Student student3=new Student();
            student3.setNumber(1);
            Student student4=new Student();
            student4.setNumber(4);
            ArrayList list=new ArrayList();
            list.add(student1);
            list.add(student2);
            list.add(student3);
            list.add(student4);
            System.out.println("-------排序前-------");
            Iterator iterator=list.iterator();
            while(iterator.hasNext()){
                Student stu=(Student)iterator.next();
                System.out.println(stu.getNumber());
            }
            //使用Collections類的sort()方法對List集合進行排序
            System.out.println("-------排序后-------");
            Collections.sort(list); 
            iterator=list.iterator();
            while(iterator.hasNext()){
                Student stu=(Student)iterator.next();
                System.out.println(stu.getNumber());
            }
            //使用Collections類的binarySearch()方法對List集合進行查找
            int index=Collections.binarySearch(list,student3);  //①
            System.out.println("student3的索引是:"+index);
}

輸出結果:

-------排序前-------
5
2
1
4
-------排序后-------
1
2
4
5
student3的索引是:0

示例9中,①的代碼是使用Collections類的binarySearch()方法對List集合進行查找,因為student3的學號為1,故排序后索引變為0。

2. 替換集合元素

若有一個需求,需要把一個List集合中的所有元素都替換為相同的元素,則可以使用Collections類的靜態方法fill()來實現。下面通過一個示例來學習使用fill()方法替換元素。

示例10

使用Collections類的靜態方法fill()替換List集合中的所有元素為相同的元素。

實現步驟如下。

(1)導入相關類,初始化數據。

(2)使用Collections類的fill()方法替換集合中的元素。

(3)遍歷輸出替換后的集合。

關鍵代碼:

public static void main(String[] args){
     ArrayList list=new ArrayList();
     list.add("張三豐");
     list.add("楊過");
     list.add("郭靖");
     Collections.fill(list, "東方不敗");  //替換元素
     Iterator iterator=list.iterator();
     while(iterator.hasNext()){
         String name=(String)iterator.next();
         System.out.println(name);
     }
}

輸出結果:

東方不敗
東方不敗
東方不敗

至此,任務1已經全部完成。

主站蜘蛛池模板: 马边| 泰来县| 雷州市| 临沧市| 沙雅县| 海宁市| 垫江县| 聊城市| 高邮市| 寿光市| 黄山市| 诸暨市| 沐川县| 潮州市| 海丰县| 东兴市| 新沂市| 太保市| 北海市| 黑山县| 兰坪| 田东县| 新竹市| 都匀市| 乌兰浩特市| 宜君县| 社旗县| 墨玉县| 四川省| 和静县| 宣武区| 彰武县| 四平市| 青岛市| 长沙县| 澄城县| 宝鸡市| 永昌县| 汉阴县| 顺义区| 海原县|