Java容器---Map基础

时间:2023-01-07 17:18:58

1.Map API

(1)Map 集合类用于存储元素对(称作“键”和“值”),其中每个键映射到一个值。

java.util Interface Map<K,V>                                                                                                                                                         

参数类型:K--Map的Key(键)

                 V--Map的与Key对应的Value(值)

实现的子类:AbstractMapAttributes  , EnumMapHashMapHashtableLinkedHashMap

                   PropertiesProviderTreeMap  , WeakHashMap


(2)Map.Entry,是Map的嵌套类,它用来描述Map中的键/值对。

static interface  Map.Entry<K,V> :Map条目(键值对)。


(3)覆盖Object 的两个方法,以正确比较 Map 对象的等价性

  • boolean equals(Object o): 将指定的对象与此映射进行比较以获得相等性。
  • int hashCode(): 返回此Map的哈希码值。

(4)常用方法

void clear()                                          从该地图中删除所有的映射(可选操作)。                                                                               

boolean containsValue(Object value) 如果此地图将一个或多个键映射到指定的值,则返回 true。

Set<Map.Entry<K,V>> entrySet()       返回此地图中包含的映射的Set视图。

V get(Object key)                                 返回到指定键所映射的值,或 null如果此映射包含该键的映射。

boolean isEmpty()                                如果此地图不包含键值映射,则返回 true 。

Set<K> keySet()                                   返回此地图中包含的键的Set视图。

V put(K key, V value)                            将指定的值与该映射中的指定键相关联(可选操作)。                                                             

V remove(Object key)                           如果存在(从可选的操作),从该地图中删除一个键的映射。

default V replace(K key, V value)          只有当目标映射到某个值时,才能替换指定键的条目。

int size()                                                返回此地图中键值映射的数量。

Collection<V> values()                         返回此地图中包含的值的Collection视图。

default void replaceAll(BiFunction<? super K,? super V,? extends V> function)

将每个条目的值替换为对该条目调用给定函数的结果,直到所有条目都被处理或该函数抛出异常。

2.HashMap

public class HashMap<K,V>

               extends AbstractMap<K,V> 

               implements Map<K,V>, Cloneable, Serializable

直接子类:LinkedHashMapPrinterStateReasons

HashMap基于哈希表(“拉链法”实现哈希表,可参见数据结构-哈希表)实现的Map接口,。 此实现提供了所有可选的Map操作,并允许null的值和null键。

HashMap类大致相当于Hashtable ,除了它是不同步的,如果多个线程同时访问哈希映射,并且至少有一个线程在结构上修改了映射,那么它必须在外部进行同步。。

这个类不能保证Map的顺序; 特别是,它不能保证订单在一段时间内保持不变。

构造方法        

HashMap() :构造一个空的 HashMap ,默认初始容量(16)和默认负载系数(0.75)。(见下面注意)                                            

HashMap(int initialCapacity) :构造一个空的 HashMap具有指定的初始容量和默认负载因子(0.75)。

HashMap(int initialCapacity, float loadFactor) :构造一个空的 HashMap具有指定的初始容量和负载因子。

HashMap(Map<? extends K,? extends V> m): 构造一个新的 HashMap与指定的相同的映射 Map 。

注意:

HashMap的一个实例有两个影响其性能的参数: 初始容量负载因子 。 容量是哈希表中的桶数,初始容量只是创建哈希表 数据结构-哈希表时的容量。 负载因子是在容量自动增加之前允许哈希表得到满足的度量。 当在散列表中的条目的数量超过了负载因数和容量的乘积,哈希表被重新散列 (即,内部数据结构被重建),使得哈希表具有桶的大约两倍。

作为一般规则,默认负载因子(.75)提供了时间和空间成本之间的良好折中。 更高的值会降低空间开销,但会增加查找成本(反映在     HashMap类的大部分操作中,包括get和put )。 在设置其初始容量时,应考虑Map中预期的条目数及其负载因子,以便最小化重新组播操作的数量。 如果初始容量大于最大条目数除以负载因子,则不会发生重新排列操作。

