更好的閱讀體驗:點這里 ( 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]
插入元素
插入元素也是使用 add
和 addAll()
方法,使用第一個參數指定插入的位置即可。
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是一種鍵值對的數據結構,其中每個鍵對應一個值。
例如有一份數據:
姓名 | 成績 |
---|---|
zhangsan | 94 |
lisi | 96 |
wangwu | 91 |
使用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>
分別表示 key
和 value
對應的數據類型。
同樣,也是可以使用 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 表達式接收鍵和值,并在控制臺打印出每個學生的分數。
使用 keys
或 values
屬性
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
TreeSet
是 SortedSet
接口的實現類,添加到 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();}}}}
}
如果存在中文亂碼問題,可以使用如下方式解決: