Map集合的实现类
HashMap和Hashtable(没写错哦~就是小写)实现类
HashMap是Map集合的典型实现类,它与Hashtable的关系,就像ArrayList与Vector的关系。
Hashtable是一个老实现类了(从JDK1.0),他有两个繁琐的方法:elements() 和 keys(),这俩相当于Map接口的 values()和 keySet() 方法,现在很少使用这两个方法。
除此之外,Hashtable和HashMap有两点典型区别:
Hashtable 是一个线程安全的Map实现,而HashMap是线程不安全的map实现,因此HashMap性能更高一些。
Hashtable 不允许使用null作为key和value,会引发NullPointException异常;但HashMap可以使用null作为key
和value(由于key不允许重复,所以keySet中只能有一个null,value中就可以由无数个null)
虽然Hashtable线程安全,但还是不建议使用Hashtable类,如果需要创建线程安全的Map实现类,可以通过Collections工具类把HashMap变成线程安全的。
HashMap与Hashtable中key不允许重复的判断依据和HashSet一样。如果使用自定义类作为key,重写该类的equals()和hashCode()的判断标准应该保持一致————当两个key通过equals方法返回true时,它们的hashCode()也应该相同。
与Hashset相同,尽量不要使用可变对象作为HashMap、Hashtable的key,如果确实需要使用可变对象作为HashMap和Hashtable的key,则尽量不要在程序中修改作为key的可变对象,否则会给访问带来很大麻烦。
LinkedHashMap实现类
就像HashSet有一个LinkedHashSet子类,HashMap也有一个LinkedHashMap子类。
LinkedHashMap也使用双向链表来维护key-value对的次序(其实只考虑key的次序)。该链表负责维护Map的迭代顺序,迭代顺序key-value的插入顺序保持一致。
LinkedHashMap可以避免对HashMap,Hashtable里的key-value进行排序(只需要保持插入顺序即可),同时又可避免使用TreeMap所增加的成本。
LinkedHashMap需要维护元素的插入顺序,所以性能略低于HashMap,但因为它以链表的形式来维护内部顺序,因此在迭代访问Map中的全部元素时有更好的性能。
LinkedHashMap linkedHashMap = new LinkedHashMap();
linkedHashMap.put("saber","阿尔托莉雅");
linkedHashMap.put("archer","吉尔伽美什");
linkedHashMap.put("emiya", "卫宫士郎");
//按put顺序输出
linkedHashMap.forEach((key,val)-> System.out.println(key+":"+val));
Properties 读写属性文件
Properties类是Hashtable类的子类,正如它的名字所暗示的,该对象在处理属性文件时特别方便(例如windows下的ini)。Properties类可以把Map对象和属性文件关联起来,而从把Map对象中的key-value对写入属性文件中。也可以把属性文件中“属性名=属性值“加载到Map对象中。
package com.woshi;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class PropertiesTest {
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
properties.setProperty("username","woshi");
properties.setProperty("password","666");
//将Properties中的key-value对保存到a.ini文件中
properties.store(new FileOutputStream("a.ini"),"comment line");
Properties prop = new Properties();
prop.setProperty("address","中国");
//加载配置文件到prop中
prop.load(new FileInputStream("a.ini"));
System.out.println(prop);
}
}
a.ini:
#comment line
#Mon Mar 16 16:51:52 CST 2020
password=666
username=woshi
Properties还可以把key-value的形式以xml文件保存起来,也可以从xml文件中加载key-value对。
SortedMap接口和TreeMap实现类
正如Set接口中派生出SortedSet子接口,SortedSet接口有一个TreeSet实现类一样,Map接口也有一个SortedMap接口,SortedMap接口也有一个TreeMap实现类。
TreeMap就是一个红黑树数据结构,每个key-value对即作为红黑树的一个节点。TreeMap存储key-value对(节点)时,需要根据key对节点进行排序。TreeMap可以保证所有的key-value对处于有序状态。
TreeMap也有两种排序方式:
- 自然排序:TreeSet的所有key必须实现Comparable接口,而且所有的key应该是同一个类的实例,否则会抛出ClassCastException异常。
- 定制排序:创建TreeMap时,传入一个Comparable对象,该对象负责对TreeMap中的所有key进行排序。采用定制排序时,不要求key实现Comparable接口。
类似于TreeSet中判断两个元素相等的标准,TreeMap中判断两个key相等的标准是:两个key通过compareTo()方法返回0。TreeMap则认为两个key是相等的。
所以,如果使用自定义类作为TreeMap的key,想让TreeMap良好的工作,则重写该类的equals()方法和compareTo()方法时应该保持一致的结果,一个返回true时,另一个返回0。
package com.woshi;
import java.util.TreeMap;
class R implements Comparable{
int count;
public R(int count) {
this.count = count;
}
@Override
public String toString() {
return "R{" +
"count=" + count +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
R r = (R) o;
return count == r.count;
}
@Override
public int compareTo(Object o) {
R r = (R)o;
return count > r.count ? 1 : count < r.count ? -1 : 0;
}
}
public class TreeMapTest {
public static void main(String[] args) {
TreeMap treeMap = new TreeMap();
treeMap.put(new R(3),"3");
treeMap.put(new R(-9), "-9");
treeMap.put(new R(-2), "-2");
treeMap.put(new R(5), "5");
System.out.println(treeMap);
//返回该TreeMap的第一个对象
System.out.println(treeMap.firstEntry());
//返回该TreeMap的最后一个对象
System.out.println(treeMap.lastEntry());
//返回该TreeMap的比new R(2)大的最小key值
System.out.println(treeMap.higherKey(new R(2)));
//返回该TreeMap的比new R(2)小的最大key-value
System.out.println(treeMap.lowerEntry(new R(2)));
//返回该TreeMap的子TreeMap(仍然是前包括后不包括)
System.out.println(treeMap.subMap(new R(-10),new R(3)));
}
}
输出结果:
{R{count=-9}=-9, R{count=-2}=-2, R{count=3}=3, R{count=5}=5}
R{count=-9}=-9
R{count=5}=5
R{count=3}
R{count=-2}=-2
{R{count=-9}=-9, R{count=-2}=-2}