跟着老毕学Java-集合框架篇之Map与工具类

------- android培训java培训、期待与您交流! ----------
————————————————————————————————————————————

 

Map和集合工具类

Map

概述

Map集合:它存储的是键值对,其中键必须保证唯一性,值允许重复。Map集合没有自身特有的迭代器,它的元素取出是通过将键或键值对放入Set集合中,利用Set集合中的迭代器取出的。Map是双列集合,Collection是单列集合。

 

共性方法

Map接口中定义了该体系通用的方法。

1.添加

 V put(K key, V value)

 void putAll(Map<? extends K,? extends V>m)

 注意putadd的不同put时,如果key已经存在,则新存入的值覆盖原来的值,并把原来的值作为方法的返回值;add时,如果该元素已经存在,则不能存入集合,方法返回值为false,如果存在,则存入集合,方法返回值为true

2.删除

clear()

V remove(Object key) 

 

3.判断

boolean containsKey(Object key) 

boolean containsValue(Object value)

boolean isEmpty() 

 

 

4.获取

 V get(Object key)

 int size()

 Collection<V> values() 

 

Set<Map.Entry<K,V>>entrySet()

Set<K> keySet() 

示例代码1

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
class  MapDemo
{
	public static void main(String[] args) 
	{
		Map<String,String> map = new HashMap <String,String>();
		System.out.println("put:"+map.put("01","zhangsan01"));//结果为null
		System.out.println("put:"+map.put("01","wangwu"));//结果我zhangsan01
		/*
		put如果存入了已经存在的键,则新键值会覆盖旧键值,并将旧键值返回;put存入一个未存在的键时,会返回null。
		*/
		map.put("02","zhangsan02");
		map.put("03","zhangsan02");
		map.put(null,null);

		System.out.println("containsKey:"+map.containsKey("022"));
		//System.out.println("remove:"+map.remove("02"));
		System.out.println("get:"+map.get("023"));
		map.put("04","null");
		System.out.println("get:"+map.get("04"));
		//可以通过get方法的返回值来判断一个键是否存在。通过返回null来判断。(毕老师这点讲的是不是有问题?)

		
		//获取map集合中的值
		Collection <String> coll =map.values();

		System.out.println(coll);
		System.out.println(map);
	}
}
/*
既然hashMap可以存放null键null值,那么通过get方法返回null,应该不能判断该键是不是存在,因为可能出现有键值为空的情况;这时就要用containsKey()方法来判断了
*/


 

Map的体系

Map

         |---Hashtable<K,V>:底层是哈希表数据结构,不可以存入nullnull值,该集合是同步的。JDK1.0,效率低。,

         |---HashMap<K,V>:底层是哈希表数据结构,允许存入nullnull值,该集合是不同步的。JDK1.2,效率高。

         |---TreeMap<K,V>:底层是二叉树结构,线程不同步,可以用于给Map集合中键进行排序。

Set很像,其实Set底层就是使用了Map集合。

元素取出的两种方式

示例代码2

/*

map集合的两种取出方式:
1.Set<K> keySet;将map中的所有的键存入到Set集合,因为set具有迭代器。
	所以可以迭代方式取出所有的键,再根据get方法,获取每一个键对应的值。
	Map集合的取出原理:将Map集合转成Set集合,再通过迭代器取出。
2.Set<Map.Entry<K,V>> entrySet:将Map集合中的映射关系存入到了Set集合中,
	而这个关系的数据类型就是:Map.Entry.
*/
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.Map;

class MapDemo2 
{
	public static void main(String[] args) 
	{
		Map <String,String> map = new HashMap<String ,String>();
		map.put("01","zhangsan01");
		map.put("02","zhangsan02");
		map.put("03","zhangsan03");
		map.put("04","zhangsan04");
		System.out.println(map);
		System.out.println("-------------");

		
		//Map元素取出的方式一(EntrySet):将Map集合中的映射关系取出,存入到Set集合中。
		Set<Map.Entry<String , String>> entrySet = map.entrySet();
		System.out.println(entrySet);
		System.out.println("-------------");

		Iterator<Map.Entry<String , String>> it = entrySet.iterator();
		while(it.hasNext())
		{
			Map.Entry<String,String> me = it.next();
			String key = me.getKey();
			String value = me.getValue();
			System.out.println(me);
			System.out.println("key:"+key+",value="+value);

		}
		
		//元素取出的方式二(KeySet)
		/*
		//先获取map集合的所有键的Set集合。
		Set<String> keySet = map.keySet();
		//有了Set集合,就可以获取机迭代器。
		Iterator<String> it = keySet.iterator();
		while(it.hasNext())
		{
			String key = it.next();
			String value = map.get(key);
			System.out.println("key:"+key+",value="+value);

		}
		*/
	}
}

/*
Map.Entry 其实Entry也是一个接口,他是Map接口中的一个内部接口。如下:

interface Map
{
	public static interface Entry
	{
		public abstract Object getKey();
		public abstract Object getValue();
	}
}
class  HashMap implements Map
{
	class Haha implements Map.Entry
	{
		public  Object getKey(){}
		public  Object getValue(){}
	}
	
}
*/

练习1

/*
每一个学生都有对应的归属地
学生Student,地址String
学生属性:姓名,年龄
注意:姓名和年龄相同视为同一个学生
保证学生的唯一性。

1.描述学生
2.定义Map容器,将学生作为键,地址作为值,存入。
3.获取Map集合中的元素。
*/

import java.util.*;
class MapTest 
{
	public static void main(String[] args) 
	{
		HashMap<Student,String> hm = new HashMap<Student,String>();
		hm.put(new Student("lisi1",22),"beijing");
		hm.put(new Student("lisi1",22),"shanghai");
		hm.put(new Student("lisi3",24),"wuhan");  
		hm.put(new Student("lisi4",25),"nanjing");

		//第一种取出方式:keySet()
		Iterator<Student> it = hm.keySet().iterator();
		while(it.hasNext())
		{
			Student stu = it.next();
			String addr = hm.get(stu);
			System.out.println(stu+".."+addr);
		}
		System.out.println("-------------");

		//第二种取出方式:entrySet()
		Set<Map.Entry<Student,String>> entrySet = hm.entrySet();
		Iterator<Map.Entry<Student,String>> ite = entrySet.iterator();
		while(ite.hasNext())
		{
			Map.Entry<Student,String> me = ite.next();
			Student s = me.getKey();
			String str = me.getValue();
			System.out.println(s+","+str);
		}

	}
}

/*
 为什么将复写equals、hashCode方法,并实现comparable接口?
 因为,Sutdent有可能存入HashMap中,也有可能存入TreeMap中。
 
 */