常用方法和Map相同


3.Hashtable

public class Hashtable<K,V>

              extends Dictionary<K,V> 

 implements Map <K,V>, Cloneable ,Serializable

已知直接子类: PropertiesUIDefaults

该类实现了一个哈希表(“拉链法”实现哈希表),它将键映射到值。 任何非null对象都可以用作键值或值。

为了从散列表成功存储和检索对象,用作键的对象必须实现hashCode方法和equals方法。

构造方法        

Hashtable() :构造一个新的,空的散列表,默认初始容量(11)和负载因子(0.75)。

Hashtable(int initialCapacity) :构造一个新的,空的哈希表,具有指定的初始容量和默认负载因子(0.75)。

Hashtable(int initialCapacity, float loadFactor): 构造一个新的,空的哈希表,具有指定的初始容量和指定的负载因子。                  

Hashtable(Map<? extends K,? extends V> t) :构造一个与给定地图相同的映射的新哈希表。


HashtableHashMap比较

相同点:

  • 都实现了Map、Cloneable、Serializable接口
  • 底层都是基于“拉链法”实现哈希表

不同的:

  • 线程安全不同:HashMap单线程安全,HashTable多线程安全
  • NULL的处理不同:HashMap的Key和Value可以为Null,HashTable的Key和ValueNull
  • 遍历:HashMap支持IteratorHashTable支持IteratorEnumeration
  • 类型不同:HashMap基于AbstractMap,HashTable基于Dictionary

4.TreeMap

public class TreeMap<K,V>

                 extends AbstractMap <K,V>

                 implements NavigableMap<K,V>, Cloneable Serializable

