- 1️⃣ 双列对象保存:Map
-
-
- 1.1 HashMap 类与 Hashtable 类
- 1.2 使用 lterator 获取 Map 集合元素
- 1.3 自定义 Map 集合的 key 类型
- 1.4 LinkedHashMap 类
- 1.5 TreeMap 类
- 1.6 Properties 类
- 1.7 HashMap和 Hashtable的区别
-
- 2️⃣ Collections 工具类
- * 总结
1️⃣ 双列对象保存:Map
Collection
每次只能保存一个对象,所以属于单值保存父接口。而在类集中又提供了保存双列对象的集合:Map
集合,利用 Map
集合可以保存一对关联数据 (按照 “key = value
”的形式),如下所示,这样就可以实现根据 key
取得 value
的操作。
图1Collection 与 Map 保存的区别
下面是Map
体系的主要类继承关系:
图2Map 体系类继承关系
可以看到,Map
接口是所有Map
体系类的根接口,其中定义了一些基本的操作方法,如put()
、get()
、remove()
等;AbstractMap
是一个抽象类,它实现了Map
接口的骨架实现,提供了一些通用的功能。其他具体的Map
类通常继承自它。
而最常用的子类有: 使用哈希表实现的HashMap
,它允许使用null
作为键或值,并且不保证元素的顺序;基于链表实现的LinkedHashMap
,它保持插入顺序或访问顺序(可选); 还有基于红黑树实现的TreeMap
,它支持按照键的自然排序进行排序,或者通过Comparator
比较器自定义指定顺序。
而ConcurrentMap
接口则扩展了Map
接口,定义了一些支持并发访问的方法;ConcurrentHashMap
是线程安全的哈希表实现的Map
,支持高并发操作,并允许在遍历时进行修改操作。这两个类都是JUC
包中的对多线程并发安全做支撑的类,对于这两个类将在我后续的专栏《高并发编程》中详细介绍,敬请期待。
Hashtable
则是一个旧版的哈希表实现的Map
,线程安全,但性能较低,不推荐使用。它的功能与HashMap
类似,但不允许使用null
作为键或值。Properties
是一个特殊的Hashtable
子类,主要用于处理属性文件。它允许通过键-值对表示配置信息,并提供了一些方法方便地读取和写入这些配置信息。
在Map
接口中的常用方法如下所示。
方法名称 | 描述 |
---|---|
int size() |
返回Map 中键值对的数量 |
boolean isEmpty() |
检查Map 是否为空 |
boolean containsKey(Object key) |
检查Map 中是否包含指定的键 |
boolean containsValue(Object value) |
检查Map 中是否包含指定的值 |
V get(Object key) |
返回指定键对应的值 |
V put(K key, V value) |
将键值对添加到Map 中 |
V remove(Object key) |
根据键删除Map 中对应的键值对 |
void putAll(Map<? extends K, ? extends V> m) |
将另一个Map 中的所有键值对添加到当前Map 中 |
void clear() |
清空Map 中的所有键值对 |
Set<K> keySet() |
返回Map 中所有键组成的集合 |
Collection<V> values() |
返回Map 中所有值组成的集合 |
Set<Map.Entry<K, V>> entrySet() |
返回Map 中所有键值对组成的集合 |
default V getOrDefault(Object key, V defaultValue) |
返回指定键对应的值,如果键不存在则返回默认值 |
default V putIfAbsent(K key, V value) |
当指定的键不存在时,将键值对添加到Map 中 |
这些方法提供了在Map
中添加、获取、删除键值对,以及检查Map
的状态和遍历Map
的能力。需要根据具体情况选择适当的方法来完成所需的操作。
1.1 HashMap 类与 Hashtable 类
在Map
接口中存在两个常用的子类: HashMap
、Hashtable
,下面先介绍这两个子类的使用。
// 范例 1: 观察HashMap 子类的使用
package com.xiaoshan.demo;
import java.util.HashMap;
import java.util.Map;
public class TestDemo {
public static void main(String[] args){
Map<String, Integer> map = new HashMap<String, Integer>(); //定义Map 集合
map.put("壹",1); //保存数据
map.put("贰",2);
map.put("叁",3);
map.put("叁",33); //key数据重复
map.put("空",null); // value为null
map.put(null,0); // key为null
System.out.println(map); //输出map集合
}
}
程序执行结果:
(贰=2, null=0, 叁=33, 壹=1, 空=null)
程序实现了 Map
最为基础的数据保存操作,在实例化 Map
接口对象时首先需要明确地指定泛型类型,此处指定 key
的类型为 String
, value
的类型为 Integer
, 然后利用 put()
方法进行数据的保存。特别需要注意的是,在进行数据保存时,如果出现了key
重复的情况,就会使用新的数据覆盖或替换已有数据。
通过上边范例的操作可以发现 Map
如下特点:
- 使用HashMap 定义的Map 集合是无序存放的;
- 如果发现了重复的 key 会进行值的覆盖,使用新的内容替换旧的内容;
- 使用HashMap 子类保存数据时 key 或 value 允许保存 null。
但需要注意的是,上边范例的代码只是演示了 Map
的基本使用,然而 Map
保存数据的目的并不是进行输出操作,而常常是为了进行查找,即利用 get()
方法通过 key
获取到对应的 value
数据。
// 范例 2: 查询操作
package com.xiaoshan.demo;
import java.util.HashMap;
import java.util.Map;
public class TestDemo {
public static void main(String[] args){
Map<String, Integer> map =new HashMap<String,Integer>(); // 定义Map 集合
map.put("壹",1); //保存数据
map.put("贰",2);
map.put("叁",3);
map.put("叁",33); //key数据重复
map.put("空",null); // value为null
map.put(null,0); // key为null
System.out.println(map.get("壹")); //key存在返回value
System.out.println(map.get("陸")); //如果key不存在,返回null
System.out.println(map.get(null)); // key存在
}
}
程序执行结果:
1
null
0
此程序利用 Map
接口中的 get()
方法根据 key
取得了其对应的 value
内容,通过执行结果可以发现,如果指定的key
存在则会返回与之对应的 value
, 而如果 key
不存在则返回 null
。
通过范例2的代码可以发现,Map
接口在使用中依然只是保存数据与获取数据,那么为什么不直接使用Collection
呢,为什么还需要Map
接口呢?
首先Collection
与 Map
接口都可以保存动态长短的数据,然而两者本质的区别在于其使用的环境。Collection
接口保存数据的主要目的是输出(利用 Iterator
接口)而 Map
保存数据的目的是实现 key
查找value
的字典功能,虽然Map
也可以进行输出操作,但是这样的操作在开发中出现较少。
在Map
接口下还有一个 Hashtable
的子类,此类是在JDK 1.0时提供的,属于最早的Map
集合的实现操作。在JDK 1.2时 Hashtable
的子类多实现了一个Map
接口,从而得以保存下来继续使用。
Hashtable
与HashMap
都属于Map
接口的子类,所以从本质上讲,它们最终都会利用子类向上转型为Map
接口对象实例化。但是在使用Hashtable
子类实例化的Map
集合中,保存的key
或value
都不允许出现null
,否则会出现"NullPointerException
" 异常 。
// 范例 3: 使用 Hashtable
package com.xiaoshan.demo;
import java.util.Hashtable;
import java.util.Map;
public class TestDemo {
public static void main(String[] args){
Map<String, Integer> map =new Hashtable<String, Integer>(); // 定义Map 集合
map.put("壹",1); //保存数据
map.put("贰",2);
map.put("叁",3);
map.put("叁",33); //key 数据重复
System.out.println(map.get("壹")); // key存在返回value
System.out.println(map.get("陸")); //key 不存在,返回null
}
}
程序执行结果:
1
null
此程序利用 Hashtable
子类实例化了 Map
接口,由于接口操作标准统一,所以 put()
与 get()
方法都可以正常使用,在使用 get()
方法进行数据查找时,如果数据不存在则返回 null
。
在实际开发中,由于 HashMap
保存数据不受 null
的限制,所以建议优先考虑使用HashMap
子类。
1.2 使用 lterator 获取 Map 集合元素
首先大家必须明确一个开发原则:集合的输出要利用 Iterator
接口完成。但是 Map
接口与 Collection
接口在定义上有所不同, Map
接口并没有提供直接取得 Iterator
接口对象的方法。所以如果要使用 Iterator
输出 Map
接口数据,就必须要清楚 Collection
接口与 Map
接口在数据保存形式上的区别,如下图所示。
图3Collection 与 Map 集合数据存储区别
可以发现,当用 Collection
集合保存数据时所有的对象都是直接保存的。而用 Map
集合保存数据时,所保存的 key
与 value
会自动包装为 Map.Entry
接口对象,也就是说如果利用 Iterator
进行迭代,那么每当使用 next()
方法读取数据时返回的都是一个 Map.Entry
接口对象,此接口定义如下。
public static interface Map.Entry<K,V>{
}
通过定义可以发现,Map.Entry
接口属于 Map
接口中定义的一个 static
内部接口(相当于外部接口)。Map.Entry
接口定义的常用方法如下所示。
方法 | 类型 | 描述 |
---|---|---|
public K getKey() |
普通 | 取得数据中的key |
public V getValue() |
普通 | 取得数据中的value |
public V setValue(V value) |
普通 | 修改数据中的value |
清楚了Map.Entry
接口作用后就可以来研究如何利用 Iterator
接口输出 Map
集合了,在 Map
接口中定义了一个 entrySet()
方法:public Set<Map.Entry<K,V>> entrySet()
,而实现 Map
接口输出的关键就在于此方法的使用上。
Iterator
输出 Map
集合的操作步骤如下:
(1)利用 entrySet()
方法将 Map
接口数据中的数据转换为 Set
接口实例进行保存,此时 Set
接口中所使用的泛型类型为 Map.Entry
, 而 Map.Entry
中的 K
与 V
的泛型类型则与 Map
集合定义的 K
与 V
类型相同;
(2)利用Set
接口中的 iterator()
方法将Set
集合转化为 Iterator
接口实例;
(3)利用 Iterator
接口进行迭代输出,每一次迭代取得的都是 Map.Entry
接口实例,利用此接口实例可以进行 key
与 value
的分离获取。
// 范例 4: 利用 Iterator 实现Map接口的输出
package com.xiaoshan.demo;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class TestDemo {
public static void main(String[] args){
Map<String, Integer> map = new Hashtable<String,Integer>();// 定义Map 集合
map.put("壹",1); //保存数据
map.put("贰",2);
map.put("叁",3);
map.put("叁",33); //key数据重复
Set<Map.Entry<String,Integer>> set = map.entrySet(); //将Map集合变为Set集合,目的是使用iterator()方法,注意泛型的统一
Iterator<Map.Entry<String,Integer>> iter = set.iterator(); //取得Iterator实例
while (iter.hasNext()){
//迭代输出
Map.Entry<String,Integer> entry = iter.next(); //取出Map.Entry
System.out.println(entry.getKey()+" = "+ entry.getValue()); // 输出数据
}
}
}
程序执行结果:
贰 = 2
壹 = 1
叁 = 33
程序按照给出的步骤实现了Iterator
接口输出 Map
集合的操作,其中最为关键的就是 Iterator
每次迭代返回的类型是Map.Entry
(注意泛型类型的设置), 而后利用 getKey()
与 getValue()
方法才可以取得所保存的 key
与 value
数据。
1.3 自定义 Map 集合的 key 类型
在使用Map
接口时可以发现,几乎可以使用任意的类型来作为 key
或 value
的存在,也就表示可以使用自定义的类型作为 key
。但要注意的是,作为key
的自定义的类必须要覆写 Object
类中的 hashCode()
与 equals()
两个方法,因为只有靠这两个方法才能确定元素是否重复,也即确认在Map
中能否找到元素,能找到则说明已有相同元素,再根据确认结果进行存储或覆盖等操作。
// 范例 5: 使用自己定义的类作为 Map 集合的key
package com.xiaoshan.demo;
import java.util.HashMap;
import java.util.Map;
class Book {
//此类为要保存的 key 类型
private String title; //只定义一个属性
public Book(String title){
//构造方法接收数据
this.title = title;
}
@Override
public String toString(){
return "书名:"+ this.title;
}
@Override
public int hashCode(){
//取得对象编码
final int prime =31;
int result =1;
result = prime* result + (title == null) ? 0 : title.hashCode();
return result;
}
@Override
public boolean equals(Object obj){
//进行对象比较
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Book other = (Book) obj;
if (title == null){
if (other.title != null){
return false;
}
}else if (!title.equals(other.title)){
return false;
}
return true;
}
}
public class TestDemo {
public static void main(String[] args){
Map<Book,String> map = new HashMap<Book,String>(); //实例化Map 接口集合
map.put(new Book("Java开发"),new String("Java")); //向Map 接口保存数据
System.out.println(map.get(new Book("Java开发"))); //根据key 取得value
}
}
程序执行结果:
Java
此程序使用一个自定义的Book
类作为 Map
集合中的 key
类型,由于已经正确地覆写了 hashCode()
与 equals()
方法,因此可以在 Map
集合中根据 key
找到对应的 value
数据。
虽然Map
集合中可以将各种数据类型作为 key
进行设置,但是从实际的开发来讲,不建议使用自定义类作为key
,建议使用Java中提供的系统类作为key
,如String
、Integer
等,其中String
作为key
的情况是最为常见的。
1.4 LinkedHashMap 类
LinkedHashMap
是Java中提供的一种基于链表和哈希表实现的有序Map
。它继承自HashMap
,并添加了一个双向链表用于维护插入顺序或访问顺序。
与普通的HashMap
不同,LinkedHashMap
会保持元素的插入顺序或访问顺序。具体来说,LinkedHashMap
维护了一个双向链表,每个节点都有指向前一个节点和后一个节点的引用。通过这个链表,LinkedHashMap
可以按照元素的插入顺序或最近访问的顺序进行迭代。
下面是一个使用LinkedHashMap
的代码示例,展示了如何保持元素的插入顺序以及访问顺序:
// 范例 6: LinkedHashMap 保持元素的插入顺序以及访问顺序
package com.xiaoshan.demo;
import java.util.LinkedHashMap;
import java.util.Map;
public class TestDemo {
public static void main(String[] args) {
// 创建一个具有默认插入顺序的LinkedHashMap
Map<String, Integer> map = new LinkedHashMap<>();
// 添加键值对到LinkedHashMap
map.put("Apple", 10);
map.put("Banana", 5);
map.put("Orange", 8);
// 遍历输出元素,按照插入顺序进行迭代
System.out.println("按照插入顺序遍历LinkedHashMap:");
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 创建一个具有自定义访问顺序(访问后放到最后)的LinkedHashMap
Map<String, Integer> accessOrderedMap = new LinkedHashMap<>(16, 0.75f, true);
accessOrderedMap.put("Apple", 10);
accessOrderedMap.put("Banana", 5);
accessOrderedMap.put("Orange", 8);
// 遍历输出元素,按照访问顺序进行迭代
System.out.println("按照访问顺序遍历LinkedHashMap:");
// 先访问一次"Banana"
accessOrderedMap.get("Banana");
// 再遍历输出时会将"Banana"放到最后
for (Map.Entry<String, Integer> entry : accessOrderedMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}
程序运行结果:
按照插入顺序遍历LinkedHashMap:
Apple: 10
Banana: 5
Orange: 8
按照访问顺序遍历LinkedHashMap:
Apple: 10
Orange: 8
Banana: 5
可以从结果发现,在默认情况下,LinkedHashMap
会保持元素的插入顺序。而如果在构造LinkedHashMap
时设置参数accessOrder
为true
,则会根据访问顺序进行迭代。当访问一个元素后,该元素会被移到链表的最后面。
1.5 TreeMap 类
TreeMap
是Java集合框架中的一种有序映射实现类,它通过红黑树(一种自平衡二叉查找树)来维护键值对的有序性。
TreeMap
将键值对按照键的自然排序或者通过指定的Comparator
进行排序。默认情况下,使用键的自然顺序进行排序,要求键实现了Comparable
接口。如果创建TreeMap
时提供了Comparator
对象,则会使用该Comparator
来排序键。
由于红黑树保持了有序性,TreeMap
可实现高效的检索、插入和删除操作。
下面是一个代码示例,演示了TreeMap
在默认情况下使用键的自然顺序排序,以及当提供Comparator
对象时使用该Comparator
进行排序:
// 范例 7: TreeMap在默认情况下使用键的自然顺序排序,当提供Comparator对象时使用该Comparator进行排序
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
class Person implements Comparable<Person> {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public int compareTo(Person o) {
return this.name.compareTo(o.getName());
}
}
class ReversedNameComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p2.getName().compareTo(p1.getName());
}
}
public class TreeMapSortExample {
public static void main(String[] args) {
// 默认情况下,TreeMap使用键的自然顺序进行排序
Map<Person, Integer> naturalOrderMap = new TreeMap<>();
naturalOrderMap.put(new Person("Alice"), 25);
naturalOrderMap.put(new Person("Charlie"), 20);
naturalOrderMap.put(new Person("Bob"), 30);
System.out.println("自然顺序排序:");
for (Person person : naturalOrderMap.keySet()) {
System.out.println(person.getName() + ": " + naturalOrderMap.get(person));
}
// 如果创建TreeMap时提供了Comparator对象,则使用该Comparator进行键的排序
Map<Person, Integer> customOrderMap = new TreeMap<>(new ReversedNameComparator());
customOrderMap.put(new Person("Alice"), 25);
customOrderMap.put(new Person("Charlie"), 20);
customOrderMap.put(new Person("Bob"), 30);
System.out.println("\n自定义顺序排序:");
for (Person person : customOrderMap.keySet()) {
System.out.println(person.getName() + ": " + customOrderMap.get(person));
}
}
}
在这个示例中,我们首先创建了一个Person
类来作为TreeMap
的键类型。Person
实现了Comparable
接口,通过实现compareTo()
方法来定义其自然顺序。然后,我们创建了一个ReversedNameComparator
类,它实现了Comparator
接口,用于自定义键的排序。
接下来,我们分别创建了默认使用自然顺序排序的TreeMap
和使用自定义排序的TreeMap
。我们将Person
对象作为键放入这两个TreeMap
中,并将它们遍历输出。
程序运行结果:
自然顺序排序:
Alice: 25
Bob: 30
Charlie: 20
自定义顺序排序:
Charlie: 20
Bob: 30
Alice: 25
可以发现,在默认情况下使用键的自然顺序进行排序。由于Person
实现了Comparable
接口,可以按照姓名的字典顺序对键进行排序。而在创建TreeMap
时提供了Comparator
对象时,那么将使用该Comparator
来排序键。我们创建了一个ReversedNameComparator
对象来反向排序Person
的键。
1.6 Properties 类
利用Map
集合可以将任意的数据类型设置为 Key
或 Value
的类型,虽然这样较为灵活,但是在某些开发中并不适用,所以在类集框架中提供了一个 Properties
子类,利用此子类只能保存字符串类型的数据 (key=value)。
Properties 类本身属于 Hashtable 的子类,但是由于 Properties 类都使用 String 数据类型进行操 作,所以在使用Properties类时主要使用本类所定义的方法。 Properties类常用方法如表13-10所示。
方法 | 描述 |
---|---|
Object setProperty(String key,String value) |
设置属性 |
String getProperty(String key) |
取得属性,如果key不存在则返回null |
String getProperty(String key, String defaultValue) |
取得属性,如果key不存在则返回默认值 |
void store(OutputStream out, String comments) throws IOException |
通过输出流保存属性内容,输出的同时可以设置注释信息 |
void load(InputStream inStream) throws IOException |
通过输入流读取属性内容 |
// 范例 8: 属性的基本操作
package com.xiaoshan.demo;
import java.util.Properties;
public class TestDemo{
public static void main(String[] args){
Properties pro = new Properties();
pro.setProperty("BJ","北京"); //保存属性信息
pro.setProperty("TJ","天津");
System.out.println(pro.getProperty("BJ")); //根据key取得属性信息
System.out.println(pro.getProperty("GZ"));
System.out.println(pro.getProperty("GZ","没有此记录")); //没有key返回默认值
}
}
程序执行结果:
北京
null
没有此记录
此程序是 Properties
类的基本操作,首先进行属性内容的设置,然后根据 key
取得指定的内容。在数据取得时如果有对应的 key
则可以直接输出 value
, 如果没有对应的 key
并且设置了默认值,则会输出默认值。
利用Properties
类还可以实现属性信息的输出流输出以及输入流读取操作,下面分别介绍这两个操作。
// 范例 9: 将属性信息保存在文件里
package com.xiaoshan.demo;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Properties;
public class TestDemo {
public static void main(String[] args) throws Exception {
Properties pro = new Properties();
pro.setProperty("BJ","北京"); //保存属性信息
pro.setProperty("TJ","天津");
//一般而言后缀可以随意设置,但是标准来讲,既然是属性文件,后缀就必须是*properties,这样做也是为了与国际化对应
//在进行属性信息保存时如果属性内容为中文则会自动进行转码操作
pro.store(new FileOutputStream(new File("D:"+ File.separator +"area.properties")),"Area Info");
}
}
此程序在属性设置完成后利用 store()
方法将属性内容设置到输出流中,由于使用的是文件输出流,所以最终属性的内容会保存在文件中,同时中文也会自动进行 UNICODE
编码转换。
当本机E
盘上存在了 area.properties
文件,那么就可以利用文件输入流 (FileInputStream
) 来进行数据的读取。
// 范例 10: 通过文件流读取属性内容
package com.xiaoshan.demo;
import java.io.File;
import java.io.FilelnputStream;
import java.util.Properties;
public class TestDemo {
public static void main(String[] args) throws Exception {
Properties pro = new Properties(); //实例化类对象
pro.load(new FileInputStream(new File("E:"+ File.separator+"area.properties")));
System.out.println(pro.getProperty("BJ"); //根据key取得value
}
}
程序执行结果:
北京
此程序利用 load()
方法加载了文件输入流中的属性内容,随后就可以根据 key
取得属性内容了。
在进行属性信息读取时可以发现,前面文章讲解的 ResourceBundle
与本节讲解的 Properties
类都支持属性文件(*.properties
)的读取,那么在实际开发中使用哪一种呢?
Properties
可以读取任意输入流,ResourceBundle
要结合国际化读取 *.prperties
文件。
ResourceBundle
类在进行资源文件读取时只能读取后缀为“*.properties
”的文件, 并且往往需要通过 Locale
类来设置当前国家及语言环境。但是Properties
类却可以不区分文件后缀,只要符合它保存数据的结构标准的输入流 (可能通过网络输入或用户输入) 数据都可以进行读取。理论上Properties
在读取上更加灵活,但是ResourceBundle
与 Locale
类结合读取不同语言资源文件的功能 Properties
类并没有。
所以如果读取国际化资源文件使用 ResourceBundle
类,如果读取一些配置信息则可以使用 Properties
类。
1.7 HashMap和 Hashtable的区别
在Map
接口中存在两个常用的子类:HashMap
和Hashtable
。尽管它们都是实现Map
接口,但它们具有一些区别和特点。
HashMap:
- HashMap是Map接口的最常用实现类之一,它基于哈希表实现;
- 允许使用null作为键或值;
- 不保证元素的顺序,即不保证迭代顺序和插入顺序相同;
- 具有较好的性能,在大多数情况下提供高效的数据存储和检索操作;
- 非线程安全,若在多线程环境下使用需进行同步处理。
Hashtable:
- Hashtable是早期Java版本提供的哈希表实现的Map类,现在已被HashMap取代,但仍然在一些旧的代码中使用;
- 不允许使用null作为键或值,否则将抛出NullPointerException;
- 具有较好的性能,在大多数情况下提供高效的数据存储和检索操作;
- 通过使用synchronized关键字进行方法级别的同步,使其成为线程安全的实现;
- 不保证元素的顺序。
需要注意的是,由于Hashtable
是线程安全的,可能会在某些应用中造成额外的开销。因此,在单线程环境下,推荐使用HashMap
,而在多线程环境下,如需要保证线程安全,可选择使用Hashtable
或者ConcurrentHashMap
。
除了线程安全性和对空键值的处理方式之外,HashMap
和Hashtable
在用法和功能上基本相似。因此,大部分情况下,可以优先选择使用HashMap
作为Map
的实现类。
2️⃣ Collections 工具类
Java 提供类库时考虑到用户的使用方便性,专门提供了一个集合的工具类—— Collections
, 这个工具类可以实现List、Set、Map 集合的操作。 Collections类的常用方法如下所示。
方法 | 描述 |
---|---|
boolean addAll(Collection<? super T> c, T... elements) |
实现集合数据追加 |
int binarySearch(List<? extends Comparable<? super T>> list, T key) |
使用二分查找法查找集合数据 |
void copy(List<? super T> dest, List<? extends T> src) |
集合复制 |
void reverse(List<?> list) |
集合反转 |
void sort(List<T> list) |
集合排序 |
通过上面列出的方法可以发现, Collections
提供了一些更为方便的辅助功能操作。下面通过一个简单的范例来进行 Collections工具类的使用验证。
// 范例 11: 为集合追加数据
package com.xiaoshan.demo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TestDemo(
public static void main(String[] args) throws Exception{
List<String> all= new ArrayList<String>(); // 实例化集合对象
//利用Collections类的方法向集合保存多个数据
Collections.addAll("xiaoshan","XIAOSHAN","小山","hellojava","HELLOWORLD");
Collections.reverse(all); //集合反转
System.out.println(all); //直接输出集合对象
}
}
程序执行结果:
[HELLOWORLD, hellojava, 小山, XIAOSHAN, xiaoshan]
程序首先实例化了一个空的集合对象,然后利用 Collections
类的 addAll()
方法一次性向集合中追加了多条数据,最后又利用 reverse()
方法实现了集合数据的反转操作。
需要注意区别的是,Collection
是集合操作的接口,包含List
子接口和Set
子接口;Collections
是集合操作的工具类,可以直接利用类中提供的方法,进行List
、Set
、Map
等集合的数据操作。
* 总结
在本文中,我们探讨了双列对象保存的一些关键概念和技术。首先,我们比较了HashMap
类和Hashtable
类,它们都是常用的Map
实现类,但有一些区别,例如线程安全性和对 null值的处理。接下来,我们介绍了使用迭代器(Iterator
)来获取Map
集合元素的方法,并演示了如何遍历Map
中的键值对。然后,我们学习了自定义Map
集合的键类型,并说明了为什么重写equals()
和hashCode()
方法对于正确的键值存储至关重要。
我们还介绍了其他一些常见的Map
实现类,包括LinkedHashMap
、TreeMap
和Properties
。最后,我们简要提及了Collections
工具类,该工具类提供了一系列静态方法来操作集合,例如排序、查找和同步等。
通过本文的学习,我们对双列对象保存的不同实现和应用有了更深入的了解。根据不同的需求和特点,我们可以选择适合的Map
实现类来满足我们的业务要求。同时,Collections
工具类也是开发中非常有用的工具,可以提高集合处理的效率和便捷性。
希望本文对读者能够提供有价值的信息,并在开发中对双列对象保存和Collections
工具类有所启发。
[ ]nbsp_nbsp 4