天天看点

【Map集合总结】HashMap---Hashtable---TreeMap三者的区别和相关的应用!!

一:Map集合:

其实就是存储“键到值”的映射的集合,简单的理解就是想存储一对一对的夫妻似得!

理解:【键就是丈夫(key),值就是老婆(value),是一一对应的关系!】

【但是注意】:一个映射不能包含重复的键(不能把同一个丈夫存储两次),每一个键最多只能映射到一个值(一个丈夫只能对应一个老婆!)

Map当中存储的全是这样的“键值对”(一对一对的!)而且必须保证其唯一性!

Collection是单列模式集合,而Map是双列模式集合,关于一些基本都是添加,修改,删除,查看的方法就不再一一介绍了,在API帮助文档中学习一下就行!

下面只是说一个比较特殊的添加方法:请看实例分析:

/*
【重点】
1.put("","")方法:的返回值是和该健值相同的之前一个健值的具体内容,类型为健值内容的类型
*/
import java.util.*;
class  HashMapDemo1
{
	public static void main(String[] args) 
	{
		Map<String,String> map=new HashMap<String,String>();
	
		/*
		map.put("01","afa");
		map.put("01","afa");
		map.put("01","afa");
		map.put("01","afa");
		map.put("01","afaf");

		sop(map); 
		//打印结果是{01=afa},只有一个元素,说明被后面相同键所对应的值替换掉了
		sop("该方法的返回值:"+map.put("01","wangke"));
		//该方法的返回值:afaf,并不是wangkeze,说明此时返回的值是前一个相同键位对应的值。*/
		
		/*
		map.put("01","afa");
		map.put("02","afa");
		map.put("03","afa");
		map.put("03","wang");
		map.put("04","afa");
		map.put("05","afa");
		sop(map);//{04=afa, 05=afa, 01=afa, 02=afa, 03=afa}//说明存入的键值是无序性的*/
		
		
		/*
		map.put("01","afa");
		map.put("02","afa");
		map.put("03","afa");
		map.put("04","afa");
		map.put("05","afa");
		map.put("03","wang");
		sop(map); //{04=afa, 05=afa, 01=afa, 02=afa, 03=wang}//03键值被改变了*/

		map.put("01","afa");
		map.put("02","afa");
		map.put("03","afa");
		map.put("04","afa");
		map.put("05","afa");
		sop(map.put("06","afa")); //返回值是null
		Set<String> set=map.keySet();
		Iterator<String> i=set.iterator();
		while (i.hasNext())
		{
			String key=i.next();
			String value=map.get(key);
			sop("键值:"+key+"内容:"+value);
		}

		/*取出的结果为:
		键位:04内容:afa
		键位:05内容:afa
		键位:01内容:afa
		键位:02内容:afa
		键位:03内容:afa
		*/

	}
	public static void sop(Object obj) 
	{
		System.out.println(obj);
	}
}
           

二:该集合主要分为三个重点的实现类:

【Hashtable】:看意思嘛,就是hash表,对!它的底层数据结构就是hash表,它出现在JDK1,.0中,是同步的线程,非常安全!但是效率不是很高!

 【HashMap】:简单说就是【Hashtable】的升级版本:在JDK1.2之后就是 【HashMap】了,但是线程不同步,执行效率高,多线程中,自己必须要加锁才行!

【TreeMap】:底层数据结构是二叉树的原理!大家应该都比较熟悉了,在set集合中,其实现类TreeSet就是二叉树的数据结构,只不过这个是单列集合!

三:【重点】keySet方法   和   entrySet方法的应用:

还是用实例来分析说明吧!

/*
【重点1】
1.keySet()方法:取出的是所有的健值,会放在set集合中
再用set集合中的迭代方式取出健值用map的get()方法去依次取出对应的内容

【重点2】entrySet()方法:
1.该方法主要是把map集合中的”映射对应项“取出存在了set集合中
其对应项的关系类型是Map.Entry
2.用set集合中迭代的方式取出对应项,再用其Map.Entry类中自有的方法getKey()
和getValue()分别取出健值和对应的内容的值
*/