TreeMap基于红黑树实现
NavigableMap
红黑树是一种自平衡的二叉树,即左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。红黑树虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。(点击查看关于数据结构---红黑树的文章
Java容器---Map基础

 

构造方法        

TreeMap():使用其键的自然排序构造一个新的空树状图。

TreeMap(Comparator<? super K> comparator):构造一个新的,空的树图,按照给定的比较器排序。

TreeMap(Map<? extends K,? extends V> m) :造一个新的树状图,其中包含与给定地图相同的映射,根据其键的                 

自然顺序进行排序 。

TreeMap(SortedMap<K,? extends V> m) :造一个包含相同映射并使用与指定排序映射相同顺序的新树映射。


5.Properties

public class Properties

extends Hashtable <Object ,Object>

直接子类:ProviderProperties类表示一组持久的属性。看参见Java I/O---Properties类(持久化键值对)因为Properties从继承Hashtable时, put种putAll方法可应用于Properties对象。 强烈不鼓励使用它们,因为它们允许调用者插入其键或值不是Strings , 应该使用setProperty方法这个类是线程安全的:多个线程可以共享一个Properties对象,而不需要外部同步。


构造方法

Properties() :创建一个没有默认值的空属性列表。

Properties(Properties defaults):创建具有指定默认值的空属性列表。                                                                                                                         

常用方法

String getProperty(String key) :使用此属性列表中指定的键搜索属性。

String getProperty(String key, String defaultValue) :使用此属性列表中指定的键搜索属性。

void list(PrintStream out /PrintWriter out) : 将此属性列表打印到指定的输出流

void load(InputStream inStream/Reader reader) : 从输入字节流读取属性列表(键和元素对)。

void loadFromXML(InputStream in) :将指定输入流中的XML文档表示的所有属性加载到此属性表中。

Enumeration<?> propertyNames() :返回此属性列表中所有键的枚举,包括默认属性列表中的不同键,如果尚未从主属性列表中找到相同名称的键。

Object setProperty(String key, String value) :取代 Hashtable方法 put 。

void storeToXML(OutputStream os, String comment, String encoding) :使用指定的编码发出表示此表中包含的所有属性的XML文档。

Set<String> stringPropertyNames() 返回此属性列表中的一组键,其中键及其对应的值为字符串,包括默认属性列表中的不同键,如果尚未从主属性列表中找到相同名称的键。

6.Map的方法演示

  1 public class MapDemo {
  2 
  3 	/**
 4 	 * @param args
 5 	 */
  6 	public static void main(String[] args) {
  7 
  8 		Map<Integer,String> map = new HashMap<Integer,String>();
  9 		methodDemo(map);
 10 		/*
 11 		 * 需求:Map集合中存储学号,姓名。
 12 		 */
 13 	}
 14 	public static void methodDemo(Map<Integer,String> map){
 15 
 16 		//1,存储键值对。如果键相同,会出现值覆盖。
 17 		System.out.println(map.put(3, "xiaoqiang"));
 18 		System.out.println(map.put(3, "erhu"));
 19 		map.put(7, "wangcai");
 20 		map.put(2, "daniu");
 21 
 22 //		System.out.println(map.remove(7));
 23 
 24 		System.out.println(map.get(7));
 25 
 26 		System.out.println(map);
 27 	}
 28 }
  1 public class MapTest {
  2 
  3 	/**
 4 	 * @param args
 5 	 */
  6 	public static void main(String[] args) {
  7 
  8 		/*
 9 		 * 什么时候使用map集合呢?
 10 		 * 当需求中出现映射关系时,应该最先想到map集合。
 11 		 *
 12 		 */
 13 
 14 		String cnWeek = getCnWeek(3);
 15 		System.out.println(cnWeek);
 16 		String enWeek = getEnWeek("星期八");
 17 		System.out.println(enWeek);
 18 
 19 	}
 20 	//根据中文星期,获取对应的英文星期。
 21 	//中文与英文相对应,可以建立表,没有有序的编号,只能通过map集合。
 22 	public static String getEnWeek(String cnWeek){
 23 
 24 		//创建一个表。
 25 		Map<String,String> map = new HashMap<String,String>();
 26 		map.put("星期一","Monday");
 27 		map.put("星期二","Tuesday");
 28 		map.put("星期三","Wednesday");
 29 		map.put("星期四","Thursday");
 30 		map.put("星期五","Friday");
 31 		map.put("星期六","Saturday");
 32 		map.put("星期日","Sunday");
 33 
 34 
 35 		return map.get(cnWeek);
 36 
 37 	}
 38 
 39 	/**
 40 	 * 根据用户的指定的数据获取对应的星期。
 41 	 */
 42 	public static String getCnWeek(int num){
 43 
 44 		if(num<=0 || num>7){
 45 			throw new NoWeekException(num+",没有对应的星期");
 46 		}
 47 
 48 		String[] cnWeeks = {"","星期一","星期二","星期三","星期四","星期五","星期六","星期日"};
 49 
 50 		return cnWeeks[num];
 51 
 52 	}
 53 
 54 }
 55 
  1 public class Employee implements Comparable<Employee> {
  2 
  3 	private String name;
  4 	private int age;
  5 
  6 
  7 	public Employee() {
  8 		super();
  9 
 10 	}
 11 
 12 	public Employee(String name, int age) {
 13 		super();
 14 		this.name = name;
 15 		this.age = age;
 16 	}
 17 
 18 	public String getName() {
 19 		return name;
 20 	}
 21 	public void setName(String name) {
 22 		this.name = name;
 23 	}
 24 	public int getAge() {
 25 		return age;
 26 	}
 27 	public void setAge(int age) {
 28 		this.age = age;
 29 	}
 30 
 31 	@Override
 32 	public String toString() {
 33 		return "Emplooye [name=" + name + ", age=" + age + "]";
 34 	}
 35 
 36 	@Override
 37 	public int hashCode() {
 38 		final int prime = 31;
 39 		int result = 1;
 40 		result = prime * result + age;
 41 		result = prime * result + ((name == null) ? 0 : name.hashCode());
 42 		return result;
 43 	}
 44 
 45 	@Override
 46 	public boolean equals(Object obj) {
 47 		if (this == obj)
 48 			return true;
 49 		if (obj == null)
 50 			return false;
 51 		if (getClass() != obj.getClass())
 52 			return false;
 53 		Employee other = (Employee) obj;
 54 		if (age != other.age)
 55 			return false;
 56 		if (name == null) {
 57 			if (other.name != null)
 58 				return false;
 59 		} else if (!name.equals(other.name))
 60 			return false;
 61 		return true;
 62 	}
 63 
 64 	@Override
 65 	public int compareTo(Employee o) {
 66 
 67 		int temp = this.age - o.age;
 68 		return temp==0? this.name.compareTo(o.name):temp;
 69 	}
 70 
 71 }
 72 
 73 ///////////////////////////////////////////////////////////////////////////////////////////
 74 public class HashMapTest {
 75 
 76 	/**
 77 	 * @param args
 78 	 */
 79 	public static void main(String[] args) {
 80 		/*
 81 		 * 1, 将员工和归属存储到HashMap集合中并取出。 同姓名同年龄视为同一个学生。
 82 		 */
 83 
 84 
 85 		Map<Employee,String>  map = new HashMap<Employee,String>();//如果改成LinkedHashMap可以实现有序。
 86 
 87 		map.put(new Employee("xiaozhang",24),"北京");
 88 		map.put(new Employee("laoli",34),"上海");
 89 		map.put(new Employee("mingming",26),"南京");
 90 		map.put(new Employee("xili",30),"广州");
 91 		map.put(new Employee("laoli",34),"铁岭");
 92 
 93 		Set<Employee> keySet = map.keySet();
 94 		for(Employee employee : keySet){
 95 
 96 			String value = map.get(employee);
 97 
 98 			System.out.println(employee.getName()+":"+employee.getAge()+"...."+value);
 99 
100 
101 		}
102 
103 //		for(Employee employee : map.keySet()){
104 //			
105 //		}
106 
107 
108 	}
109 
110 
111 
112 }
113 
  1 public class TreeMapTest {
  2 
  3 	/**
 4 	 * @param args
 5 	 */
  6 	public static void main(String[] args) {
  7 
  8 		/*
 9 		 * 2, 按照学生的年龄进行升序排序并取出。 按照学生的姓名进行升序排序并取出。
 10 		 */
 11 
 12 		// 自定义比较器。
 13 		Comparator<Employee> comparator = new Comparator<Employee>() {
 14 
 15 			@Override
 16 			public int compare(Employee o1, Employee o2) {
 17 
 18 				int temp = o1.getName().compareTo(o2.getName());
 19 				return temp == 0 ? o1.getAge() - o2.getAge() : temp;
 20 			}
 21 		};
 22 
 23 		Map<Employee, String> map = new TreeMap<Employee, String>(comparator);
 24 
 25 		map.put(new Employee("xiaozhang", 24), "北京");
 26 		map.put(new Employee("laoli", 34), "上海");
 27 		map.put(new Employee("mingming", 26), "南京");
 28 		map.put(new Employee("xili", 30), "广州");
 29 		map.put(new Employee("laoli", 34), "铁岭");
 30 
 31 		// entrySet
 32 		Set<Map.Entry<Employee, String>> entrySet = map.entrySet();
 33 		for (Map.Entry<Employee, String> me : entrySet) {
 34 
 35 			Employee key = me.getKey();
 36 			String value = me.getValue();
 37 			System.out.println(key.getName() + "::" + key.getAge() + "....."
 38 					+ value);
 39 		}
 40 
 41 	}
 42 
 43 }
 44 
2018-01-07
内容主要来自API