Java基础之集合Map
在java.util包中的集合类包含了除List之外还有另一套常用集合类:Map。
Map提供了一个更通用的元素存储方法,那就是“键值对”存储。
元素对(称作“键”和“值”),其中每个键映射到一个值。
如果说数组或者集合中的某一个值是通过下标来获取,那么Map中的值就是通过对应的键来获取。
比如我们有一个要暂存一个名字是张三的数据,Map就可以供我们设置键是name,值是张三:Map<"name", "张三">
Map接口
首先也是看根接口:Map接口,这里的K就是key键,V就是value值。
Map接口中定义了通用的存(put)取(get)方法,还有一些判空isEmpty、移除键值对remove、清空clear等等。
抽象类AbstractMap<K,V>实现了Map<K,V>接口,我们也可以通过继承AbstractMap<K,V>抽象类来实现自己的Map。
Java内部提供了一些实现:
HashMap:基于哈希表的Map接口实现。允许使用null键和null值。不保证映射的顺序;特别是它不保证顺序会随着时间的推移保持不变。最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。
代码示例:
// 创建一个HashMap
Map<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("One", 1);
map.put("Two", 2);
map.put("Three", 3);
// 访问键值对
int value = map.get("Two"); // 返回2
System.out.println("Value of 'Two': " + value);
// 检查是否包含键或值
boolean containsKey = map.containsKey("One"); // 返回true
boolean containsValue = map.containsValue(3); // 返回true
System.out.println("Contains key 'One': " + containsKey);
System.out.println("Contains value 3: " + containsValue);
// 获取所有键的集合
Set<String> keys = map.keySet();
System.out.println("Keys: " + keys);
// 获取所有值的集合
Collection<Integer> values = map.values();
System.out.println("Values: " + values);
// 获取所有键值对的集合
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
// 删除一个键值对
int removedValue = map.remove("One"); // 返回1
System.out.println("Removed value: " + removedValue);
// 替换一个键值对
map.replace("Two", 22);
System.out.println("Map after replacement: " + map);
// 如果键不存在,则添加键值对
map.putIfAbsent("Four", 4);
System.out.println("Map after putIfAbsent: " + map);
// 获取键对应的值,如果键不存在,则返回默认值
int defaultValue = map.getOrDefault("Five", 5);
System.out.println("Default value for 'Five': " + defaultValue);
// 检查Map是否为空
boolean isEmpty = map.isEmpty();
System.out.println("Is map empty? " + isEmpty);
// 获取Map的大小
int size = map.size();
System.out.println("Size of map: " + size);
// 清空Map
map.clear();
System.out.println("Map after clear: " + map);
Hashtable:类似于HashMap,但是它是同步的。不允许使用null键或null值。现在已经被ConcurrentHashMap替代,因为后者提供了更好的并发性能。
// Hashtable
Map<String, Integer> hashtable = new Hashtable<>();
hashtable.put("Two", 2);
System.out.println("Hashtable: " + hashtable);
Properties:用于处理属性文件。键和值都是字符串。项目中的配置文件一般就是这个。
代码示例:
// Properties
Properties properties = new Properties();
properties.setProperty("Three", "3");
System.out.println("Properties: " + properties);
LinkedHashMap:继承自HashMap,维护了插入的顺序。
代码示例:
// LinkedHashMap
Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("Four", 4);
System.out.println("LinkedHashMap: " + linkedHashMap);
IdentityHashMap:使用==而不是equals来比较键。主要用于需要保持键的身份信息的情况。
代码示例:
// IdentityHashMap
Map<String, Integer> identityHashMap = new IdentityHashMap<>();
identityHashMap.put(new String("Five"), 5);
System.out.println("IdentityHashMap: " + identityHashMap);
TreeMap:基于红黑树的实现,实现了SortedMap接口。可以确保键的顺序。能够把它保存的记录根据键(key)排序,默认是按升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。TreeMap不允许key的值为null。非同步的。
代码示例:
// TreeMap
Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("Six", 6);
System.out.println("TreeMap: " + treeMap);
WeakHashMap:允许键对象被垃圾回收器回收。主要用于缓存实现。
代码示例:
// WeakHashMap
Map<String, Integer> weakHashMap = new WeakHashMap<>();
weakHashMap.put("Seven", 7);
System.out.println("WeakHashMap: " + weakHashMap);
ConcurrentHashMap:支持高并发性的哈希表实现。允许多个线程并发访问,并且是线程安全的。
代码示例:
// ConcurrentHashMap
Map<String, Integer> concurrentHashMap = new ConcurrentHashMap<>();
concurrentHashMap.put("Eight", 8);
System.out.println("ConcurrentHashMap: " + concurrentHashMap);
EnumMap:键必须是枚举类型。它的性能比传统的HashMap要高,因为它是针对枚举类型优化的。
代码示例:
// EnumMap
Map<Day, String> enumMap = new EnumMap<>(Day.class);
enumMap.put(Day.MONDAY, "Monday");
System.out.println("EnumMap: " + enumMap);
}
enum Day {
MONDAY, TUESDAY, WEDNESDAY
}
}
SortedMap:接口,不是实现,但是可以用于创建排序的映射。
// SortedMap 示例
SortedMap<String, Integer> sortedMap = new TreeMap<>();
sortedMap.put("Three", 3);
sortedMap.put("One", 1);
sortedMap.put("Two", 2);
// 按顺序遍历SortedMap
System.out.println("SortedMap:");
for (Map.Entry<String, Integer> entry : sortedMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
NavigableMap:扩展了SortedMap,提供了更多的导航方法。如headMap、tailMap和subMap,这些方法允许我们获取映射的子集。
// NavigableMap 示例
NavigableMap<String, Integer> navigableMap = new TreeMap<>(sortedMap);
// 使用headMap返回小于指定键的子映射
NavigableMap<String, Integer> headMap = navigableMap.headMap("Two", true);
System.out.println("HeadMap (<= 'Two'): " + headMap);
// 使用tailMap返回大于等于指定键的子映射
NavigableMap<String, Integer> tailMap = navigableMap.tailMap("Two");
System.out.println("TailMap (>= 'Two'): " + tailMap);
// 使用subMap返回指定范围内的子映射
NavigableMap<String, Integer> subMap = navigableMap.subMap("One", false, "Three", true);
System.out.println("SubMap ('One', 'Three'): " + subMap);
// 获取第一个键和对应的值
Map.Entry<String, Integer> firstEntry = navigableMap.firstEntry();
System.out.println("First Entry: " + firstEntry.getKey() + ": " + firstEntry.getValue());
// 获取最后一个键和对应的值
Map.Entry<String, Integer> lastEntry = navigableMap.lastEntry();
System.out.println("Last Entry: " + lastEntry.getKey() + ": " + lastEntry.getValue());
自定义Map实现: AbstractMap提供了Map接口的基本实现,以减少实现Map接口的工作量。可以用来创建自定义Map实现
示例:
class CustomMap extends AbstractMap<String, Integer> {
private Map<String, Integer> innerMap = new HashMap<>();
@Override
public Set<Entry<String, Integer>> entrySet() {
return innerMap.entrySet();
}
public void putCustom(String key, Integer value) {
innerMap.put(key, value);
}
}
CustomMap customMap = new CustomMap();
customMap.putCustom("One", 1);
customMap.putCustom("Two", 2);
System.out.println("CustomMap: " + customMap);
最常用的就是HashMap和SetMap,其他的了解即可。
几种遍历方法:
for遍历:
上面示例已经有过,可以使用keySet()方法来获取所有key列表,然后通过get(key)来获取对应的值,以实现遍历当前Map:
// 使用keySet()遍历
for (String key : map.keySet()) {
System.out.println(key + " :" + map.get(key));
}
// 使用entrySet()遍历
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + " :" + entry.getValue());
}
迭代器遍历:
// 使用keySet()遍历
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
System.out.println(key + " :" + map.get(key));
}
// 使用entrySet()遍历
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
System.out.println(entry.getKey() + " :" + entry.getValue());
}
遍历性能速度:
entrySet遍历的速度要比keySet快
迭代器的遍历速度要比增强for循环快, 增强for循环使用方便,但不适合处理超大量级的数据。
END