import java.util.*;
class  EntrySetDemo2
{
	public static void main(String[] args) 
	{
		Map<String,String> map=new HashMap<String,String>();
		map.put("001","wangming");
		map.put("002","wang");
		map.put("003","wangming");
		map.put("004","wangfsd");
		map.put("005","wangmif");
		map.put("006","wfsfang");

		/*
		这里用keySet方法进行
		*/
		//这里是把HashMap集合的中key元素转移到set集合中去
		Set<String> set=map.keySet(); 

		//通过迭代的方式,取出set集合中的元素(也就是原来HashMap中的键值)
		Iterator<String> it=set.iterator();
		while (it.hasNext())
		{
			String key=it.next(); //这就是迭代取出的键值

			//通过HashMap集合中的get方法又去把键值作为参数传递,得到HashMap中的value值
			String value=map.get(key); 
			
			sop(key+":"+value);
		}


		/*
		以下是用entry()的方法
		*/

		//这是用map的entrySet()方法取出对应项存在set集合中
		Set<Map.Entry<String,String>> mapEntry=map.entrySet();
		
		//用迭代的方式取出Map.Entry的类型;
		Iterator<Map.Entry<String,String>> i=mapEntry.iterator();
		
		//再用其Map.Entry类中的方法getKey()和getValue()去取得健值和内容
		while (i.hasNext())
		{	Map.Entry<String,String> entry=i.next();
			
			//取出健值和对应的内容值
			String key=entry.getKey();
			String value=entry.getValue();

			sop(key+":"+value);
		}

	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

/*【分析Map.Entry类型的来历】
1.Entry是Map接口中的一个接口;
2.该接口是对外开放的,而且是静态的,因为能直接被Map.的方式调用
3.该Entry接口中的方法有两个getKey()和getValue(),肯定是抽象的,需要实现类去实现;
4.由实现类HashMap去实现了Map接口和另外一个类去实现内置的Entry接口,并且实现了抽象的两个方法;
【总结】这里就是用到了内部类的思想,为什么要把Entry接口定义在Map接口内部,是因为必须先要有集合,
才能有对应项的存在
*/
/*interface Map
{
	public static interface Entry
	{
		public abstract Object getKey();
		public abstract Object getValue();
	}
}

class HashMap implements Map
{
	class Xxx implements Entry
	{
		public Object getKey(){}
		public Object getValue(){}
	}
}
*/
           

四、中级应用:关于对象加入Map集合的方法,一样的请看实例分析就能掌握了

/*
题目:每一个学生都有对应的归属地;
学生;Student 地址: address:String
学生:属性中姓名和年龄相同的视为同一个学生
必须保证学生的唯一性
编写这样一个程序去实现上述内容

【分析】
1.先定义一个学生类;
2.每个学生指的是:【姓名和年龄】整体属性和其它的不能一样,否则就是同一个学生
3.用Map对应的关系映射去做出”一个学生对应一个地址“
*/
import java.util.*;

//定义按照上面要求的一个学生类
class Student implements Comparable<Student>
{
	private String name;
	private int age;
	
	Student(String name,int age)
	{
		this.name=name;
		this.age=age;
	}
	
	//为了保证学生类中学生的唯一性,覆写了hashCode()的方法,确保哈希值唯一性
	//才能做equals方法的判断,这是SET集合中必须做的,确保不重复元素的存在
	public int hashCode()
	{
		return name.hashCode()+age*89;
	}
	
	//覆写了hashCode()的方法之后,就在覆写equals方法,主要都是为了确保元素唯一性
	public boolean equals(Object obj)
	{
		if (!(obj instanceof Student))
			throw new ClassCastException("类型不匹配");

		Student s=(Student)obj;

		//判断同名同年龄的为一个学生,所以返回值为false,最终就不会被加入到集合中!
		return this.name.equals(s.name) && this.age==age;
	}


	//实现Comparable接口,覆写compareTo方法,这其实就是为了让其自然排序
	public int compareTo(Student s)
	{
		//现根据年龄进行自然排序
		int num=new Integer(this.age).compareTo(new Integer(s.age));
		
		//当学生的年龄相同时,再进行名字的自然排序
		if (num==0)
		{
			return this.name.compareTo(s.name);
		}
		return num;
	}

	public String getName()
	{
		return name;
	}

	public int getAge()
	{
		return age;
	}
}

class StudentAddress3 
{
	public static void main(String[] args) 
	{
		//创建HashMap集合,把学生类和地址装入进去!
		HashMap<Student,String> hm=new HashMap<Student,String>();
		hm.put(new Student("wangming",20),"huilixian");
		hm.put(new Student("wing",22),"sichuan");
		hm.put(new Student("wig",22),"xichang");
		hm.put(new Student("wg",23),"panzhihua");
		hm.put(new Student("wg",23),"moujjn");
		hm.put(new Student("abc",20),"nanjin");

		//通过keySet方法完成取出展示
		Set<Student> keySet=hm.keySet();
		Iterator<Student> is=keySet.iterator();

		sop("----keySet方法----");
		while (is.hasNext())
		{
			Student stu=is.next();
			String address=hm.get(stu);
			sop("姓名:"+stu.getName()+"年龄:"+stu.getAge()+"地址"+address);
		}

		//通过entrySet方法完成取出展示
		Set<Map.Entry<Student,String>> entrySet=hm.entrySet();
		Iterator<Map.Entry<Student,String>> iter=entrySet.iterator();

		sop("----entrySet方法----");
		while (iter.hasNext())
		{
			Map.Entry<Student,String> map=iter.next();
			Student stu=map.getKey();
			String address=map.getValue();
			sop("姓名:"+stu.getName()+"年龄:"+stu.getAge()+"地址:"+address);
		}

	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
           

五、【比较器的定义】中级应用!

/*
【重点】比较器
同样之前一样的题目要求,
现在只是要按照学生的年龄排序,从年龄大到小的排序
*/

import java.util.*;
class Student implements Comparable<Student>
{
	private String name;
	private int age;
	
	Student(String name,int age)
	{
		this.name=name;
		this.age=age;
	}
	
	public void setName(String name)
	{
		this.name=name;
	}

	public String getName()
	{
		return name;
	}

	public void setAge(int age)
	{
		this.age=age;
	}

	public int getAge()
	{
		return age;
	}

	public int hashCode()
	{
		return name.hashCode()*age*89;
	}

	public boolean equals(Object obj)
	{
		if (!(obj instanceof Student))
		{
			throw new ClassCastException("类型不匹配!");
		}
		
		Student s=(Student)obj;
		return this.name.equals(s.name) && this.age==s.age;
	}

	public int compareTo(Student s)
	{
		int num=new Integer(this.age).compareTo(new Integer(s.age));
		if (num==0)
		{
			return this.name.compareTo(s.name);
		}
		return num;
	}
}
/*
TreeMapTest4这个类可以自己试着分析,跟之前的一个实例的道理,并不是很难!
*/
class  TreeMapTest4
{
	public static void main(String[] args) 
	{
		TreeMap<Student,String> hm=new TreeMap<Student,String>(new myCompimpl());
		hm.put(new Student("wangkeze",28),"huilixian");
		hm.put(new Student("wangze",20),"huilixian");
		hm.put(new Student("wa",49),"huilixian");
		hm.put(new Student("wa",49),"huilixian");
		hm.put(new Student("a",49),"huilixian");

		//通过keySet方法完成取出展示
		Set<Student> hs=hm.keySet();
		Iterator<Student> itor=hs.iterator();
		while (itor.hasNext())
		{
			Student s=itor.next();
			String address=hm.get(s);
			sop(s.getName()+","+s.getAge()+":"+address);
		}

		//通过entrySet方法完成取出展示
		Set<Map.Entry<Student,String>> me=hm.entrySet();
		Iterator<Map.Entry<Student,String>> itorm=me.iterator();
		while (itorm.hasNext())
		{
			Map.Entry<Student,String> map=itorm.next();
			Student stu=map.getKey();
			String addressM=map.getValue();
			sop(stu.getName()+","+stu.getAge()+":"+addressM);
		}
	}

	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

/*
【分析】当我们具体的排序要求在集合中不能够满足时,我们就可以自定义一个比较器去完成!
下面就是一个比较器,我们来具体分析一下
*/

//自定义myCompimpl比较器名称实现Comparator接口
class myCompimpl implements Comparator<Student>
{
	//要比较的对象都是传入两个学生类实体
	public int compare(Student s1,Student s2)
	{
		//通过这学生两个实体提取各自的年龄进行compareTo方法的比较,再排序就行
		int num=new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
		
		//如果两个学生的年龄都是相同的,那么再根据名称的自然排序方式就行就OK了
		if (num==0)
		{
			return s1.getName().compareTo(s2.getName());
		}
		return num;
	}
}
           

六、高级应用:

/*
统计一个字符串中“每种字母出现的次数”,并且打印出来
打印的格式:x(几次)、y(几次)……

例如字符串:gfadgagkolauinaaf
【思路】
1.将字符串转化成为字符数组,因为要对每一个字母进行操作
2.定义一个map集合,因为打印结果的字母有顺序,所以要用到treemap集合
3.遍历字符数组
	将每一个字母作为健去查map集合,
	如果返回为null,将该字符和1存入到map集合中,
	如果返回不为null,说明该字符和对应的次数在集合中已经存在了,
	这时候,直接取出字符次数,自增之后再重新按照该健存入到集合中
*/
import java.util.*;
class GetCharNumber5
{
	public static void main(String[] args) 
	{
		String str="jfkl;ajf;lajfaljfl;afasfsadfds";
		getInfor(str);
	}

	public static void getInfor(String str)
	{
		//将字符串转化成为字符数组
		char[] ch=str.toCharArray();

		//定义一个TreeMap集合,泛型类型分别是Character和Integer
		//因为存入集合中的引用是【字符】和【次数】
		TreeMap<Character,Integer> tm=new TreeMap<Character,Integer>();
	
		//从字符数组中依次取出值到Map集合中判断是否存在
		for (int i=0; i<ch.length;i++ )
		{
			//这里是依次取出单个的字符到集合中去得到次数的值
			Integer value=tm.get(ch[i]);
			
			//如果Map中次数为空,那么就说明没有该字符存在,
			//于是加入该字符和次数1添加到集合中去,
			//这时出现的次数是第一次
			if (value == null)
			{
				tm.put(ch[i],1);
			}else 
			{
				//发现集合中的对应的该次数存在,那么再加入相应的键值字符和+1之后的value
				//值到集合中去!
				value=value+1;
				tm.put(ch[i],value);
			}
		}
		
		/*这里是entrySet方法,就不再一一介绍了,不难掌握的
		StringBuffer sb=new StringBuffer();
		Set<Map.Entry<Character,Integer>> setMap=tm.entrySet();
		Iterator<Map.Entry<Character,Integer>> it=setMap.iterator();
		
		while (it.hasNext())
		{
			Map.Entry<Character,Integer> me=it.next();
			Character key=me.getKey();
			Integer value=me.getValue();
			sb.append(key+"("+value+")"+"、");
		}

		sop(sb);
		*/
		
		//定义一个可变的容器来存储要打印的内容……
		StringBuffer sb=new StringBuffer();
		
		//通过keySet方法去到Set集合中实现元素的迭代取出并且打印出来
		Set<Character> set=tm.keySet();
		Iterator<Character> it=set.iterator();
		while (it.hasNext())
		{
			Character key=it.next();
			Integer value=tm.get(key);

			//定义打印格式:很简单的
			sb.append(key+"("+value+")"+"、");
		}
		sop(sb);	
	}
	
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
           

【总结】实现Map集合并不是很难,一定要抓住其特点,是一一映射存在的,很多问题都能迎刃而解!!