黑马程序员—java基础学习--Map集合、Collections,Arrays工具类

Map集合因其独特的特性而被广泛使用,使用Map集合注意到的问题也自然有很多,Map集合能够更加有序,高效的操作数据。今天,便要一同去遨游在Map集合中的海洋,感受Map集合的神奇。

*Map集合

一、Map集合的特点:

该集合存储键值对,是一对一对的往里面存,而且要保证元素的唯一性。

二、Map集合的基本方法:

1,增加

put ( key , value )

putAll ( key , value )

2,删除

clear ( )

remove ( key )

3,判断

containsKey ( key ) 

containsValue ( value ) 

isEmpty ( )

4,获取

get ( key )

size ( )

values ( )

entrySet ( )

keySet ( )

Map

| - - Hashtable :底层是哈希表数据结构,不可以存入null作为键和值的情况,该集合是同步的。 JDK1.0,效率低

| - - HashMap  :底层是哈希表数据结构,允许使用null键和null值,该集合是不同步的。JDK1.2,效率高

| - - TreeMap   :底层是二叉树数据结构,可以用于给map集合中的键进行排序,线程不同步。

经上述分析,Set集合和Map集合较为相似,其实Set集合底层就是使用了Map集合。

三、Map集合的取出方式

1,Set keySet:将map中所有的键存入到Set集合,因为set具备迭代器,所有可以迭代方式取出所有的键,在根据get方法,获取每一个键对应的值。理解代码如下:

import java.util.*;

class  MapDemo2
{
	public static void main(String[] args) 
	{
		Map map = new HashMap();
		
		//添加元素,添加元素如果出现相同的键,那么后添加的值会覆盖原有的键对应的值。并put方法会返回被覆盖的值
		map.put("01","zhangsan1");	//put方法有返回值,返回的是相同键的原来的值
		map.put("02","zhangsan2");
		map.put("03","zhangsan3");
		map.put("04","zhangsan4");

		//先获取map集合中的所有键的Set集合,keySet方法
		Set keySet = map.keySet();

		//通过迭代器迭代Set集合
		Iterator it = keySet.iterator();
		while(it.hasNext()){
			String key = it.next();
			//通过key获取对应的value
			String value = map.get(key);
			System.out.println(key+":"+value);
		}
	}
}

2,Set < Map.Entry< k , v>>  entrySet:将map集合中的映射关系存入到了set集合中,而这个关系的数据类型就是:Map.Entry。其实Entry也是一个接口,它是Map接口中的一个内部接口。理解代码如下:

import java.util.*;

class  MapDemo2
{
	public static void main(String[] args) 
	{
		Map map = new HashMap();
		
		//添加元素,添加元素如果出现相同的键,那么后添加的值会覆盖原有的键对应的值。并put方法会返回被覆盖的值
		map.put("01","zhangsan1");	//put方法有返回值,返回的是相同键的原来的值
		map.put("02","zhangsan2");
		map.put("03","zhangsan3");
		map.put("04","zhangsan4");
		
		//将Map集合中的映射关系取出,存入到Set集合中
		Set> entrySet = map.entrySet();

		Iterator> it = entry.iterator();

		while(it.hasNext()){
			Map.Entry me = it.next();
			String key = me.getKey();
			String value = me.getValue();
			System.out.println(key+":"+value);
		}
	}
}

四、Map集合的项目应用:

1,需求:对学生对象的年龄进行升序排序

因为数据时以键值对形式存在的,所以要使用可以排序的Map集合,TreeMap。代码如下:

import java.util.*;

class Student implements Comparable	//定义Student类,因为用到排序,所以实现了Comparable接口
{
	private String name;
	private int age;
	Student(String name,int age){
		this.name = name;
		this.age = age;
	}
	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}
	public String toString(){
		return this.name+":"+age;
	}
	public int hashCode(){	//复写hashCode和equals方法,如果集合用的是HashMap,则需要覆盖此方法
		return name.hashCode()+age*34;
	}
	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;
	}
}

class StuNameComparator implements Comparator	//定义姓名比较器
{
	public int compare(Student s1,Student s2){
		int num = s1.getName().compareTo(s2.getName());
		if(num == 0){
			return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
		}
		return num;
	}
}