class Student implements Comparable<Student>
{
	private String name;
	private int age;
	Student(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	public String getName()
	{
		return name;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public int getAge()
	{
		return age;
	}
	public void setAge(int age)
	{
		this.age = age;
	}
	public int hashCode()
	{
		return name.hashCode()+37*age;//这点要注意
	}
	public boolean equals(Object obj)
	{
		if( !(obj instanceof Student))
			throw new ClassCastException("类型不匹配"); 
		Student s = (Student) obj;
		return this.name.equals(s.getName())&&this.age==s.getAge();
	}
	public int compareTo(Student s)
	{
		int num = new Integer(this.age).compareTo(new Integer(s.getAge()));
		if(num == 0)
			this.name.equals(s.name);
		return num;
	}
	public String toString()
	{
		return name+","+age;
	}
}

练习2

 
/*
需求:对学生对象的年龄进行升序排序。

因为数据是以键值对形式存在的,所以要使用可以排序的Map集合,TreeMap。
*/
import java.util.*;

class StuNameComparator implements Comparator<Student>
{
	public int compare(Student s1,Student s2)
	{
		int num = s1.getName().compareTo(s2.getName());
		if(num == 0)
			return new Integer(s1.getAge()).compareTo(s2.getAge());
		return num;
	}
}
class MapTest2 
{
	public static void main(String[] args) 
	{
		TreeMap<Student,String> tm = new TreeMap<Student,String>(new StuNameComparator());
		tm.put(new Student("lisi1",22),"beijing");
		tm.put(new Student("alisi1",23),"shanghai");
		tm.put(new Student("alisi1",24),"shanghai");
		tm.put(new Student("xlisi3",24),"wuhan");  
		tm.put(new Student("lisi4",25),"nanjing");

		Iterator<Map.Entry<Student,String>> it = tm.entrySet().iterator();
		while(it.hasNext())
		{
			Map.Entry<Student,String> me = it.next();
			Student stu = me.getKey();
			String addr = me.getValue();
			System.out.println(stu+","+addr);
		}
		
	}
}


 

练习3

/*
练习:
”stdafasdffadf“获取该字符串中的字母出现的次数。
希望打印结果:a(1)c(2)。。。。

通过结果发现,每个字母都有对应的次数
说明字母和次数之间都有映射关系。

注意了,当发现有映射关系时,可以选择Map集合
因为Map集合中存放的就是映射关系。

什么时候使用Map集合呢?
当数据之间存在这个映射关系时,就要先想到Map集合。
我的思路:
1.建立字母为键,类型为char,次数为值,类型为int,的Map,因为字母按顺序打印,所以选用TreeMap
2.将字符串遍历,重复的字符,值++;
3.使用迭代器打印TreeMap集合。

毕老师思路:
1.将字符串转换成字符数组,因为要对每一个字母进行操作。

2.定义一个map集合,因为打印结果的字母有顺序,所以使用TreeMap集合。

3.遍历字符数组。
	将每一个字符作为键去查map集合。
	如果返回null,将该字母和1存入到map集合。
	如果返回不是null,说明该字母在map集合已经存在,并有对应的次数。
	那么就获取该次数进行自增,然后将该字母和自增后的次数存入到map集合中,覆盖调用原键所对应的值。
4.将map集合中的数据变成指定的字符串形式返回。


*/
import java.util.*;
class MapTest3 
{
	public static void main(String[] args) 
	{
		//String str = myCharCount("adfasdf!!!!!sssasdfas");
		String str =charCount("dsadfadfasdf");
		System.out.println(str);
	}
	//毕老师的方法
	public static String charCount(String str)
	{
		char [] chs = str.toCharArray();
		TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();			
		for(int x =0;x<chs.length;x++)
		{
			int count =0;
			char ch = str.charAt(x);
			if(!(ch>='a'&&ch<='z'|| ch>='A'&&ch<='Z'))
				continue ;

			Integer value = tm.get(chs[x]);
			
			/*
			if(value == null)
				tm.put(chs[x],1);
			else
			{
				value = value+1;
				tm.put(chs[x],value);
			}
			*/
			if(value!=null)
				count = value;
			count++;
			tm.put(chs[x],count);				
		}

		StringBuilder sb = new StringBuilder();
		Set<Map.Entry<Character,Integer>> entrySet = tm.entrySet();
		Iterator<Map.Entry<Character,Integer>>it = entrySet.iterator();
		while(it.hasNext())
		{
			Map.Entry<Character,Integer> me = it.next();
			Character ch = me.getKey();
			Integer value = me.getValue();
			sb.append(ch+"("+value+")");
		}
		return sb.toString();

	}
	//我的方法
	public static String myCharCount(String str)
	{	
		
		String resault="";
		TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();

		int count = 0;				
		for(int x =0;x<str.length();x++)
		{
			char ch = str.charAt(x);
			if(!(ch>='a'&&ch<='z'|| ch>='A'&&ch<='Z'))
				continue ;
			if(!tm.containsKey(ch))
				tm.put(ch,1);
			else
			{
				int num =tm.get(ch)+1;
				tm.put(ch,num);
			}				
		}

		
		Iterator<Map.Entry<Character,Integer>> it = tm.entrySet().iterator();
		while(it.hasNext())
		{
			Map.Entry<Character,Integer> me = it.next();
			char letter = me.getKey();
			int num = me.getValue();
			resault += letter+"("+num+")";
		}

		return resault;
		
	}
}

 

Map扩展

Map集合中的值还可以是Map集合,这是Map集合嵌套使用的情况。

示例代码3

/*
map扩展知识

map集合使用是因为具备映射关系。

“yureban” “01” “zhangsan”
“yureban” “02” "lisi"
"jiuyeban" "01" "zhousi"
"jiuyeban" "02" "liuwu"

一个学校有多个教室,每个教室都有自己的名字,而一个教室对应多个学生。

*/
import java.util.*;
class Student1
{
	private static String id;
	private String name;
	Student1(String id,String name)
	{
		this.id = id;
		this.name = name;
	}
	public String toString()
	{
		return id+":::"+name;
	}
	public static void main(String[] args) 
	{
		Student1  s1 =new Student1("id","name");
		id = "1212";
		Integer a = Integer.parseInt(id,10);		
		System.out.println(s1.id);
		System.out.println(a);
		
		
	}
	
}
class MapDemo3 
{
	public static void demo()
	{
		HashMap<String,List<Student1>> czbk = new HashMap<String,List<Student1>>();
		List<Student1> yure = new ArrayList<Student1>();
		List<Student1> jiuye = new ArrayList<Student1>();

		czbk.put("yuer:",yure);
		czbk.put("jiuye:",jiuye);

		yure.add(new Student1("01","zhangsan"));
		yure.add(new Student1("02","wagnwu"));

		jiuye.add(new Student1("01","liuqiang"));
		jiuye.add(new Student1("02","limeng"));

		Iterator<String> it = czbk.keySet().iterator();
		while(it.hasNext())
		{
			String roomName = it.next();
			List<Student1> room = czbk.get(roomName);
			System.out.println(roomName);
			getInfos(room);
		}
	}
	public static void getInfos(List<Student1> room)
	{
		Iterator<Student1> it = room.iterator();
		while(it.hasNext())
		{
			System.out.println(it.next());
		}
	}
	
	public static void main(String[] args) 
	{
		demo();
	}

	public static void getStudentInfo(HashMap<String,String> hm)
	{
		Iterator<Map.Entry<String,String>> it = hm.entrySet().iterator();
		while(it.hasNext())
		{
			Map.Entry<String,String> me = it.next();
			String num =me.getKey();
			String name = me.getValue();
			System.out.println(num+":"+name);
		}
		System.out.println(hm);
	}
}

集合框架工具类

Collections

Collections是一个集合工具类,它没有构造方法,所有的成员方法都是静态的。利用它可以实现对集合的一些特殊操作,如排序、二分查找、取最值、反转等。

1、  List集合进行排序
Collections.sort(list)Collections.sort( list, comparator)

2、  获取集合的最大值

Collections.sort(collection)Collections.sort(collectioncomparator)

3、  二分查找
binarySearch(List<? extends Comparable<? super T>> list, T key)
binarySearch(List<? extends T> list, T key, Comparator<? super T> c)

4、  填充
filllistobj),将集合所有元素都换成obj

5、  替换
replaceAll(List<T> list, T oldVal, T newVal),将集合中出现的所有的某一个值,替换为另一个。

6、  反转

reverse(List<?> list),头变尾,尾变头。

7、随机排列
         shuffle(list),应用:洗牌、掷色子。

重点掌握的下边三个方法

1、  reverseOrder:强行逆转比较器的自然顺序或元素的自然顺序。

2、  将集合由线程不安全转为线程安全的
synchronizedCollection(Collection<T>c)
synchronizedList(List<T>list)
synchronizedMap(Map<K,V>m)
synchronizedSet(Set<T>s)

其原理是:内部封装一个容器,然后定义一个锁,使用该锁同步并封装该容器的所有方法。

示例代码4

import java.util.*;
class  CollectionsDemo
{

