[学习笔记]Java集合框架之Map集合

时间:2023-02-26 08:29:05

Map集合

1. 概述

Map<K, V>集合是一个接口,和Collection集合不同的是,它是双列集合,也就是说它所存储的是键值对。

2. 特点

  • Map集合存储的是键值对,其中键要求唯一。
  • Map集合的键对应一个值,值不要求唯一,但是一个键不能对应对个值。
  • Map集合没有Iterator迭代器,如果需要迭代需要转化为单列集合间接迭代。

3. 继承关系

Map
  |--Hashtable:哈希表结构,不保证存取顺序,不允许null键或者null值,线程安全,效率较低,已被HashMap替代
         |--Propertise:键值对均是String类型的Map集合,包括直接对流操作的方法,专为配置文件而生。
  |--HashMap:哈希表结构,不保证存取顺序,允许null键和null值,非线程安全,效率较高。
         |--LinkedHashMap:带双向链表的哈希表结构,保持存取顺序,允许null键和null值,非线程安全,效率较高。
  |--TreeMap:平衡排序二叉树(红黑树)结构,按自然排序或比较器存入元素以保证元素有序,非线程安全。
              元素唯一性取决于ComparaTo方法或Comparator比较器。

4. 常用方法

Map集合的方法一部分和Set集合类似。
  • 添加键值对
    V  put(K key, V value)
  • 根据键获取值
    V  get(Object key)
  • 判断是否包含键或者值
    boolean  containsKey(Object key)
    boolean  containsValue(Object value)
  • 删除对应键值对
    V  remove(Object key)
    default boolean  remove(Object key, Object value)
  • 替换新值
    default V  replace(K key, V value) // 返回老值
    default boolean  replace(K key, V oldValue, V newValue)
  • 获取entrySet(包含所有键值对的Map对象的Set集合)
    Set<Map.Entry<K,V>>  entrySet()
  • 获取包含所有键的Set集合
    Set<K>  keySet()
  • 获取包含所有值的Collection集合
    Collection<V>  values()

示例