class MapTest2 
{
	public static void main(String[] args) 
	{
		TreeMap tm = new TreeMap(new StuNameComparator());//将姓名比较器传入TreeMap集合中

		tm.put(new Student("lisi1",21),"beijing");
		tm.put(new Student("lisi1",21),"tianjin");
		tm.put(new Student("lisi2",22),"shanghai");
		tm.put(new Student("lisi3",23),"nanjing");
		tm.put(new Student("lisi4",24),"wuhan");

		Iterator> it = tm.entrySet().iterator();	//通过获取键值对映射关系的方式迭代Map集合
		while(it.hasNext()){
			Map.Entry me = it.next();
			Student stu = me.getKey();
			String addr = me.getValue();
			System.out.println(stu+">>"+addr);
		}
	}
}
2,需求:“sdfgzxvasdfxcvdf"获取该字符串中字母出现的次数,希望打印结果为a ( 1 )  c ( 2 ) .....

通过结果发现,每一个字母都有对应的次数,说明字母和次数之间都有映射关系,可以选择map集合,因为Map集合中存放的就是映射关系。

思路: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 s = charCount("sdfgzxvasdfxcvdf");
		System.out.println(s);
	}
	public static String charCount(String str){
		//1,将字符串转换为字符数组
		char[] chs = str.toCharArray();
		
		//2,定义一个TreeMap集合
		TreeMap tm = new TreeMap();

		int count = 0;
		//3,遍历数组
		for (int x=0; x= 'a' && chs[x]<='z' || chs[x]>='A'&&chs[x]<='Z'))
				continue;
			Integer value = tm.get(chs[x]);

			if(value != null){
				count = value;
			}
			count++;
			tm.put(chs[x],count);
			count = 0;
		}
		//定义StringBuilder缓冲区
		StringBuilder sb = new StringBuilder();
		//迭代Map,将Map的键和值存入字符串缓冲区
		Iterator> it = tm.entrySet().iterator();
		while(it.hasNext()){
			Map.Entry me = it.next();
			Character key = me.getKey();
			Integer value = me.getValue();
			sb.append(key+"("+value+")");
		}
		return sb.toString();
	}
}

五、Map集合的扩展知识

Map集合被使用时因为具备映射关系,所以会出现映射的嵌套关系,如传智播客具备就业办和基础班,基础班和就业班各拥有自己的学生姓名和学号,也就是毕老师所讲的大圈套小圈思想。此时,使用迭代器迭代传智播客,再在迭代的过程中迭代出就业办和基础班的学生信息即可解决Map多映射关系集合。

六、Collections与Collection的区别

Collection为util包中的接口,而Collections为util中的工具类,具备的都是静态方法,常见的有集合的排序,取最大值,反转等常用方法。

Collections逆转比较器方法如下:

import java.util.*;

class CollectionsDemo2 
{
	public static void main(String[] args) 
	{
		orderDemo();
	}
	public static void orderDemo(){
		TreeSet ts = new TreeSet(Collections.reverseOrder(new StrComparator()));//此处传入Collections工具类中的强行逆转比较器,使得代码更为简单
		ts.add("abcde");
		ts.add("aaa");
		ts.add("kkk");
		ts.add("ccc");

		Iterator it = ts.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}
	}
}
class StrComparator implements Comparator//以前的做法,定义比较器来进行反转
{
	public int compare(String s1,String s2){
		return s2.compareTo(s1);
	}
}
七、Arrays工具类

Arrays:用于操作数组的工具类,里面都是静态方法。

asList ( arr ):将数组变为集合。此方法中如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转成集合中的元素,如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。
将数组变为List集合有什么好处?

可以使用集合的思想和方法来操作数组中的元素。注意,将数组变成集合,不可以使用集合的增删方法,因为数组的长度是固定的,如果增删,会发生异常。

数组变为集合的代码如下:

import java.util.*;

