本文已参与「新人创作礼」活动,一起开启掘金创作之路
Map用于保存具有映射关系的数据,因此Map集合里保存着两组值,一组值用于保存Map里的Key,key和value 都可以是任何引用类型数据。Map的Key不允许重复,即同一个Map对像的任何两个key通过equals方法比较总是返回false;
public class MapTest {
public static void main(String[] args) {
Map map = new HashMap();
map.put("疯狂java讲义", 109);
map.put("疯狂iOS讲义", 10);
map.put("疯狂Ajax讲义", 79);
map.put("轻量级java EE企业应用实战",99);
System.out.println(map.put("疯狂iOS讲义", 99));
System.out.println(map);
System.out.println("是否包含值为 疯狂iOS讲义 key: "+
map.containsKey("疯狂iOS讲义"));
System.out.println("是否包含值为99的 value: " +
map.containsValue(99));
for (Object key : map.keySet()) {
System.out.println(key+"-->"+map.get(key));
}
map.remove("疯狂Ajax讲义");
System.out.println(map);
}c
}
HashMap 和 Hashtable 实现类
HashMap和Hashtable都是Map接口的典型实现类,它们之间的关系完全类似于ArrayList和Vector的关系:
public class Tes01 {
public static void main(String[] args) {
// 无序,唯一
Map map = new HashMap();
map.put("a",1);
map.put("b",2);
map.put("c",3);
map.put("d",4);
map.put("e",5);
map.put(null,89);
System.out.println(map.size());
System.out.println(map);
System.out.println(map.containsKey("a"));
System.out.println(map.containsValue(1));
Map map2 = new HashMap();
map2.put("a",1);
map2.put("b",2);
map2.put("c",3);
map2.put("d",4);
map2.put("e",5);
System.out.println(map == map2);
System.out.println(map.equals(map2));
Set<String> set = map.keySet();
for (String s : set) {
System.out.println(s);
}
Collection<Integer> values = map.values();
for (Integer i : values) {
System.out.println(i);
}
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String, Integer> e : entries) {
System.out.println(e.getKey()+"--"+e.getValue());
}
}
}
Hashtable是一个古老的Map实现类,它从JDK1.0就出现了。
java8改进了 HashMap的实现,使用HashMap存在key冲突时依然具有较好的性能。
- Hashtable是一个线程安全的Map实现,但HashMap是线程不安全的实现,所以HashMap的性能比Hashtable的性能高一点,但如果有多个线程访问同一个Map对象时,使用Hashtable实现类会更好。
- Hashtable不允许使用null作为key和value,如果试图把null值放进Hashtable中,将会应发NullPointerException异常,但HasHMap可以使用null作为key或value
public class Test02 {
public static void main(String[] args) {
Map map3 = new Hashtable();
map3.put("a",1);
map3.put("b",2);
map3.put("c",3);
map3.put("d",4);
map3.put("e",5);
// 不能存入空值,运行时会报错
map3.put(null,null);
System.out.println(map3.size());
System.out.println(map3);
System.out.println(map3.containsKey("a"));
System.out.println(map3.containsValue(1));
}
}
LinkedHashMap实现类
HashSet 有一个LinkedHasahSet子类,HashMap 也有一个LinkedHashMap子类;LinkedHashMap也使用双向链表来维护 key-value 对的次序(其实只需要考虑key的次序),该链表负责维护Map的迭代顺序,迭代顺序与key-value 对的插入顺序保持一致。
LinkedHashMap 可以避免对HashMap, Hashtable里的key-value 对进行排序(只要插入key-value对时保持顺序即可),同时又避免使用TreeMap所增加的成本。
public class LinkedHashMapTest {
public static void main(String[] args) {
LinkedHashMap score = new LinkedHashMap();
score.put("语文", 80);
score.put("英文", 82);
score.put("数学", 76);
score.forEach((key, Value) -> System.out.println(key+"--->"+Value));
}
}
使用Properties 读写属性文件
Properties 类是Hashtable类的子类,正如它的名字所暗示的,该对象在处理属性文件时特别方便(windows操作平台上的ini文件就是一种属性文件)。Properties类可以把Map对象和属性文件关联起来,从而可以把Map对象中的key-value对写入属性文件中,也可以把属性文件中的"属性名=属性值"加载到Map对象中。由于属性文件里的属性名,属性值只能是字符串类型,所以Propertise里的keys,value都是字符串类型。
public class PropertiesTest {
public static void main(String[] args) throws Exception{
Properties props = new Properties();
props.setProperty("usernames","yeeku");
props.setProperty("password","123456");
props.store(new FileOutputStream("D:\\a.ini"),
"comment line");
System.out.println(props);
Properties props2 = new Properties();
props.setProperty("gender","male");
props2.load(new FileInputStream("D:\\a.ini"));
System.out.println(props2);
System.out.println(props);
}
}
SortedMap接口 和 TreeMap实现类
正如Set接口派生出SortedSet子接口,SortedSet接口有一个TreeSet实现类一样,Map也派生出一个SortedMap子接口,SortedMap接口也有一个TreeMap实现类。
TreeMap 就是一个红黑树数据结构,每个 key-value对即作为红黑树的一个节点。TreeMap存储 key-value 对(节点)时,需要根据key对节点进行排序。TreeMap 可以保证所有的 key-value 对处于有序状态。TreeMap也有两种排序方式。
- 自然排序: TreeMap 的所有key 必须实现 Comparable 接口,而且所有的key 应该说同一个类的对象,否则将会抛出ClassCastException 异常。
- 定制排序:创建TreeMap时,传入一个Comparator 对象,该对象负责对TreeMap中的所有的key进行排序。采用定制排序时不要求Map的key实现Comparable接口。
public class Student implements Comparable<Student>{
private int age;
private String name;
private double height;
public Student() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public Student(int age, String name, double height) {
this.age = age;
this.name = name;
this.height = height;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", height=" + height +
'}';
}
@Override
public int compareTo(Student o) {
// return this.getAge()-o.getAge();
return (this.getName()).compareTo(o.getName());
}
}
public class Test01 {
public static void main(String[] args) {
Map<String, Integer> map = new TreeMap<>();
map.put("a",1);
map.put("b",2);
map.put("c",3);
map.put("d",4);
map.put("e",5);
System.out.println(map);
System.out.println(map.size());
}
}
public class Test03 {
public static void main(String[] args) {
Map<Student, Integer> map = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return ((Double)o1.getHeight()).compareTo((Double)o2.getHeight());
}
});
map.put(new Student(19,"a",170.5),1);
map.put(new Student(19,"b",170.5),2);
map.put(new Student(19,"c",170.5),3);
map.put(new Student(19,"d",170.5),4);
map.put(new Student(19,"e",170.5),5);
System.out.println(map);
System.out.println(map.size());
}
}
WeakHashMap 实现类
weakHashMap 与 HashMap 的用法基本相似。与HashMap的区别在于,HashMap 的 key保留了对实际对象的强引用,这意味着只要该HashMap对象不被销毁,该HashMap的所有key所引用的对象就不会被垃圾收回,HashMap 也不会自动删除这些key 所对应的key-value对;但WeakHashMap 的Key只保留了对实际对象的弱引用,这意味着如果WeakHashMap 对象的key所引用的对象没有被其他强引用变量所引用,则这些key所引用的对象可能被回收,WeakHashMap也可能自动删除这些Key 所对应的key-value对。
public class WeakHashMapTest {
public static void main(String[] args) {
WeakHashMap whm = new WeakHashMap();
whm.put(new String("语文"),new String("良好"));
whm.put(new String("数学"),new String("及格"));
whm.put(new String("英文"),new String("中等"));
whm.put("java",new String("中等"));
System.out.println(whm);
System.gc();
System.runFinalization();
System.out.println(whm);
}
}
IdentityHashMap 实现类
这个 Map 实现类的实现机制与 HashMap 基本相似,但它处理两个key 相等时比较独特 : 在IdentityHashMap中,当且仅当两个key严格相等(key1 == key2)时,IndentityHashMap才认为两个key相等;
public class IdentityHashMapTest {
public static void main(String[] args) {
IdentityHashMap ihm = new IdentityHashMap();
// 下面两行代码将会向IdentityHashMap对象中添加两个key-value;
ihm.put(new String("语文"),89);
ihm.put(new String("语文"),78);
// 下面两行代码将会向IdentityHashMap对象中添加一个key-value;
ihm.put("java", 93);
ihm.put("java", 98);
System.out.println(ihm);
}
}
EnumMap
EnumMap是一个与枚举类一起使用的Map实现, EnumMap 中的所有key 都必须是单个枚举类的枚举类。 创建EnumMap时必须显示或隐式指定它对应的枚举类。
enum Season{
SPRING,SUMMER,FALL,WINTER
}
public class EnumMapTest {
public static void main(String[] args) {
EnumMap enumMap = new EnumMap(Season.class);
enumMap.put(Season.SUMMER, "夏日炎言");
enumMap.put(Season.SPRING, "春暖花开");
System.out.println(enumMap);
}
}
各Map实现类的性能分析
对于 Map的常用实现类而言,虽然HashMap和 Hashtable 的实现机制几乎一摸一样,但由于Hashtable 是一个古老的,线程安全的集合,因此HashMap 通常比Hashtable 要快。
TreeMap 通常比 HashMap, Hashtable要慢,(尤其在插入,删除key-value对时更慢), 因为TreeMap底层采用红黑树来管理 key-value 对 (红黑树的每一个节点就是一个key-value)
使用TreeMap 有一个好处:TreeMap 中的 key-value对总是处于有序状态,无序专门进行排序操作。当TreeMap 被填充之后,就可以调用keySet(),取得由key组成的Set,然后使用toArray()方法生成key的数组,接下来使用Arrays的binarySearch()方法在已排序的数组中快速地查询对象。
应该多使用HashMap, 因为HashMap查询快(底层是数组来存储key-value对),如果需要一个总是一个排好序的Map时,则可以考虑使用TreeMap.
LinkedHashMap 比 HashMap 慢一点,因为它需要维护链表来保持Map中key-value时的添加顺序,IdentityHashMap 性能没有特别之处,和HashMap基本相似的实现,只是它使用==而不是equals() 方法来判断元素相等。EnumMap性能最好,但它只能使用同一个枚举类的枚举值作为key。
java提供了一个操作Set, List 和 Map等集合的工具类: Collections,
public class Test01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("cc");
list.add("bb");
list.add("cc");
Collections.addAll(list,"dd","ee","ff");
Collections.addAll(list,new String[]{"gg","oo","pp"});
System.out.println(list);
// binarySearch二分查找
Collections.sort(list);//升序方式
System.out.println(list);
System.out.println(Collections.binarySearch(list, "cc"));
System.out.println("====================================");
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2,"tt","ss");
// 替换方法
Collections.copy(list,list2);//将list2上的内容替换到list上面
System.out.println(list);
System.out.println(list2);
// fill 填充
Collections.fill(list2,"yyy");
System.out.println(list2);
}
}
过期接口:Enumeration
public class EnumerationTest {
public static void main(String[] args) {
Vector v = new Vector();
v.add("疯狂java讲义");
v.add("轻量级java EE企业级应用实战");
Hashtable score = new Hashtable();
score.put("语文", 78);
score.put("数学", 88);
Enumeration em = v.elements();
while (em.hasMoreElements()){
System.out.println(em.nextElement());
}
Enumeration keyEm = score.keys();
while (keyEm.hasMoreElements()){
Object key = keyEm.nextElement();
System.out.println(key+"-->"+score.get(key));
}
}
}