Java基礎教程 - 9 集合

更好的閱讀體驗:點這里 ( www.doubibiji.com
更好的閱讀體驗:點這里 ( www.doubibiji.com
更好的閱讀體驗:點這里 ( www.doubibiji.com

9 集合

什么是集合?

集合就是可以存儲多個數據的一種數據類型,集合內的每一個數據稱之為元素,其中的元素可以是任意類型的數據,包括字符串、數字、布爾,甚至是集合等等。

在前面已經學習了數組,數組也是可以批量的存儲數據,但是集合比數組要強大的多。

數字一旦初始化以后,長度就固定了,是無法改變的,而且類型也確定了,同時提供的方法有限,對添加、刪除、插入、搜索等操作就很不方便。

在Java中常用的集合分為3類:

  • List
  • Set
  • Map

不同的集合有不同的特點,例如:

  • 是否支持重復的元素,有的集合中的元素不能重復,有的可以。
  • 是否有序,有的集合中的元素是有序的,可以通過index來獲取元素,有的集合是無序的,無法通過index獲取元素。

下面一一介紹。

9.1 List

List 列表就是一個普通的集合,滿足你最原始的想象,主要有如下特點:

  • 列表中的元素可以重復;
  • 列表中的元素可以修改,可以增加、修改、刪除;
  • 列表中的元素是有序的,可以通過索引來訪問;
  • 列表中可以存儲不同數據類型的數據;

和數組很像,但是會自動擴容,支持不同類型的數據。

1 創建List

// 創建一個String類型的列表,<String>表示泛型
List<String> strList = new ArrayList<>();// 創建一個Integer類型的列表
List<Integer> numbers = new ArrayList<>();// 不指定類型,什么元素都可以放,和 List<Object> 一樣
List objList = new ArrayList<>();

在創建集合的時候,可以通過 <類型> 泛型指定集合中元素的類型,關于泛型,后面在進階篇再講解。

指定泛型后,后面在獲取集合中元素的時候,獲取的數據就是泛型指定的類型;如果不指定泛型,那么元素在取出的時候是Object類型,那么賦值給指定類型的變量就需要強制轉換,后面獲取元素的時候再講。


還可以在創建的時候,指定List初始化的大小,在使用的時候,如果元素超過了初始容量,會自動進行擴容。

如果知道列表中要放多少數據,建議在新建數組的時候指定列表大初始大小,這樣避免擴容,從而耗費性能,因為列表的底層還是使用數組實現的,默認長度是10,而數組是無法動態修改大小的,所以在擴容的時候會創建一個新的列表,將之前列表中的數據拷貝到新列表中。

// 創建一個初始容量為5的ArrayList,用于存儲Integer類型的元素  
List<Integer> list = new ArrayList<>(5);  

還可以創建不可變的List,不可變的List不能添加、修改、刪除元素,只能讀取元素,否則會報錯:

List<String> colorList = List.of("red", "green", "blue");
System.out.println(colorList);    // [red, green, blue]

如果想快速創建包含元素的可變 List,可以使用如下方式:

// 將List.of(1, 2, 3)作為參數創建一個新的可變List
List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3));	

2 基礎操作

添加元素

通過 add()addAll() 方法可以添加元素。

List<Integer> numList1 = new ArrayList<>();
numList1.add(1);        // 添加元素
numList1.add(2);List<Integer> numList2 = List.of(3, 4);
numList1.addAll(numList2);      // 將numList2中所有的元素都添加到numList1中
訪問元素

使用 get() 方法,通過下標來訪問列表中的元素,從0開始,注意不要越界。

List<Integer> numbers = List.of(1, 2, 3);
Integer integer = numbers.get(0);   // 訪問元素:1
// 訪問元素
System.out.println(integer); // 1// 放入三個類型的數據,分別是integer、String、List列表
List itemList = List.of(1, "abc", List.of(1, 2, 3));
// 因為沒有使用泛型,所以需要強制轉換
Integer i = (Integer) itemList.get(0);
String s = (String) itemList.get(1);
List<Integer> list = (List<Integer>) itemList.get(2);

如果使用泛型,直接取出數據就是泛型的類型,如果沒有使用泛型,那么取出的類型需要根據類型進行強制轉換。

獲取長度

通過 size() 方法,可以獲取到List 的長度。

List<Integer> numbers = List.of(1, 2, 3);// 獲取長度
System.out.println(numbers.size()); // 3
修改元素

修改元素可以使用 set() 方法,修改指定位置的元素。

List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3));numbers.set(1, 5);      // 修改元素
System.out.println(numbers); // [1, 5, 3]
插入元素