class ArraysDemo 
{
	public static void main(String[] args) 
	{
		String[] arr = {"abc","cc","kkkk"};
		List list = Arrays.asList(arr);	//asList方法是将数组转换为集合
		
		System.out.println("contains:"+list.contains("cc"));	//转换为集合后可使用集合的方法
	//	list.add("qq");	//此处将抛出异常,因为数组长度是不可变的
		System.out.println(list);

		int[] nums1 = {2,4,5};
		Integer[] nums2 = {2,4,5};//此处同时涉及自动装箱
		List list1 = Arrays.asList(nums1);
		List list2 = Arrays.asList(nums2);
		System.out.println(list1);	//此处打印结果为数组的哈希码
		System.out.println(list2);	//此处打印结果为[2,4,5]
	}
}

集合转为数组注意问题:

1.指定类型的数组要定义多长呢?

当指定类型的数组小于了集合的size,那么该方法内部会创建一个新的数组,长度为集合的size,当指定类型的数组长度大于了集合的size,就不会新创建数组,而是使用了传递进来的数组。所以创建一个刚刚好的数组最好。

2,为什么要将集合转换为数组?

为了限定对元素的操作,不需要进行增删了

import java.util.*;

class  CollectionToArray
{
	public static void main(String[] args) 
	{
		ArryaList al = new ArrayList();

		al.add("abc1");
		al.add("abc2");
		al.add("abc3");

		String[] arr = al.toArray(new String[al.size()]);//通过Collection接口中的toArray方法将集合转换为数组
		System.out.println(Arrays.toString(arr));	//直接用Arrays工具类的toString方法进行数组的打印
	}
}
八、高级for循环(for each循环)

格式:

for ( 数据类型 变量名  : 被遍历的集合或者数组 ) {

}

对集合进行遍历,只能获取元素,但是不能对集合进行过多操作。

迭代器除了遍历还可以进行remove集合中元素的动作。

如果使用ListIterator,还可以在遍历过程中对集合进行增删改查的动作。

传统for循环和高级for的区别:

高级for有一个局限性,必须有被遍历的目标。建议在遍历数组的时候还是希望使用传统for,因为传统for可以定义索引。
理解代码如下:

import java.util.*;

class ForEachDemo 
{
	public static void main(String[] args) 
	{
		ArrayList al = new ArrayList();

		al.add("abc1");
		al.add("abc2");
		al.add("abc3");
		
		//1.5之后可以简化书写为下:
		for(String str : al){
			System.out.println(str);
		}

		/*
		未用foreach代码如下:
		Iterator it = al.iterator();
		while(it.hasNext){
			System.out.println(it.next());
		}
		*/

		HashMap hm = new HashMap();
		hm.put(1,"a");
		hm.put(2,"b");
		hm.put(3,"c");
		
		//第一种用高级for遍历map集合的方法
		Set keySet = hm.keySet();
		for(Integer key:keySet){
			System.out.println(key+":"+hm.get(key));
		}

		//第二种用高级for遍历map集合的方法
		Set> entrySet = hm.entrySet();
		for(Map.Entry me : entrySet){
			System.out.println(me.getKey()+"::"+me.getValue());
		}
	}
}

九、可变参数

可变参数其实就是数组的简写形式,不用每一次都手动的建立数组对象,只要将要操作的元素作为参数传递即可。隐式的将这些参数封装成了数组。在使用时注意可变参数一定要定义在参数列表的最后面。

class ParamMethodDemo 
{
	public static void main(String[] args) 
	{
		show("abc",2,4,5,6,7,8);
	}
	//可变参数的做法
	public static void show(String str,int... arr){
		System.out.println(arr.length);
	}
	/*
	//以前的做法
	public static void show(int[] arr){
		
	}
	*/
}

十、静态导入StaticImport

 当类名重名时,需要指定具体的包名,当方法重名时,指定具备所有的对象或类。

静态导入示例:

//	import java.util.*;
import static java.util.Arrays.*;	//导入的是Arrays这个类中所有静态成员
import static java.lang.System.*;	//导入的是System类中所有的静态成员
class StaticImport 
{
	public static void main(String[] args) 
	{
		int[] arr = {3,1,5};
		//Arrays.sort(arr);
		sort(arr);	//静态导入之后可以省略类名

		//int index = Arrays.binarySearch(arr,1);
		int index = binarySearch(arr,1);

		//System.out.println(Arrays.toString(arr));
		out.println(toString(arr));

		out.println("index="+index);

	}
}


你可能感兴趣的:(黑马程序员—java基础学习--Map集合、Collections,Arrays工具类)