集合框架复习总结(四)

之前复习完了List和Set的内容,剩下Map的内容也一起复习了。

Map接口和Collection接口的不同
Map是双列的,Collection是单列的
Map的键唯一,Collection的子体系Set是唯一的
Map集合的数据结构值针对键有效,跟值无关;Collection集合的数据结构是针对元素有效


Map是一种把键对象和值对象进行关联的容器
        一个值对象又可以是一个Map,依次类推,这样就可形成一个多级映射。对于键对象来说,像Set一样, 一个Map容器中的键对象不允许重复,这是为了保持查找结果的一致性;如果有两个键对象一样,那你想得到那个键对象所对应的值对象时就有问题了,可能你得到的并不是你想的那个值对象,结果会造成混乱,所以 键的唯一性很重要,也是符合集合的性质的。
        当然在使用过程中,某个键所对应的值对象可能会发生变化,这时会按照最后一次修改的值对象与键对应。对于值对象则没有唯一性的要求。你可以将任意多个键都映射到一个值对象上,这不会发生任何问题(不过对你的使用却可能会造成不便,你不知道你得到的到底是那一个键所对应的值对象)。

Map有两种比较常用的实现:HashMap和TreeMap。HashMap也用到了哈希码的算法,以便快速查找一个键,TreeMap则是对键按序存放,因此它便有一些扩展的方法,比如firstKey(),lastKey()等,你还可以从TreeMap中指定一个范围以取得其子Map。键和值的关联很简单,用put(Object key,Object value)方法即可将一个键与一个值对象相关联。用get(Object key)可得到与此key对象所对应的值对象。

     一般来说,我们常用的Map子类有HashMap,TreeMap和LinkedHashMap,其与Set的存储结构很相似,LinkedHashMap是底层链表结构,HashMap是运用了哈希算法的,TreeMap是树结构存储,进行了排序。

一、Map基本功能描述
1、添加功能
 V put(K key,V value):添加元素。
 如果键是第一次存储,就直接存储元素,返回null
 如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值
2、删除功能
 void clear():移除所有的键值对元素
 V remove(Object key):根据键删除键值对元素,并把值返回
3、判断功能
 boolean containsKey(Object key):判断集合是否包含指定的键
 boolean containsValue(Object value):判断集合是否包含指定的值
 boolean isEmpty():判断集合是否为空
4、获取功能
 Set<Map.Entry<K,V>> entrySet():
 V get(Object key):根据键获取值
 Set<K> keySet():获取集合中所有键的集合
 Collection<V> values():获取集合中所有值的集合
5、长度功能
 int size():返回集合中的键值对的个数


下面举一些例子介绍:

例子1:

public static void main(String[] args) {
	Map<String,Integer> map = new HashMap<String, Integer>();
	
	//添加元素
	map.put("Jack",22);
	map.put("Marry",23);
	System.out.println(map);
	
	//删除,清空功能
	map.remove("Jack");
	System.out.println(map);
	
	map.clear();
	System.out.println(map);
}

得到的结果为:

{Jack=22, Marry=23}
{Marry=23}
{}


例子2:

map.put("Jack",22);
map.put("Marry",23);
System.out.println(map);
		
//判断集合是否包含键
System.out.println(map.containsKey("Jack"));
System.out.println(map.containsKey("Tom"));		
//判断集合是否包含指定的值
System.out.println(map.containsValue(22));
System.out.println(map.containsValue(25));

得出的结果为:
{Jack=22, Marry=23}
true
false
true
false


例子3:

map.put("Jack",22);
map.put("Marry",23);
System.out.println(map);

//判断集合是否为空
System.out.println(map.isEmpty());
map.clear();
System.out.println(map.isEmpty());

得到的结果为:
{Jack=22, Marry=23}
false
true


例子4:

//添加元素
map.put("Jack",22);
map.put("Marry",23);

//得到键获取该键的值
System.out.println(map.get("Jack"));
System.out.println(map.get("Tom"));

//获取集合的长度
System.out.println(map.size());


得到的结果为:
22
null
2


下面重点讲一下遍历的方法:
通常可以使用keyset()方法得到每一个key,然后get(key),得到每一个key对应的值这样来遍历:

map.put("Jack",22);
map.put("Marry",23);
map.put("Tom", 23);


System.out.println(map.keySet());
for (String key : map.keySet()) {
	System.out.println("我叫" + key + ",今年" + map.get(key) +"岁");
}

得出的结果为:
我叫Jack,今年22岁
我叫Tom,今年23岁
我叫Marry,今年23岁


那么,还有一种方法,是把键和值的键值对封装成一个对象,然后来遍历的:
其方法是使用Map.Entry接口,而Entry接口是Map中的一个子接口,可以单独使用,而还需要获取entrySet()来得到所有键值对,举个例子来解释一下这个方法应该怎么使用:
map.put("Jack",22);
map.put("Marry",23);
map.put("Tom", 23);

