集合就像是一個購物車,可以將購買的所有商品的存放在一個統一的購物車中集合的概念現實生活: 很多的事物湊在一起數學中的集合: 具有共同屬性的事物的總體是一種工具類,是一種容器,裡面可以存儲任意數量的相同屬性的類。集合的作用在類的內部對數據進行組織簡單快速的搜索大數量的條目有的集合口,提供了一系列排列有... ...
Java中的集合
集合就像是一個購物車,可以將購買的所有商品的存放在一個統一的購物車中
集合的概念
現實生活: 很多的事物湊在一起
數學中的集合: 具有共同屬性的事物的總體
Java中的集合類: 是一種工具類,是一種容器,裡面可以存儲任意數量的相同屬性的類。
集合的作用
在類的內部對數據進行組織
簡單快速的搜索大數量的條目
有的集合藉口,提供了一系列排列有序的元素,並且可以在序列中快速地插入或者刪除元素
有的集合介面,提供了映射關係,可以通過關鍵字(key)去快速查找到對應的唯一對象,而這 個關鍵字可以是任意類型
兩個集合框架
Collection
- List
- Queue
- Set
List、Queue、Set的區別:
List和Queue中的元素是有序排列的
Set中的元素是無序排列的
在Collection中存儲的是一個一個獨立的對象
Map
在Map中會以<Key,Value>,也就是兩個對象形成一個映射的關係的方式去存儲數據,這有點像C#中的Diectory類型。
Collection 介面、子介面及其實現類
List介面及其實現類 --- ArrayList
- List中的元素可以是重覆的並且是有序排列的,被稱為序列
- List可以精確的控制每個元素的插入位置,或刪除某個位置元素
- ArrayList --- 數組序列,是List的一個重要實現類
- ArrayList的底層是由數組實現的
實現功能 --- 模擬學生選課功能
- 選擇課程(往集合中添加課程)
- 刪除所選的某門課程(刪除集合中的元素)
- 查看所選課程
- 修改所選課程
//: Course.java
package com.faraj.collection;
public class Course {
public String name;
public String id;
public Course(String id, String name) {
this.id = id;
this.name = name;
}
}
創建課程類Course.java 由於是學習,類中的屬性就用了public實際應用應該使用private修飾,然後添加getName; setName; getId; SetId方法;
//: Student.java
package com.faraj.collection;
import java.util.HashSet;
import java.util.Set;
public class Student {
public String id;
public String name;
public Set<Course> courses;
public Student(String id, String name){
this.id = id;
this.name = name;
this.courses = new HashSet<Course>();
}
}
創建學生類Student.java
//: ListTest.java
package com.faraj.collection;
import java.util.*;
public class ListTest {
public List<Course> coursesToSelect;
public ListTest() {
this.coursesToSelect = new ArrayList<Course>();
}
/**
* 給courseToSelect添加元素
*/
public void addTest() {
Course cr1 = new Course("1", "資料庫系統概論");
coursesToSelect.add(cr1);
Course temp = coursesToSelect.get(0);
System.out.println("已添加課程: " + temp.id + "-" + temp.name);
coursesToSelect.add(0, new Course("2", "數據結構"));
Course temp2 = coursesToSelect.get(0);
System.out.println("已添加課程: " + temp2.id + "-" + temp2.name);
coursesToSelect.add(0, new Course("2", "數據結構"));
Course[] courses = new Course[]{
new Course("3", "線性代數"),
new Course("4", "ASP網頁設計")
};
coursesToSelect.addAll(Arrays.asList(courses));
System.out.println("已添加課程: " + coursesToSelect.get(2).id + "-" +
coursesToSelect.get(2).name);
System.out.println("已添加課程: " + coursesToSelect.get(3).id + "-" +
coursesToSelect.get(3).name);
coursesToSelect.addAll(2, Arrays.asList(
new Course("5", "面向對象編程"),
new Course("6", "彙編語言")));
System.out.println("已添加課程: " + coursesToSelect.get(2).id + "-" +
coursesToSelect.get(2).name);
System.out.println("已添加課程: " + coursesToSelect.get(3).id + "-" +
coursesToSelect.get(3).name);
}
/**
* 獲取集合中的所有元素
*/
public void getTest() {
for (int i = 0; i < coursesToSelect.size(); i++) {
System.out.println("課程:" + coursesToSelect.get(i).id + " - " +
coursesToSelect.get(i).name);
}
}
/**
* 通過迭代器遍歷List
*/
public void iteratorTest() {
Iterator<Course> it = coursesToSelect.iterator();
int i = 1;
while (it.hasNext()) {
Course cr = it.next();
System.out.println("課程" + i++ + ":" + cr.id + "-" + cr.name);
}
}
/**
* 使用foreach方式迴圈獲得list中的所有元素
*/
public void foreachTest() {
int i = 1;
for (Course cr : coursesToSelect) {
System.out.println("課程" + i++ + ":" + cr.id + "-" + cr.name);
}
}
/**
* 修改List中的元素
*/
public void modifyTest() {
coursesToSelect.set(1, new Course("7", "Java語言設計"));
}
/**
* 刪除List中的元素
*/
public void removeTest(){
coursesToSelect.remove(0);
}
public static void main(String[] args) {
ListTest lt = new ListTest();
lt.addTest();
// lt.getTest();
// lt.iteratorTest();
lt.modifyTest();
lt.removeTest();
lt.foreachTest();
}
}
創建備選課程類ListTest.java
package com.faraj.collection;
import java.util.*;
public class SetTest {
public List<Course> coursesToSelect;
public SetTest() {
coursesToSelect = new ArrayList<Course>();
}
public void add() {
coursesToSelect.addAll(
Arrays.asList(
new Course("1", "資料庫系統概論"),
new Course("2", "C語言基礎"),
new Course("3", "Python語言實踐"),
new Course("4", "基礎演算法實現"),
new Course("5", "彙編語言"),
new Course("6", "Linux基礎"),
new Course("7", "面向對象編程"))
);
}
public void getAll() {
for (Course c : coursesToSelect) {
System.out.println(c.id + "--" + c.name);
}
}
public static void main(String[] args) {
SetTest st = new SetTest();
st.add();
st.getAll();
Student stu = new Student("1", "Faraj");
Scanner sca = new Scanner(System.in);
System.out.println("Welcome Stu. " + stu.name + "to select courses. You should and only can select 3 course.");
int num = 1;
for (int i = 0; i < 3; i++) {
System.out.println("Please choose NO. " + num + " course's ID");
num ++;
String input = sca.next();
for (Course cor : st.coursesToSelect) {
if (cor.id.equals(input)) {
stu.courses.add(cor);
}
}
}
System.out.println("你選擇了:");
for (Course stuC : stu.courses) {
System.out.println(stuC.id + " - " + stuC.name);
}
}
}
Map和HashMap
Map介面
- Map提供了一種映射關係,其中的元素是以鍵值()對的形式存儲的,能夠實現根據key查找value
- Map中的鍵值對是以Entry類型的對象實例形式存在
- key不可重覆,但是value值可以重覆
- 每個key只能映射一個值
- Map 支持範性,Map<K,V>
HashMap類
- HashMap是Map的一個重要實現類,也是最常用的,基於哈希表實現
- HashMap中的Entry對象是無序排列的
- Key和Value的值都可以為null, 但是一個HashMap中只能有一個Key值為null的映射(Key值不可重覆)
案例:
功能說明: 通過Map<String,Student>進行學生信息管理
其中key為學生的ID,value為學生對象
通過鍵盤輸入學生信息
對集合中的學生信息進行增刪改查
創建MapTest.java
//: MapTest.java
package com.faraj.collection;
import java.util.*;
public class MapTest {
public Map<String, Student> students;
public MapTest() {
students = new HashMap<>();
}
/**
* 通過put方法在Map中添加entry(鍵值對)
*/
public void putTest() {
Scanner scan = new Scanner(System.in);
while (true) {
System.out.println("請輸入學生ID");
String id = scan.next();
int nextInput;
if (students.get(id) == null) {
System.out.println("請輸入學生的姓名");
students.put(id, new Student(id, scan.next()));
System.out.println("是否繼續添加? 1繼續 2退出");
nextInput = scan.nextInt();
if (nextInput != 1) {
if (nextInput == 2) break;
}
} else {
System.out.println("該ID已存在");
System.out.println("是否重新添加 1是 2退出");
while (true) {
try {
nextInput = scan.nextInt();
break;
} catch (InputMismatchException e) {
System.out.println("你輸入的內容不合法,請重新輸入");
}
}
if (nextInput != 1) {
if (nextInput == 2) break;
}
}
}
}
/**
* 通過keySet取得遍歷students
*/
public void keySetTest() {
Set<String> keys = students.keySet();
System.out.println("現已添加學生人數:" + keys.size());
for (String stuId : keys) {
System.out.println("學生(" + stuId + ")" + students.get(stuId).name);
}
}
/**
* 使用entrySet遍歷students
*/
public void entrySetTest() {
Set<Map.Entry<String, Student>> entries = students.entrySet();
System.out.println("學生總數:" + entries.size());
for (Map.Entry<String, Student> entry : entries) {
System.out.println(entry.getKey() + " - " + entry.getValue().name);
}
}
/**
* 從Map中刪除學生
*/
public void removeTest() {
Scanner scan = new Scanner(System.in);
while (true) {
System.out.println("請輸入要刪除的學生ID");
String id = scan.next();
if (students.get(id) == null) {
System.out.println("找不到該學生ID");
System.out.println("重新輸入請輸入1,退出應輸入2");
int next = scan.nextInt();
if (next != 1) {
if (next == 2) {
break;
}
}
} else {
System.out.println("學生(" + id + ")" + students.get(id).name + " 已被刪除");
students.remove(id);
System.out.println("重新輸入請輸入1,退出應輸入2");
int next = scan.nextInt();
if (next != 1) {
if (next == 2) {
break;
}
}
}
}
}
/**
* 通過Put方法更改學生姓名
*/
public void modifyTest() {
Scanner scan = new Scanner(System.in);
while (true) {
System.out.println("請輸入要修改的學生的ID");
String stuId = scan.next();
Student stu = students.get(stuId);
if (stu == null) {
System.out.println("該ID的學生不存在,請重新輸入");
continue;
}
System.out.println("當前學生(" + stuId + ")" + " - " + stu.name + ", 請輸入修改後的名字");
String newName = scan.next();
Student newStu = new Student(stuId,newName);
students.put(stuId,newStu);
break;
}
}
public static void main(String[] args) {
MapTest mt = new MapTest();
mt.putTest();
mt.keySetTest();
mt.modifyTest();
mt.entrySetTest();
}
}
判斷coursesToSelect(List)中是否存在課程
在Course.java中重寫equals方法
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Course)){
return false;
}
Course cour = (Course)obj;
if (cour.name == null){
return this.name == null;
}else{
return this.name.equals(cour.name);
}
}
在SetTest.java類中添加以下方法
public void containsTest() {
System.out.println("請輸入你要查找的名稱");
Course inputCourse = new Course();
inputCourse.name = scan.next();
if (coursesToSelect.contains(inputCourse))
System.out.println("包含《" + inputCourse.name + "》");
else System.out.println("不包含《" + inputCourse.name + "》");
}
在SetTest.java的main方法中測試該方法
st.containsTest();
另外在List中還有一個containsAll()方法,其用法與contains差不多,就是傳入的是一個比較的對象集合
判斷Set中是否存在課程
將之前SetTest.java中的部分代碼提取成一個單獨的方法
public void createStuAndSelectCourse(){
Student stu = new Student("1", "Faraj");
System.out.println("Welcome Stu. " + stu.name + "to select courses. You should and only can select 3 course.");
int num = 1;
for (int i = 0; i < 3; i++) {
System.out.println("Please choose NO. " + num + " course's ID");
num++;
String input = scan.next();
for (Course cor : coursesToSelect) {
if (cor.id.equals(input)) {
stu.courses.add(cor);
}
}
}
System.out.println("你選擇了:");
for (Course stuC : stu.courses) {
System.out.println(stuC.id + " - " + stuC.name);
}
}
在該文件中創建一下方法
public void setContainsTest() {
System.out.println("請輸入學生選則的課程名稱");
String name = scan.next();
Course inputCourse = new Course();
inputCourse.name = name;
if (student.courses.contains(inputCourse)) {
System.out.println("該學生選擇了《" + inputCourse.name + "》");
} else {
System.out.println("該學生並沒有選擇《" + inputCourse.name + "》");
}
}
在main方法中調用新創建的兩個方法
st.createStuAndSelectCourse();
st.setContainsTest();
運行程式發現HashSet中的contains方法告訴我們並沒有包含課程
不用擔心,這不是因為我們的代碼寫錯了,而是……
HashSet的contains方法的實現機制
在Object這個根類中除了定義了上面通過Course類重寫的equals()方法,還定義了一個**hashCode()**方法,這個方法返回的是對象的哈希碼的值,當我們在調用HashSet的contains()方法的時候,其實先調用每個元素的hashCode獲取它們的哈希碼,如果哈希碼相等的情況下,才會調用equals方法來判斷是否相等,這有當這兩個方法返回的值都是true的時候,contains()方法才會認定這個HashSet包含某個元素。
graph LR co>HashSet.contains] ==> hc{.hashCode} hc{比較.hashCode} -.相等.-> eq(.equals) hc{比較.hashCode} -. 不相等 .-> false[false] eq(.equals) -.true.-> True[True] eq(.equals) -.false.-> false[false] style co fill:#FFBB4A,color:white,stroke-width:0px style hc fill:#3FBA69,color:white,stroke-width:0px style eq fill:#3FBA69,color:white,stroke-width:0px style True fill:#069BF9,color:white,stroke-width:0px style false fill:#EF3C41,color:white,stroke-width:0px在Course類中添加hashCode方法的重寫
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
然後重新啟動程式,就能看到程式正常運行了
如何判斷List中索引的位置
- 通過indexOf來獲取某元素的索引位置
在之前的SetTest類中的containsTest方法中加入以下代碼:
System.out.println("當前課程的索引位置為:"+coursesToSelect.indexOf(inputCourse));
public void containsTest() {
System.out.println("請輸入你要查找的名稱");
Course inputCourse = new Course();
inputCourse.name = scan.next();
if (coursesToSelect.contains(inputCourse)){
System.out.println("包含《" + inputCourse.name + "》");
System.out.println("當前課程的索引位置為:"+coursesToSelect.indexOf(inputCourse));
}
else System.out.println("不包含《" + inputCourse.name + "》");
graph LR
index[indexOf] ==>arr1[元素1]
subgraph 遍歷
arr1[元素1] -.-> arr2[元素2]
arr2[元素2] -.-> arr3[元素3]
arr3[元素3] -.-> arr4[...]
arr4[...] -.-> arr5[元素n]
end
lastindex[lastIndexOf] ==> arr5[元素n]
arr1[元素1] --> equals[equals]
arr2[元素2] --> equals1[equals]
arr3[元素3] --> equals2[equals]
arr4[...] --> equals3[equals]
indexOf方法會遍歷整個集合,調用每個元素的equals方法,如果equals返回true則返回當前元素的索引位置,如果集合中有多個相同的對象,則會取第一個對應的元素的索引。
lastIndexOf方法會從集合中的最後一個元素開始遍歷,判斷的過程和indexOf是一樣的
- 不管是lastIndexOf或者是indexOf如果未找到集合中包含的元素,都會返回-1
判斷Map中是否包含指定的key或者value
可以調用.containsKey()方法來判斷Map中是否包含key
調用.containsValue()方法來判斷Map中是否包含value
註意⚠️:在使用.caontainsValue()方法的時候需要重寫.equals()方法
在MapTest類中添加以下方法
public void containsKeyOrValue(){
System.out.println("請輸入學生ID");
String id = scanner.next();
System.out.println("您輸入的學生ID為:"+id+"該學生"+
(students.containsKey(id) ? "存在" : "不存在"));
if (students.containsKey(id)){
System.out.println("該學生的ID為:"+ id + "該學生的姓名為:" + students.get(id).name);
}
System.out.println("請輸入學生姓名");
String name = scanner.next();
Student newStudent = new Student();
newStudent.name = name;
System.out.println("您輸入的學生姓名為:" + name +
(students.containsValue(newStudent)? "該學生存在" : "該學生不存在"));
}
在Student類中重寫equals方法
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Student))
return false;
Student stu = (Student) obj;
if (stu.name == null) {
return this.name == null;
}else {
return this.name.equals(stu.name);
}
}
使用Collections.sort()方法排序
創建新類CollectionTest
package com.faraj.collection;
import java.util.*;
public class CollectionTest {
public Scanner scan;
public Random rand;
public CollectionTest() {
scan = new Scanner(System.in);
rand = new Random();
}
public void sortTest1() {
List<Integer> integers = new ArrayList<>();
for (int i = 0; i < 100; i++) {
integers.add(rand.nextInt(100));
}
System.out.println("=========Before sort=========");
for (Integer integer : integers) {
System.out.print(integer + " ");
}
Collections.sort(integers);
System.out.println();
System.out.println("=========After sort=========");
for (Integer integer : integers) {
System.out.print(integer + " ");
}
}
public static void main(String[] args) {
CollectionTest ct = new CollectionTest();
ct.sortTest1();
}
}
在上面的方法中,我們測試了對Integer 類型的排序,下麵來測試一下String類型的sort()
public void sortTest2() {
List<String> strings = new ArrayList<>();
strings.add("Microsoft");
strings.add("Google");
strings.add("Apple");
System.out.println("=========Before sort=========");
for (String string : strings) {
System.out.print(string + "\t");
}
Collections.sort(strings);
System.out.println();
System.out.println("=========After sort=========");
for (String string : strings) {
System.out.print(string + "\t");
}
}
對於字元串,sort 的比較順序
- 比較一個字元到最後一個字元
- 按照排序: 0~9、A~Z、a~z
public void sortTest3() {
String s = "qwertyuiopasdfghjklzxcvbnmZXCVBNMASDFGHJKLQWERTYUIOP1234567890";
List<String> strings = new ArrayList<>();
for (int i = 0; i < 10; i++) {
StringBuilder str = new StringBuilder();
for (int j = 0; j < 10; j++) {
int ra = rand.nextInt(62);
str.append(s.charAt(ra));
}
String newStr = str.toString();
if (!strings.contains(newStr)){
strings.add(newStr);
}
}
System.out.println("=========Before sort=========");
for (String string : strings)
System.out.println(string);
Collections.sort(strings);
System.out.println("=========After sort=========");
for (String string : strings)
System.out.println(string);
}
隨機生成一個十位的字母大小寫加數字的字元串,併進行排序
Comparable & Comparator
Comparable介面 —— 可比較的
- 實現該介面表示:這個類的實例是可以比較大小的,可以進行排序
- 定義了預設的比較規則
- 它的實現類必須實現compareTo()方法
- 當實現了Comparable介面的對象的實例進行比較的時候,就會調用對象中的compareTo()方法進行比較
- compareTo()方法返回正數表示大,負數表示小,0表示相等
Comparator介面 —— 比較工具介面
- 用於定義臨時比較規則,而不是預設比較規則
- Comparator介面的實現類必須實現compare()方法
- Comparator和Comparable都是Java集合框架的成員
實現:
首先讓Student類繼承與Comparable介面
重寫comparaTo方法
//: Student.java
package com.faraj.collection;
import javax.xml.crypto.dsig.keyinfo.RetrievalMethod;
import java.util.HashSet;
import java.util.Set;
public class Student implements Comparable<Student> {
public String id;
public String name;
public Set<Course> courses;
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Student))
return false;
Student stu = (Student) obj;
if (stu.name == null) {
return this.name == null;
}else {
return this.name.equals(stu.name);
}
}
public Student() {
}
public Student(String id, String name) {
this.id = id;
this.name = name;
this.courses = new HashSet<>();
}
@Override
public int compareTo(Student o) {
return Integer.compare(Integer.parseInt(this.id), Integer.parseInt(o.id));
}
}
- 創建StudentComparator類,讓它繼承與Comparator介面
- 重寫compare方法
package com.faraj.collection;
import java.util.Comparator;
public class StudentComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
- 進行比較排序,在CollectionTest中添加以下方法
public void sortTest4() {
List<Integer> ints = new ArrayList<>();
do {
int count = rand.nextInt(1000);
if (!ints.contains(count)) {
ints.add(count);
}
} while (ints.size() < 5);
List<Student> students = new ArrayList<>(Arrays.asList(
new Student(String.valueOf(ints.get(0)), "Ming."),
new Student(String.valueOf(ints.get(1)), "H."),
new Student(String.valueOf(ints.get(3)), "Dai"),
new Student(String.valueOf(ints.get(2)), "JJ."),
new Student(String.valueOf(ints.get(4)), "Sum")
));
System.out.println("=========Before sort=========");
for (Student stu : students) {
System.out.println("#" + stu.id + " " + stu.name);
}
System.out.println("=========After sort=========");
Collections.sort(students);
for (Student stu : students) {
System.out.println("#" + stu.id + " " + stu.name);
}
System.out.println("=========Sort by name=========");
Collections.sort(students, new StudentComparator());
//students.sort(new StudentComparator()); 也可以寫成這個形式
for (Student stu : students) {
System.out.println("#" + stu.id + " " + stu.name);
}
}