插入元素也是使用 addaddAll() 方法,使用第一個參數指定插入的位置即可。

List<Integer> numList1 = new ArrayList<>();
numList1.add(1);        // 添加元素
numList1.add(1, 2);     // 在index為1的位置添加元素List<Integer> numList2 = List.of(3, 4);// 將numList2插入到numList1中
numList1.addAll(2, numList2);      
System.out.println(numList1);			 // [1, 2, 3, 4]
刪除元素

刪除元素可以通過 元素index 來刪除。

List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3));numbers.remove(Integer.valueOf(2));	// 通過元素移除,將值為2的元素移除
numbers.remove(1);		// 通過index移除,移除index為1的元素System.out.println(numbers); // [1]
清空List
List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3));numbers.clear();		// 清空List
System.out.println(numbers); // []

3 遍歷List

當遍歷 Java 中的列表時,您可以使用以下方法:

使用 for 循環

List<String> fruits = new ArrayList<>(List.of("apple", "banana", "orange"));for (int i = 0; i < fruits.size(); i++) {System.out.println(fruits.get(i));
}

for 循環中,使用列表的長度 fruits.size() 作為循環條件,每個元素通過 get(index) 方法獲取。

使用 for-each 循環

List<String> fruits = new ArrayList<>(List.of("apple", "banana", "orange"));for (String fruit : fruits) {System.out.println(fruit);
}

for-each 循環中,將每個列表元素 fruit 賦值給變量 String fruit,然后在循環體中執行相應的操作。這種方法比使用 for 循環更簡潔,特別是當不需要訪問每個元素的索引時。

使用迭代器

List<String> fruits = new ArrayList<>(List.of("apple", "banana", "orange"));// 獲取迭代器
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {System.out.println(iterator.next());
}

在使用迭代器遍歷列表時,首先需要獲取列表的迭代器 fruits.iterator(),然后可以使用 while 循環和迭代器的 hasNext()next() 方法來訪問列表的每個元素。

遍歷的時候刪除元素

我們可能會有這樣的場景,遍歷一個 List,將其中滿足條件的元素刪除,例如刪除一個 List 中的偶數,可能編寫代碼如下:

List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3, 4, 5));for (Integer num : numbers) {if (num % 2 == 0) {numbers.remove(num);    // 刪除元素}
}

但是執行代碼,卻發現報錯,如下:

Exception in thread "main" java.util.ConcurrentModificationExceptionat java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1043)at java.base/java.util.ArrayList$Itr.next(ArrayList.java:997)at com.demo.ListTest.main(ListTest.java:16)

當在迭代器遍歷集合的同時,又對集合進行了結構性修改(比如添加、刪除元素)時就會拋出 ConcurrentModificationException 異常。

那怎么在遍歷的時候刪除元素呢?

可以使用迭代器的 remove() 方法來安全地刪除元素,舉個栗子:

List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3, 4, 5));// 使用迭代器遍歷列表
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {Integer num = iterator.next();// 在遍歷時如果想要刪除某個元素,使用迭代器的 remove 方法if (num % 2 == 0) {iterator.remove();}
}System.out.println(numbers); // 輸出:[1, 3, 5]

4 排序

將列表中的元素按照從小到大排列:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class SortListExample {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("Apple");list.add("Orange");list.add("Banana");Collections.sort(list);System.out.println(list); // 輸出:[Apple, Banana, Orange]}
}

從大到小排列:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class SortListExample {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("Apple");list.add("Orange");list.add("Banana");// 使用 reverseOrder() 方法實現降序排序Collections.sort(list, Collections.reverseOrder());System.out.println(list); // 輸出應該是:[Orange, Banana, Apple] }
}

但是使用自定義的對象放入到 List 中就無法排序了,因為自定義對象沒有實現 Comparable接口,所以自定義對象可以實現 Comparable接口,重寫 compareTo 方法,可以實現按照自定的屬性進行排序:

import java.util.ArrayList;
import java.util.List;class Student implements Comparable {private String name;private int age;public Student(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;}@Overridepublic int compareTo(Object target) {if (target instanceof Student) {Student student = (Student) target;return this.name.compareTo(student.name);  //按照姓名從小到大排列} else {throw new RuntimeException("類型不匹配");}}
}public class SortListExample {public static void main(String[] args) {List<Student> list = new ArrayList<>();list.add(new Student("zhangsan", 15));list.add(new Student("lisi", 16));list.add(new Student("wangwu", 17));for (Student s : list) {System.out.println(s.getName());}}
}

利用compare(Object target)方法,比較當前對象和target的大小,如果想從小到大排列,則當前對象的屬性小于 target 的屬性,返回負數,如果相等,返回0,如果大于,返回正數,則就實現了從小到大排列,反之從大到小排列。


如果不想實現 Comparable接口,也可以使用Collections.sort()方法并傳入一個Comparator 比較器對象。

舉個栗子:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;class Student {private String name;private int age;public Student(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 class SortListExample {public static void main(String[] args) {List<Student> list = new ArrayList<>();list.add(new Student("zhangsan", 15));list.add(new Student("lisi", 17));list.add(new Student("wangwu", 16));Collections.sort(list, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {if(o1 instanceof Student && o2 instanceof Student){// 年齡相等就算相同, 按照年齡從小到大排列return Integer.compare(o1.getAge(), o2.getAge());}else{throw new RuntimeException("類型不匹配");}}});for (Student s : list) {System.out.println(s.getName());}}
}

5 其他常用操作

判斷List是否為空

可以通過 isEmpty()方法判斷 List 是否為空。

List<Integer> numbers = new ArrayList<>();
if (numbers.isEmpty()) {System.out.println("集合為空");
}numbers.add(1);
numbers.add(2);
numbers.add(3);
if (!numbers.isEmpty()) {System.out.println("集合不為空");
}

一般使用的時候,可以搭配 null 來判斷一個 List 為非空,例如: if (null != numbers && !numbers.isEmpty())

檢查包含某個元素
List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3));System.out.println(numbers.contains(2)); // true

9.2 Set

Set與List的區別:Set是一種不允許重復元素的集合類型,而且Set是無序的。

Set更重要的是用來做一些運算,例如求兩個集合的交集、并集、差集等。

Set最主要的特點:

  • 不支持重復的元素

  • 內容是無序的,不能下標來訪問元素

  • Set是可以被修改的

  • 可以存儲不同的數據類型

List 有序,是添加元素的時候,后添加的元素會排列到前面元素的后面。而無序,是每次添加的元素之間沒有順序,這里設計數據結構的相關知識,后面可以通過學習數據結構來了解。

1 創建Set

// 創建一個String類型的Set
Set<String> colorSet = new HashSet<>();// 創建一個Integer類型的Set
Set<Integer> numSet = new HashSet<>();// 不指定類型,什么元素都可以放,和 Set<Object> 一樣
Set objList = new HashSet<>();

還可以在創建的時候,指定 Set 初始化的大小,在使用的時候,如果元素超過了初始容量,會自動進行擴容。

// 創建一個初始容量為5的HashSet,用于存儲Integer類型的元素  
Set<Integer> list = new HashSet<>(5);  

還可以創建不可變的 Set,不可變的 Set 不能添加、修改、刪除元素,只能讀取元素:

Set<String> colorList = Set.of("red", "green", "blue");
System.out.println(colorList);    // [red, green, blue]

如果想快速創建包含元素的可變 Set,可以使用如下方式:

// Set.of(1, 2, 3)作為參數創建一個新的可變Set
Set<Integer> numbers = new HashSet<>(Set.of(1, 2, 3));
System.out.println(numbers);

2 基礎操作

添加元素

通過 add()addAll() 方法可以添加元素。

Set<Integer> numSet1 = new HashSet<>();
// 添加元素
numSet1.add(1);        
numSet1.add(2);Set<Integer> numSet2 = Set.of(3, 4);
numSet1.addAll(numSet2);      // 將numSet2中所有的元素都添加到numSet1中
訪問元素

因為Set是無序的,所以無法通過下標來訪問Set中的元素,如果想訪問Set中的元素,只能通過遍歷的方式來獲取Set中的元素。

獲取長度

通過 size() 方法,可以獲取到 Set 的長度。

Set<Integer> numbers = Set.of(1, 2, 3);
// 獲取長度
System.out.println(numbers.size()); // 3
刪除元素

刪除元素只能通過 元素 來刪除,無法通過 index 來刪除。

Set<Integer> numSet = new HashSet<>(Set.of(1, 2, 3));
// 刪除元素
numSet.remove(2);
System.out.println(numSet); // [1, 3]

因為Set是無序的,所以無法通過下標來刪除元素。

清空Set
Set<Integer> numSet = new HashSet<>(Set.of(1, 2, 3));
// 清空set
numSet.clear();
System.out.println(numSet); // []
將Set轉換為List
Set<Integer> numSet = Set.of(1, 2, 3);
// 將set作為參數傳遞給List,其實這種方式也可以將List轉換為Set
List<Integer> numList = new ArrayList<>(numSet);
System.out.println(numList);

3 遍歷Set

當遍歷 Set 時,您可以使用以下方法:

使用 for-each 循環

Set<String> colorSet = Set.of("red", "green", "blue");for (String color : colorSet) {System.out.println(color);
}

在這個示例中,我們使用 for-each 循環遍歷了 Set 中的每個元素,并打印每個元素。

因為 Set 是無序的,所以無法使用簡單的 for 循環通過 index 來遍歷。

使用迭代器

Set 類型也實現了 Iterable 接口,因此您也可以使用迭代器來遍歷 Set 中的元素。例如:

Set<String> colorSet = Set.of("red", "green", "blue");// 獲取迭代器
Iterator<String> iterator = colorSet.iterator();
while (iterator.hasNext()) {System.out.println(iterator.next());
}

在這個示例中,我們首先獲取了 Set 的迭代器,并使用 while 循環和 hasNext() 方法遍歷了 Set 中的每個元素,并使用 next() 方法訪問當前元素。

4 其他常用操作

因為 List 和 Set 都是繼承自 Collection 接口,很多方法都是 Collection 接口中規范的,所以很多 List 有的操作 Set 也是有的。

判斷Set是否為空

可以通過 isEmpty() 方法判斷 Set 是否為空,通過 isNotEmpty() 方法判斷 Set 是否不為空。

Set<Integer> numSet = new HashSet<>();
if (numSet.isEmpty()) {System.out.println("Set為空");
}numSet = new HashSet<>(Set.of(1, 2, 3, 4, 5));
if (!numSet.isEmpty()) {System.out.println("Set不為空");
}
檢查包含某個元素
Set<Integer> numSet = new HashSet<>(Set.of(1, 2, 3));
System.out.println(numSet.contains(2)); // true
并集

使用 addAll() 方法將兩個 Set 合并為一個Set。下面是一個示例:

Set<Integer> set1 = new HashSet<>(Set.of(1, 2, 3));
Set<Integer> set2 = new HashSet<>(Set.of(3, 4, 5));
set1.addAll(set2);
System.out.println(set1); // [1, 2, 3, 4, 5]
交集

使用 retainAll() 方法獲取兩個Set的交集。下面是一個示例:

Set<Integer> set1 = new HashSet<>(Set.of(1, 2, 3));
Set<Integer> set2 = new HashSet<>(Set.of(3, 4, 5));
// 求交集
set1.retainAll(set2);
System.out.println(set1); // [3]
差集

使用 removeAll() 方法獲取兩個 Set 的差集。下面是一個示例:

Set<Integer> set1 = new HashSet<>(Set.of(1, 2, 3));
Set<Integer> set2 = new HashSet<>(Set.of(3, 4, 5));
// 求差集
set1.removeAll(set2);
System.out.println(set1); // [1, 2]

9.3 Map

Map是一種鍵值對的數據結構,其中每個鍵對應一個值。

例如有一份數據:

姓名成績
zhangsan94
lisi96
wangwu91

使用List、Set的方式存儲上面的數據是很不方便的。

而使用Map存儲就很適合,可以將姓名作為key,成績作為value。

{"zhangsan": 94,"lisi": 96,"wangwu": 91
}

這樣可以很容易通過姓名key得到對應的成績value。

1 創建Map

// 創建一個String-String類型的Map
Map<String, String> map1 = new HashMap<>();// 創建一個String-Integer類型的Map
Map<String, Integer> map2 = new HashMap<>();

Map<String, String> map 其中 <String, String> 分別表示 keyvalue 對應的數據類型。

同樣,也是可以使用 Map.of() 來創建不可變的 Map,不可變的 Map 不能添加、修改、刪除元素,只能讀取元素:

Map<String, Integer> scoreMap = Map.of("zhangsan", 90, "lisi", 99,"wangwu", 80);
System.out.println(scoreMap);    // {wangwu=80, lisi=99, zhangsan=90}

如果想快速創建包含元素的可變 Map,可以使用如下方式:

Map<String, Integer> scoreMap = new HashMap<>(Map.of("zhangsan", 90, "lisi", 99,"wangwu", 80));
System.out.println(scoreMap);    // {wangwu=80, lisi=99, zhangsan=90}

2 基礎操作

添加元素

添加元素使用 put() 方法:

Map<String, Integer> numbers = new HashMap<>();
// 添加元素
numbers.put("one", 1);
numbers.put("two", 2);
numbers.put("three", 3);System.out.println(numbers);	// {one=1, two=2, three=3}
訪問元素

訪問元素的時候,通過 key 來訪問。

Map<String, Integer> numbers = Map.of("one", 1, "two", 2, "three", 3);// 獲取元素
System.out.println(numbers.get("two")); // 2

如果訪問不存在的key,則得到結果為null。

獲取長度
Map<String, Integer> numbers = Map.of("one", 1, "two", 2, "three", 3);// 獲取長度
System.out.println(numbers.size()); // 3
刪除元素

刪除的時候,通過 key 來刪除

Map<String, Integer> numbers = new HashMap<>(Map.of("one", 1, "two", 2, "three", 3));// 刪除元素
numbers.remove("two");
System.out.println(numbers);    // {three=3, one=1}
清空Map
Map<String, Integer> numbers = new HashMap<>(Map.of("one", 1, "two", 2, "three", 3));// 清空map
numbers.clear();
System.out.println(numbers);    // {}

3 遍歷操作

使用 for...in 循環

Map<String, Integer> numbers = Map.of("one", 1, "two", 2, "three", 3);for (Map.Entry<String, Integer> entry : numbers.entrySet()) {String key = entry.getKey();Integer value = entry.getValue();System.out.println("key:" + key + ", value:" + value);
}

這個示例使用了 for...in 循環遍歷 Map,其中的 entrySet() 方法返回一個包含鍵值對的Set,然后在循環中使用 getKey()getValue() 方法訪問鍵和值。

使用 forEach() 方法

Map<String, Integer> numbers = Map.of("one", 1, "two", 2, "three", 3);// 使用forEach方法遍歷
numbers.forEach方法遍歷((key, value) -> {System.out.println("key:" + key + ", value:" + value);
});

這個示例使用了 forEach() 方法遍歷 Map,其中的 lambda 表達式接收鍵和值,并在控制臺打印出每個學生的分數。

使用 keysvalues 屬性

Map<String, Integer> numbers = Map.of("one", 1, "two", 2, "three", 3);// 首先得到key組成的set,然后遍歷set
for (String key : numbers.keySet()) {Integer value = numbers.get(key);System.out.println("key:" + key + ", value:" + value);
}for (Integer value : numbers.values()) {System.out.println("value:" + value);
}

這個示例使用了 keySet()values() 方法分別遍歷 Map 的鍵和值,然后在循環中使用鍵或值變量訪問相應的鍵或值。

4 其他常用操作

判斷Map是否為空

可以通過 isEmpty() 方法判斷 Map 是否為空,通過 isNotEmpty() 方法判斷 Map 是否不為空。

Map<String, Integer> numbers = new HashMap<>();
if (numbers.isEmpty()) {System.out.println("Map為空");
}numbers.put("one", 1);
numbers.put("two", 2);
numbers.put("three", 3);
if (!numbers.isEmpty()) {System.out.println("Map不為空");
}
檢查包含某個鍵
Map<String, Integer> numbers = Map.of("one", 1, "two", 2, "three", 3);
// 是否包含某個key
System.out.println(numbers.containsKey("two"));     // true
檢查包含某個值
Map<String, Integer> numbers = Map.of("one", 1, "two", 2, "three", 3);
// 是否包含某個value
System.out.println(numbers.containsValue(2)); // true
獲取Map中的所有鍵
Map<String, Integer> numbers = Map.of("one", 1, "two", 2, "three", 3);
// 獲取所有的key
Set<String> keys = numbers.keySet();
System.out.println(keys); // [three, one, two]  無序的

9.4 集合的體系結構

其實看上面的 List 和 Set 方法是基本一樣的,因為他們實現了共同的 Collection 接口。Map 是另外與 Collection 接口類似的頂級接口。

常用的集合的體系結構如下:

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

需要注意:ArrayList、HashSet、HashMap 都是非線程安全的,所以不能用在多個線程中共享數據,如果要使用線程安全的類,需要使用CopyOnWriteArrayList、CopyOnWriteArraySet、ConcurrentHashMap。


下面再介紹一下可能會用到的其他的類,另外一些沒介紹的,可以百度一下如何使用。

1 TreeSet

TreeSetSortedSet 接口的實現類,添加到 TreeSet 中的元素會自動排序和去重。

所以 TreeSet 中只能放同類型的數據,不同類型的數據無法進行比較排序。

TreeSet兩種排序方法:自然排序和定制排序。默認情況下,TreeSet采用自然排序。

舉個栗子:

自然排序法

自然排序要求存儲在TreeSet中的元素實現Comparable接口,并覆寫compareTo(Object o)方法。

import java.util.Set;
import java.util.TreeSet;public class TreeSetTest {public static void main(String[] args) {Set<String> treeSet = new TreeSet();treeSet.add("edg");treeSet.add("abc");treeSet.add("bcd");treeSet.add("abc");for (String s : treeSet) {System.out.println(s);}}
}

輸出結果:

abc
bcd
edg

從上面的代碼可以看出,對加入的字符串進行排序,默認使用的是自然排序。因為String 類實現了Comparable接口


自然排序排列對象

如果將自定義的對象添加的 TreeSet 中的時候,發現會報錯,因為該對象沒有實現 Comparable 接口。

所以如果使用自然排序,放入到 TreeSet 中的類對象,需要實現 Comparable 接口。

import java.util.Set;
import java.util.TreeSet;class Student implements Comparable {private String name;private int age;public Student(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;}@Overridepublic int compareTo(Object target) {if (target instanceof Student) {Student student = (Student) target;return this.name.compareTo(student.name);  //按照姓名從小到大排列} else {throw new RuntimeException("類型不匹配");}}
}public class TreeSetTest {public static void main(String[] args) {Set<Student> treeSet = new TreeSet();treeSet.add(new Student("zhangsan", 15));treeSet.add(new Student("zhangsan", 15));treeSet.add(new Student("lisi", 16));treeSet.add(new Student("wangwu", 17));for (Student s : treeSet) {System.out.println(s.getName());}}
}

上面的 Student 類實現了 Comparable 接口,并實現了 compareTo() 方法。利用compare(Object target)方法,比較當前對象和target的大小,如果想從小到大排列,則當前對象的屬性小于 target 的屬性,返回負數,如果相等,返回0,如果大于,返回正數,則就實現了從小到大排列,反之從大到小排列。上面是直接通過name調用String 類的 compareTo 方法實現返回值。

需要注意,添加到 TreeSet 中,比較兩個對象是否相等,是通過 compareTo 方法判斷的,不是equals。


定制排序

當默認的自然排序不滿足需求時,可以使用定制排序,定制排序通常通過傳遞一個實現了Comparator接口的比較器對象給TreeSet的構造函數來實現,通過實現compare(Object o1, Object o2)方法來實現排序邏輯,使用定制排序,可以靈活地定義元素之間的順序,而不必要求元素自身實現Comparable接口。

舉個栗子:

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;// 不用實現接口了
class Student {private String name;private int age;public Student(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 class TreeSetTest {public static void main(String[] args) {Comparator<Student> comparator = new Comparator<Student>() {//按照年齡從小到大排列@Overridepublic int compare(Student o1, Student o2) {if(o1 instanceof Student && o2 instanceof Student){// 年齡相等就算相同return Integer.compare(o1.getAge(), o2.getAge());}else{throw new RuntimeException("類型不匹配");}}};Set<Student> treeSet = new TreeSet(comparator);treeSet.add(new Student("zhangsan", 15));treeSet.add(new Student("zhangsan", 15));treeSet.add(new Student("lisi", 15));treeSet.add(new Student("wangwu", 17));for (Student s : treeSet) {System.out.println(s.getName());}}
}

執行結果:

zhangsan
wangwu

2 Properties

Properties 類是Hashtable的子類,主要用于處理屬性文件,Properties 里的key value 都是字符串類型。

存儲數據使用setProperty(String key,Stringvalue)方法,獲取數據使用getProperty(String key)方法。

舉個例子:

首先在項目根目錄下新建一個 .properties 文件:

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

編輯內容如下:

username=doubibiji
password=123456

上面就是使用了 key=value 的方式定義兩個配置。

下面使用 Properties 讀取配置:

package com.doubibiji;import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;public class PropertiesTest {public static void main(String[] args){FileInputStream fis = null;try {Properties pros = new Properties();fis = new FileInputStream("test.properties");//加載文件中的配置到Properties對象中pros.load(fis); // 獲取配置String username = pros.getProperty("username");String password = pros.getProperty("password");System.out.println("username=" + username); // username=doubibijiSystem.out.println("password=" + password); // password=123456} catch (IOException e) {e.printStackTrace();} finally {if(fis != null){try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}
}

如果存在中文亂碼問題,可以使用如下方式解決:

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/14002.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/14002.shtml
英文地址,請注明出處:http://en.pswp.cn/web/14002.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【stm32/CubeMX、HAL庫】嵌入式實驗六:定時器(2)|PWM輸出

參考&#xff1a; 【【正點原子】手把手教你學STM32CubeIDE開發】 https://www.bilibili.com/video/BV1Wp42127Cx/?p13&share_sourcecopy_web&vd_source9332b8fc5ea8d349a54c3989f6189fd3 《嵌入式系統基礎與實踐》劉黎明等編著&#xff0c;第九章定時器&#xff0c…

愛普生TG5032SFN溫補晶振在機器人控制中的應用

機器人控制是機器人技術的核心組成部分&#xff0c;它涉及通過傳感器采集外部環境信息&#xff0c;然后經過信號處理、運動規劃和執行控制等步驟&#xff0c;最終實現機器人的運動控制和任務執行。在技術的不斷更選&#xff0c;機器人控制也在不斷進步和演變。智能化機器人具備…

cannot compute sizeof(off_t) when compile netcdf-fortran

export LD_LIBRARY_PATH/netcdf-c/lib:$LD_LIBRARY_PATH

Z緩沖技術在AI去衣中的關鍵角色

引言&#xff1a; 人工智能&#xff08;AI&#xff09;技術的飛速發展&#xff0c;為圖像處理領域帶來了革命性的變化。其中&#xff0c;AI去衣技術作為一種新興的應用&#xff0c;引起了廣泛關注。它不僅在多媒體內容的編輯、虛擬現實和增強現實等領域具有重要的應用價值&…

Jenkins 構建 Maven 項目:項目和服務器在一起的情況

bash.sh內容 #!/bin/bash#刪除歷史數據 rm -rf ruoyi-admin.jar# appname$1 appnamevideo.xxxxx.com #獲取傳入的參數 echo "arg:$appname"#獲取正在運行的jar包pid # pidps -ef | grep $1 | grep java -jar | awk {printf $2} pidps -ef | grep $appname | grep ja…

1673. 找出最具競爭力的子序列

題目 給定一個整數數組 nums 和一個正整數 k&#xff0c;返回長度為 k 且最具競爭力的 nums 子序列。 數組的子序列是從數組中刪除一些元素&#xff08;可能不刪除元素&#xff09;得到的序列。 在子序列 a 和子序列 b 第一個不相同的位置上&#xff0c;如果 a 中的數字小于…

mysql 刪除特殊字符 表中存了特殊字符 換行符 回車符 word字符 查詢不到

省流&#xff1a; UPDATE t1 SET f1 REPLACE(REPLACE( f1 , CHAR(10), ), CHAR(13), ); 用 replace() 函數將 換行符char(10) 和 回車符char(13) 替換為空字符串。 char(10)&#xff1a;換行 char(13)&#xff1a;回車 發現表里存進很多換行符&#xff0c;如下圖&#xff1a…

深入研究Qt Meta - Object System

目錄 先說RTTI 再說QMeta Object System 關于Q_OBJECT 這篇文章我打算研究一下QMetaObject System&#xff0c;也就是Qt自己構建起來的元對象系統。 先說RTTI 啥是RTTI&#xff1f;這是C編程里的一個常見術語&#xff0c;全稱是&#xff1a;運行階段類型識別&#xff08;Ru…

Chrome DevTools攻略

Chrome DevTools&#xff0c;也稱為Chrome開發者工具&#xff0c;是一套直接內置于Google Chrome瀏覽器的Web開發者工具。以下是一些使用Chrome DevTools的攻略和技巧&#xff1a; 打開DevTools&#xff1a; 右鍵點擊頁面上的任何元素&#xff0c;選擇“檢查”或“審查元素”。…

2024年華為OD機試真題-機場航班調度程序-C++-OD統一考試(C卷D卷)

題目描述: XX市機場停放了多架飛機,每架飛機都有自己的航班號CA3385,CZ6678,SC6508等,航班號的前2個大寫字母(或數字)代表航空公司的縮寫,后面4個數字代表航班信息。但是XX市機場只有一條起飛用跑道,調度人員需要安排目前停留在機場的航班有序起飛。為保障航班的有序起…

【webrtc】MediaEngine的實現CompositeMediaEngine創建VOE

m98音視頻的引擎是管理channel的看起來是外部強加給CompositeMediaEngine 管理的。CompositeMediaEngine :合成媒體引擎 G:\CDN\rtcCli\m98\src\media\base\media_engine.h// CompositeMediaEngine constructs a MediaEngine from separate // voice and video engine classes…

Python中文分詞工具庫之jieba使用詳解

概要 在自然語言處理(NLP)領域,中文文本的分詞是一個重要且基礎的任務。Python的jieba庫是一個廣泛使用的中文分詞工具,提供了豐富的功能,包括精準模式、全模式、搜索引擎模式等,適用于不同的應用場景。本文將詳細介紹jieba庫,包括其安裝方法、主要特性、基本和高級功能…

代碼隨想錄35期Day49-Java

Day49題目 LeetCode123買賣股票三 核心思想:和昨天的買賣股票相比,這個只允許買兩次,因此把狀態新增幾個,可見代碼注釋 class Solution {public int maxProfit(int[] prices) {// 設置五個狀態 0 : 無操作 , 1 : 第一次買入, 2 : 第一次賣出 , 3: 第二次買入, 4:第二次賣出…

java技術:oauth2協議

目錄 一、黑馬程序員Java進階教程快速入門Spring Security OAuth2.0認證授權詳解 1、oauth服務 WebSecurityConfig TokenConfig AuthorizationServer 改寫密碼校驗邏輯實現類 2、oauth2支持的四種方式&#xff1a; 3、oauth2授權 ResouceServerConfig TokenConfig 4、…

前端面試題日常練-day19 【面試題】

題目 希望這些選擇題能夠幫助您進行前端面試的準備&#xff0c;答案在文末。 1. AJAX是什么的縮寫&#xff1f; A. Asynchronous JavaScript and XMLB. Asynchronous JavaScript and XHTMLC. Asynchronous Java and XMLD. Asynchronous Java and XHTML2. 下列哪個方法用于創建…

SpringCloudAlibaba 動態讀取配置文件的信息

傳統讀取方式&#xff1a; 在application.properties中寫入要讀取的內容&#xff0c;如下&#xff1a; coupon.user.nameTom coupon.user.age27 接口引入處&#xff1a; Value("${coupon.user.name}")private String name;Value("${coupon.user.age}")p…

MySQL的索引是什么

MySQL的索引 一、索引概述二、索引結構1.簡要概述2.從二叉樹說起3.再在說下B-Tree4.為什么選擇BTree5.Hash又是什么6.博主被面試官經常問的題目 三、索引分類四、聚集索引&二級索引五、索引語法 一、索引概述 1.索引是幫助MySQL 高效獲取數據的數據結構(有序)。在數據之外…

[STM32-HAL庫]Flash庫-HAL庫-復雜數據讀寫-STM32CUBEMX開發-HAL庫開發系列-主控STM32F103C6T6

目錄 一、前言 二、實現步驟 1.STM32CUBEMX配置 2.導入Flash庫 3.分析地址范圍 4.找到可用的地址 5.寫入讀取普通數據 6.寫入讀取字符串 6.1 存儲相關信息 6.2 存取多個參數 三、總結及源碼 一、前言 在面對需要持久化存儲的數據時&#xff0c;除了掛載TF卡&#xff0c;我們…

燃數科技前端25-40K*14薪一面超簡單,下周二面啦

一面 1、自我介紹 2、低代碼如何設計的 3、react路由原理 4、react生命周期 5、什么是回調地獄&#xff0c;如何解決 6、jwt和session有什么區別 7、js文件相互引用有什么問題&#xff1f;如何解決 8、一個很大的json文件&#xff0c;前端讀取如何優化 面試我的不像是…

為什么說 Redis 是單線程的?——Java全棧知識(25)

為什么說 Redis 是單線程的&#xff1f; 我們常說的 Redis 是單線程的&#xff0c;但是我前面在講持久化機制的時候又說 RDB 的持久化是通過主進程 fork 出一個子進程來實現 RDB 持久化。那么 Redis 到底是多線程還是單線程的呢&#xff1f; Redis 的網絡 IO 和鍵值的讀寫是單…