package collection.map; import java.util.HashMap;import java.util.Map; public class MapFunc {  public static void main(String[] args) { /* * Map集合的使用 * 1. Map集合中的键是唯一的。 * 2. Map集合没有迭代器,如果需要迭代需要转成单列集合。 */ Map<String, String> map = new HashMap<String, String>();  // 添加元素 map.put("星期一", "Monday"); // 返回值为null map.put("星期二", "Tuesday"); map.put("星期三", null); // HashMap可以存储null值 map.put("星期二", "Tues"); // 如果键相同,则值覆盖,并返回原有旧值。  // 给定键获取值 String value = map.get( "星期二"); // " Tues"  // 判断是否包含键和值 boolean b1 = map.containsKey( "星期三"); // true boolean b2 = map.containsValue( "Tuesday"); // false  // 给定键删除。 String str1 = map.remove( "星期三"); // null  // 替换(修改) String str2 = map.replace( "星期一", "Mon" ); // "Monday" }}

注意

Map.Entry是Map接口中的内部接口,因为依托Map集合存在而存在,并且由于该接口能够获取Map集合中的所有键值对,所以定义在内部。

5. 迭代

方法一:使用entrySet集合方法二:使用keySet集合

示例

package collection.map; import java.util.Collection;import java.util.HashMap;import java.util.Map;import java.util.Map.Entry;import java.util.Set; public class Map_Demo {  public static void main(String[] args) {  Map<String, String> map = new HashMap<String, String>();  // 添加元素 map.put("Mon", "星期一"); map.put("Tues", "星期二"); map.put("Wed", "星期三"); map.put("Thur", "星期四"); map.put("Fir", "星期五"); map.put("Sat", "星期六"); map.put("Sun", "星期日");  // 通过keySet方法获取所有键值 Set<String> keySet = map.keySet(); for (String key : keySet) { String value = map.get( key); }  // 通过entrySet方法获取所有键值 Set<Map.Entry<String, String>> entrySet = map.entrySet(); for (Entry<String, String> entry : entrySet) { String entryKey = entry.getKey(); String entryValue = entry.getValue(); }  // 获取所有值 Collection<String> allvalues = map .values(); }}

HashMap集合与TreeMap集合

特点

  • 其方法和思想均和HashSet以及TreeSet高度类似,可以参照。
  • HashMap的键保持唯一性,取决于hashCode以及equals方法。
    TreeMap的键保持唯一性,取决于比较方法和比较器。

键唯一性示例

ComparatorOnlyByAge.java
package comparator; import java.util.Comparator; import bean.Person; public class ComparatorOnlyByAge implements Comparator<Person> {  @Override public int compare(Person o1, Person o2) { return o1 .getAge() - o2 .getAge(); }}

MapSubclass.java
package collection.map; import java.util.HashMap;import java.util.Map;import java.util.TreeMap; import bean.Person; import comparator.ComparatorOnlyByAge; public class MapSubclass {  public static void main(String[] args) {  // 注意:HashMap判断键是否相同的依据是hashCode和equals方法。 Map<Person, String> mapHash = new HashMap<Person, String>(); mapHash.put(new Person( "jacob", 25), "huainan" ); mapHash.put(new Person( "hanlin", 26), "beijing" ); mapHash.put(new Person( "meteor", 25), "shanghai" ); for (Person key : mapHash.keySet()) { System.out.println( "(" + key + "," + mapHash.get(key ) + ")" ); } System.out.println( "-------------------");  // 注意:TreeMap判断键是否相同的依据是比较方法或比较器。 Map<Person, String> mapTree = new TreeMap<Person, String>(new ComparatorOnlyByAge()); mapTree.put(new Person( "jacob", 25), "huainan" ); mapTree.put(new Person( "hanlin", 26), "beijing" ); mapTree.put(new Person( "meteor", 25), "shanghai" ); mapTree.put(new Person( "yuhang", 25), "xi'an" ); mapTree.put(new Person( "huangdeng", 26), "guangzhou"); for (Person key : mapTree.keySet()) { System.out.println( "(" + key + "," + mapTree.get(key ) + ")" ); } }}

运行结果

(Person [name=hanlin, age=26],beijing)(Person [name=meteor, age=25],shanghai)(Person [name=jacob, age=25],huainan)-------------------(Person [name=jacob, age=25],xi'an)(Person [name=hanlin, age=26],guangzhou)

案例

获取字符串中每个字母出现的次数
package collection; import java.util.Map;import java.util.TreeMap; public class Map_Test {  public static void main(String[] args) { /* * 获取字符串中每一个字母出现的次数。 * 要求返回结果个格式是 a(1)b(2)d(4)......,并且不应包含符号; * 思路: * 1. 获取到字符串中的每一个字母。 * 2. 用字母取查表,如果查到了该字母对应的次数,就将这个次数+1后重新存回表中。 * 如果没有查到呢?将该字母和1存到表中。 * 3. 每一字母都查完表后,表中记录的就是所有字母出现的次数。 * * 字母和次数之间存在对应关系,而且字母是唯一性的,所以可以使用map集合做表进行查询。 * 通过结果发现 字母有顺序的,所以可以通过map集合中的 treemap作为表。 */ String str = "an+object+that+maps+keys+to+values.+a+map+cannot+contain+duplicate+keys;" + "+each+key+can+map+to+at+most+one+value.this+interface+takes+the+place+of=the=" + "dictionary=class,=which=was=a=totally=abstract=class=rather than=an=interface." + "the map interface provides three collection views, which/allow/a/map's/contents" + "/to/be/viewed/as/a/set/of/keys,/collection/of/values,/or/set/of/key-value/mappings." ; Map<Character, Integer> map = getCharCount(str); String result = printCharCount(map ); System.out.println( result);  }  public static String printCharCount(Map<Character, Integer> map) { StringBuilder str = new StringBuilder(); for (Character key : map.keySet()) { str.append(key ).append("(" ).append(map .get(key )).append(")" ); } return str.toString(); }  public static Map<Character, Integer> getCharCount(String str) { // 将字符串转成数组,方便对每一个字符做判断处理 char[] chs = str.toCharArray(); Map<Character, Integer> map = new TreeMap<Character, Integer>(); for (int i = 0; i < chs.length; i++) { // 如果不是字母,则继续下一次循环 if (!Character. isAlphabetic(chs[i])) continue; Character key = chs[ i]; int value = 0; // 如果该字母已被记录,则获取该字母已出现的次数;否则次数就初始化为0 if (map.containsKey( key)) { value = map.get( key); } // 将该次数自增并记录 map.put(key, ++value); } return map; }}

运行结果

a(39)b(3)c(21)d(4)e(37)f(7)g(1)h(13)i(16)j(1)k(6)l(16)m(7)n(18)o(22)p(10)r(10)s(23)t(33)u(5)v(7)w(6)y(7)

Properties集合

特点

  • Properties集合表示了一个持久的属性集。
  • Properties集合键值对均是String类型。
  • Properties集合可以直接从一个流中读取数据,也可以直接保存到一个流中。
  • 强烈建议Properties集合只存储String类型的数据,尽管可以利用其父类方法存储其他类型数据。

常用方法

  1. 添加属性值
    Object  setProperty(String key, String value)
  2. 获取属性值
    String  getProperty(String key)
    String  getProperty(String key, String defaultValue)
  3. 获取所有属性
    Set<String>  stringPropertyNames()
  4. 打印所有属性和属性值
    void  list(PrintStream out)
    void  list(PrintWriter out)
  5. 将属性集存储到流中(可以使用XML方式)
    void  store(OutputStream out, String comments)
    void  store(Writer writer, String comments)
    void  storeToXML(OutputStream os, String comment)
    void  storeToXML(OutputStream os, String comment, String encoding)
  6. 从流中读取属性集(可以使用XML方式)
    void  load(InputStream inStream)
    void  load(Reader reader)
    void  loadFromXML(InputStream in)

示例

package collection.map; import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.util.Properties;import java.util.Set; public class PropertiseDemo {  public static void main(String[] args) { Properties pro = new Properties(); // 1. 添加属性 pro.setProperty( "name" , "Windows 7" ); pro.setProperty( "date" , "2014.12.15" ); pro.setProperty( "time" , "17:20" ); pro.setProperty( "bit" , "x64" ); pro.setProperty( "lan" , "zh" );  // 2. 获取属性 String str1 = pro.getProperty( "name" ); // "Windows 7" String str2 = pro.getProperty( "OS" , "none" ); // "none"  // 3. 获取所有属性 Set<String> set = pro.stringPropertyNames(); // [name, date, lan, time, bit]  // 4. 存储属性集到流中 File file = new File( "temp\\Properties.xml" ); try { pro.storeToXML( new FileOutputStream( file), "PropertiesDemo" ); } catch (IOException e) { e.printStackTrace(); }  // 5. 从流中读取属性集 Properties proFromXml = new Properties(); try { proFromXml.loadFromXML( new FileInputStream( file)); } catch (IOException e) { e.printStackTrace(); } System.out.println( proFromXml); }}