	public static void main(String[] args) 
	{
		sortDemo();
	}

	public static  void sortDemo()
	{
		List <String> list = new ArrayList<String>();
		list.add("abcdd");
		list.add("asdfas");
		list.add("saa");
		list.add("bbb");
		list.add("qt");
		list.add("bbb");



		sop(list);
		//排序演示,要排序的元素继承comparable类或者新建一个比较器。
		Collections.sort(list,new StrLenComparator());
		sop(list);
		sop("----------sort");

		//取最大值演示:要排序的元素继承comparable类或者新建一个比较器。
		String max = Collections.max(list,new StrLenComparator());
		sop(max);
		sop("----------max");
		
		//二分查找:必须先是有序集合,前后排序的比较规需要相同,是自然顺序都是自然顺序,是比较器都是比较器。
		int index = Collections.binarySearch(list,"kkkk");
		//int index = halfSearch(list,"aaaa");
		sop(index);
		sop("----------binarySearch");
		/*
		我的问题:如果前边排序是用比较器,后来查找的时候没有加比较器,返回值如何?
		*/
		
		//reverse:将集合中的元素反转。
		Collections.reverse(list);
		sop(list);
		sop("----------reverse");

		//swap():交换集合中两个元素的位置
		Collections.swap(list,2,5);
		sop(list);
		sop("----------swap");

		//shufle:使用默认随机源对指定列表进行置换(如洗牌动作、色子)
		Collections.shuffle(list);
		sop(list);
		sop("----------shuffle");

		//fill方法:可以将list集合中的所有元素替换成指定元素,
		//练习:将list集合中的部分元素替换成指定元素。
		sop(list);
		Collections.fill(list,"yyyy");
		sop(list);
		sop("----------fill");
		//repalceAll:将集合中的所有的指定元素替换成新元素
		Collections.replaceAll(list,"yyyy","00");//其实封装了list.set(index,"00");
		sop(list);
		sop("----------repalceAll");
		


	}