System.out.println(map.entrySet());
for (Entry<String, Integer> entry : map.entrySet()) {
	System.out.println(entry + "  我叫" + entry.getKey() + ",年龄为" + entry.getValue());
}

得到的结果为:
[Jack=22, Tom=23, Marry=23]
Jack=22  我叫Jack,年龄为22
Tom=23  我叫Tom,年龄为23
Marry=23  我叫Marry,年龄为23


其中包含的方法有entrySet()是获取集合中的键值对,getKey()和getvalue()分别是获取键和值。
当然,我们也可以用迭代器进行遍历。


二、Map接口的子类HashMap,TreeMap和LinkedHashMap的简单介绍
1、HashMap
此类不保证映射的顺序,特别是它不保证该顺序恒久不变。基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了不同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。另外,HashMap是非线程安全的,也就是说在多线程的环境下,可能会存在问题,而Hashtable是线程安全的。


重点:HashMap和Hashtable的区别
* Hashtable是JDK1.0版本出现的,是线程安全的,效率低,HashMap是JDK1.2版本出现的,是线程不安全的,效率高
* Hashtable不可以存储null键和null值,HashMap可以存储null键和null值


2、LinkedHashMap
LinkedHashMap可以保证怎么存就怎么取,其原理和Set有点相似。Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。


3、TreeMap
也是相当于Set的改进,变为键值对形式存储。TreeMap类不仅实现了Map接口,还实现了java.util.SortMap接口,因此集合中的映射关系具有一定的顺序.但是在添加,删除,和定位映射关系上,TreeMap类比HashMap类的性能差一些.TreeMap类实现的Map集合中的映射关系是根据键值对象按一定的顺序排列的.因此不允许键对象是null.


各举一个例子解释一下吧
有一个Person类:

public class Person {
	public String name;
	public int age;
	
	public Person() {
		super();
	}
	 
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}	
	
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}

	public String getName() {
		return name;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	
}


1、HashMap

public static void main(String[] args) {
	HashMap<Person, String> hm = new HashMap<Person, String>();
		
	hm.put(new Person("Jack",23), "is a doctor");
	hm.put(new Person("Marry",24), "is a teacher");
	hm.put(new Person("Tom",22), "is a student");
	hm.put(new Person("Max",26), "is a worker");
		
	for (Entry<Person, String> en : hm.entrySet()) {
		System.out.println(en.getKey() + "  " +en.getValue());
	}	
}

得到的结果为:
Person [name=Max, age=26]  is a worker
Person [name=Jack, age=23]  is a doctor
Person [name=Marry, age=24]  is a teacher
Person [name=Tom, age=22]  is a student
存储是没有顺序的。


2、LinkedHashMap

public static void main(String[] args) {
	LinkedHashMap<Person, String> lhm = new LinkedHashMap<Person, String>();

	lhm.put(new Person("Jack",23), "is a doctor");
	lhm.put(new Person("Marry",24), "is a teacher");
	lhm.put(new Person("Tom",22), "is a student");
	lhm.put(new Person("Max",26), "is a worker");

	for (Entry<Person, String> en : lhm.entrySet()) {
		System.out.println(en.getKey() + "  " +en.getValue());
	}
}

得到的结果为:
Person [name=Jack, age=23]  is a doctor
Person [name=Marry, age=24]  is a teacher
Person [name=Tom, age=22]  is a student
Person [name=Max, age=26]  is a worker
怎么存就怎么取。


3、TreeMap

public static void main(String[] args) {
	TreeMap<Person, String> tm = new TreeMap<Person, String>(new Comparator<Person>() {
		@Override
		public int compare(Person p1, Person p2) {
			int num = p1.getName().compareTo(p2.getName());
			return num==0 ? p1.getAge()-p2.getAge() : num;
		}
		
	});
		tm.put(new Person("Jack",23), "is a doctor");
		tm.put(new Person("Marry",24), "is a teacher");
		tm.put(new Person("Tom",22), "is a student");
		tm.put(new Person("Max",26), "is a worker");

		for (Entry<Person, String> en : tm.entrySet()) {
			System.out.println(en.getKey() + "  " +en.getValue());
		}


得到的结果为:
Person [name=Jack, age=23]  is a doctor
Person [name=Marry, age=24]  is a teacher
Person [name=Max, age=26]  is a worker
Person [name=Tom, age=22]  is a student
这里是根据比较器,先比较名字,按字典排序,再比较年龄。若再添加一个tm.put(new Person("Jack",22), "is a doctor"),会输出结果:
Person [name=Jack, age=22]  is a doctor
Person [name=Jack, age=23]  is a doctor
Person [name=Marry, age=24]  is a teacher
Person [name=Max, age=26]  is a worker
Person [name=Tom, age=22]  is a student


好了,到这里集合框架的复习基本回顾完了。

猜你喜欢

转载自blog.csdn.net/m0_38012174/article/details/77749471