	//二分法原理。
	public static int halfSearch(List<String> list,String key/*,Comparator cmp*/)
	{
		int max,min,mid;
		max =list.size()-1;
		min = 0;

		while(min<max)
		{
			mid =(max+min)>>1;
			String str = list.get(mid);
			int num = str.compareTo(key);//int num = cmp.compare(s1,s2);
			if(num>0)
				max =mid -1;
			else if(num<0)
				min =mid + 1;
			else
				return mid;
		}

		return min;//-min-1;
	}
	public static void  sop(Object obj)
	{
		System.out.println(obj);
	}
}
class StrLenComparator implements Comparator<String>
{
	public int compare(String s1,String s2)
	{
		if(s1.length()>s2.length())
			return 1;
		if(s1.length()<s2.length())
			return -1;
		return s1.compareTo(s2);
	}
}


 

示例代码5

*
Collections.reverseOrder()命令:反转自然顺序或比较器
*/
import java.util.*;
class StrComparator implements Comparator<String>
{
	public int compare(String s1,String s2)
	{
		/*int num =s1.compareTo(s2);
		if(num>0)
			return 1;
		if(num<0)
			return -1;
		return num;
		*/

		return s2.compareTo(s1);
	}
}
class StrLenComparator implements Comparator<String>
{
	public int compare(String s1,String s2)
	{
		if(s1.length()>s2.length())
			return 1;
		if(s1.length()<s2.length())
			return -1;
		return s1.compareTo(s2);
	}
}

class CollectionsDemo2 
{
	public static void main(String[] args) 
	{
		orderDemo();
	}
	public static void orderDemo()
	{
		TreeSet<String> ts = new TreeSet<String>(Collections.reverseOrder( new StrLenComparator()));
		ts.add("adsdf");
		ts.add("afasdf");
		ts.add("efsf");
		ts.add("bc");
		ts.add("e");

		Iterator<String> it = ts.iterator();
		while(it.hasNext())
		{
			System.out.println(it.next());
		}
	} 
}


 

 

Arrays

数组工具类:

binarySearch:二分查找数组中的元素。
copyOf:复制数组
copyOfRange:复制数组内的某一段

equals:判断两个数组是否相等。

deeEquals:如果两个指定数组彼此是深层相等的,则返回true

deeHashCode:基于指定数组的深层内容返回哈希码。

deeToString: 返回指定数组深层内容的字符串表示形式。

fill:将指定的值分配给指定数组的每个元素。

hashCode:基于指定数组的内容返回哈希码。

sort: 对数组元素进行排序

toString:把数组的元素转化成字符串

重点Arrays有个asList(T… t)方法,可以把数组转换为List集合,它与Collection接口中的toArray一起,构成了数组API和集合API之间的桥梁。

CollectionToArray

示例代码6

/*
集合变数组。
Collection接口中的toArray方法。
*/
import java.util.*;
class CollectionToArray 
{
	public static void main(String[] args) 
	{
		ArrayList<String >al = new ArrayList<String>();
		al.add("abc1");
		al.add("abc2");
		al.add("abc3");

		/*
		1.指定类型的数组到底要定义多长?
		当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组,数组的长度为集合的size
		当指定类型的数组长度大于了集合的size,就不会新创建数组,而是用传递进来的数组。

		所以创建一个刚刚好的数组最优。

		2.为什么要将集合变数组?
		为了限定对元素的操作。(如返回数据时,将数据变成数组)

		*/

		String [] arr = al.toArray(new String[0]);
		System.out.println(Arrays.toString(arr));

	}
}


 

 

ArrayToList

示例代码7

class ArraysDemo 
{
	public static void main(String[] args) 
	{
//		int[] arr =new int[]{2,5,7};
//		System.out.println(Arrays.toString(arr));
		

		String [] arr ={"abc","cc","kkk"};
		//把数组编程List集合有什么好处?
		/*
		可以使用集合的思想和方法来操作数组中的元素。(如判断是否包含:如果是数组,需要进行循环判断))。否则需要自己封装多种方法。

		注意:将数组变成集合,不可以使用集合的增删方法(add,remove),因为数组的长度是固定的。

		如果增删了,那么会发生UnsupportedOperationException
		*/
		
		List<String>  list = Arrays.asList(arr);
		//list.add(0,"k");//UnsupportedOperationException
		System.out.println(list);

		
		
		
		int [] nums ={2,5,9};
		List<int[]> li = Arrays.asList(nums);
		

		/*
		如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转成集合中的元素。
		如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存储。
		*/

		sop(li);
		Integer [] nums1 ={2,5,9};
		List<Integer> lis = Arrays.asList(nums1);
		sop(lis);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}


 

 


————————————————————————————————————————————

------- android培训java培训、期待与您交流! ----------

你可能感兴趣的:(跟着老毕学Java-集合框架篇之Map与工具类)