黑马程序员——Java基础---集合框架(二)及工具类Collections、Arrays

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

第一讲   Map集合

一、概述

1、简述  

Map<K,V>集合是一个接口,和List集合及Set集合不同的是,它是双列集合,并且可以给对象加上名字,即键(Key)

2、特点

1)该集合存储键值对。一对一对往里存。

2)而且要保证键的唯一性。

二、Map集合的子类

Map

|--Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jdk1.0.效率低。 

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

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

三、Map集合的常用方法

1、添加

put(K key, V value);   //添加元素,如果出现添加时,相同的键。那么后添加的值会覆盖原有键对应值。并且put方法会返回被覆盖的值。

putAll(Map<? extends K,? extends V> m)   //添加一个集合

2、删除

clear();   //清空

remove(Object key);   //删除指定键值对

3、判断

containsValue(Object value) ;   //判断值是否存在

containsKey(Object key) ;   //判断键是否存在

isEmpty();   //判断是否为空

4、获取

get(Object key);   //通过键获取值

size();   //获取集合的长度

values();   //获取Map集合中的所有的值,返回一个Collection集合

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

Set<K> keySet();

注:HashMap集合可以通过get()的返回值来判断一个键是否存在,通过返回null来判断。

四、Map集合的两种取出方式

Map集合的取出原理:将Map集合转成Set集合,再通过迭代器取出。

1、Set<K> keySet():将map中所有的键存入到Set集合。因为Set具备迭代器。所以可以用迭代方式取出所有的键,再根据get方法。获取每一个键对应的值。

示例:

import java.util.*;

class MapDemo 
{
	public static void main(String[] args) 
	{
		Map<String,String> map = new HashMap<String,String>();

		map.put("02","tom2");
		map.put("03","tom3");
		map.put("01","tom1");
		map.put("04","tom4");
		
		//先获取map集合中的所有键的Set集合,keySet()
		Set<String> keySet = map.keySet();
		//有了Set集合,就可以获取迭代器
		Iterator<String> it = keySet.iterator();

		while(it.hasNext())
		{
			String key = it.next();
			//有了键可以通过map集合的get获取其对应的值
			String value = map.get(key);
			System.out.println("key:"+key+"value:"+value);
		}	

	}
}
2、Set<Map.Entry<k,v>> entrySet:将map集合中的映射关系存入到了set集合中,而这个关系的数据类型就是:Map.Entry。Entry其实就是Map中的一个static内部接口。
示例:

import java.util.*;

class MapDemo2 
{
	public static void main(String[] args) 
	{
		Map<String,String> map = new HashMap<String,String>();

		map.put("02","tom2");
		map.put("03","tom3");
		map.put("01","tom1");
		map.put("04","tom4");
		//将Map集合中的映射关系取出,存入到Set集合中
		Set<Map.Entry<String,String>> entrySet = map.entrySet();
		//有了Set集合,就可以获取迭代器
		Iterator<Map.Entry<String,String>> it = entrySet.iterator();
		
		while(it.hasNext())
		{
			Map.Entry<String,String> me = it.next();
			//通过Map.Entry中特有的方法getKey()和getValue()获取键和值
			String key = me.getKey();
			String value = me.getValue();

			System.out.println(key+":"+value);
		}
	}
}
关于Map.Entry:

Map是一个接口。其实,Entry也是一个接口,Entry其实就是Map中的一个static内部接口。就相当于内部类一样。为什么要定义到内部呢?因为只有有了Map集合,有了键

值对,才会有键值的映射关系。关系属于Map集合中的一个内部事物。而且该事物在直接访问Map集合中的元素。

练习:

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

思路:
1、描述学生。
2、定义map容器。将学生作为键,地址作为值。存入。
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;
	}
	//复写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;
	}
	//复写hashCode
	public int hashCode()
	{
		return name.hashCode()+age*34;
	}
	//复写equals,比较对象内容
	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 String getName()
	{
		return name;
	}
	public int getAge()
	{
		return age;
	}
	//复写toString(),自定义输出内容
	public String toString()
	{
		return name+":"+age;
	}
}


class MapTest 
{
	public static void main(String[] args) 
	{
		Map<Student,String> map = new HashMap<Student,String>();
		
		map.put(new Student("tom01",21),"beijing");
		map.put(new Student("tom02",22),"shanghai");
		map.put(new Student("tom03",23),"tianjin");
		map.put(new Student("tom01",24),"lanzhou");

		//第一种取出方式keySet

		Set<Student> keySet = map.keySet();

		Iterator<Student> it = keySet.iterator();

		while(it.hasNext())
		{
			Student stu = it.next();
			String addr = map.get(stu);
			System.out.println(stu.getName()+":"+stu.getAge()+".."+addr);
		}
		//第二种取出方式 entrySet
		Set<Map.Entry<Student,String>> entrySet = map.entrySet();

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

	}
}
五、Map集合的扩展及应用

1、什么时候使用Map集合:当数据之间存在映射关系时,就应该首先想到用map集合。

2、示例:
获取某个字符串中的字母出现的次数。如:"sdfgzxcvasdfxcvdf",打印出:a(1)c(2).....的结果

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

代码:

/*
思路:
1、将字符串转换成字符数组。因为要对每一个字母进行操作。

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

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

4、将map集合中的数据变成指定的字符串形式返回。
*/
import java.util.*;
class MapTest 
{
	public static void main(String[] args) 
	{
		String s = charCount("absfafe,ferge+rtryhrjhy");
		System.out.println(s);
	}
	//获取字符串中字符出现的次数
	public static String charCount(String str)
	{
		char[] chs = str.toCharArray();
		//定义一个TreeMap集合
		TreeMap<Character,Integer> map = new TreeMap<Character,Integer>();

		int count = 0;
		for(int x=0;x<chs.length;x++)
		{
			if(!(chs[x]>='a' && chs[x]<='z') || chs[x]>='A' && chs[x]<='Z')
				continue;//如果字符串中不是字母,则跳出本次循环进行下次循环

			Integer value = map.get(chs[x]);

			if(value!=null)//如果集合中没有该字母则存入
				count = value;
			count++;
			map.put(chs[x],count);//存入键值对

			count = 0;
		}
		//定义一个容器,将键值对存入
		StringBuilder sb = new StringBuilder();
		Set<Map.Entry<Character,Integer>> entrySet = map.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();//返回字符串
	}
}
六、Map扩展知识

 在很多项目中,应用比较多的是一对多的映射关系,这就可以通过嵌套的形式将多个映射定义到一个大的集合中,并将大的集合分级处理,形成一个体系。

如:

/*
map扩展知识。
map集合被使用是因为具备映射关系。
下面是一个学校有多个教室。每一个教室都有名称。
*/

import java.util.*;

class Student
{
	private String id;
	private String name;
	Student(String id,String name)
	{
		this.id = id;
		this.name = name;
	}
	public String toString()
	{
		return id+":"+name;
	}
}

class MapDemo3 
{
	public static void method_list()
	{	
		//学校集合
		HashMap<String,List<Student>> cxsw = new HashMap<String,List<Student>>();
		//qh班集合
		List<Student> qh = new ArrayList<Student>();
		//zy班集合
		List<Student> zy = new ArrayList<Student>();
		//学校中班级集合和名称的集合
		cxsw.put("siqi",qh);
		cxsw.put("yiqi",zy);
		
		//qh班中学生学号和姓名的映射
		qh.add(new Student("01","tom"));
		qh.add(new Student("02","Jerry"));
		
		//zy班中学生学号和姓名的映射
		zy.add(new Student("01","Danny"));
		zy.add(new Student("02","Jack"));

		Iterator<String> it = cxsw.keySet().iterator();

		while(it.hasNext())
		{
			String className = it.next();
			List<Student> clas = cxsw.get(className);
			
			getInfos(clas);
		}
	}
	//获取全部学生信息
	public static void getInfos(List<Student> list)
	{
		Iterator<Student> it = list.iterator();
		while(it.hasNext())
		{
			Student s = it.next();
			System.out.println(s);
		}
	}
	public static void main(String[] args) 
	{
		method_list();

	}
	//获取班级中学生信息,包括姓名和学号
	public static void getStudentInfo(HashMap<String,String> classMap)
	{
		Iterator<String> it = classMap.keySet().iterator();

		while(it.hasNext())
		{
			String id = it.next();
			String name = classMap.get(id);
			System.out.println(id+":"+name);
		}
	}
}

第二讲   Collections

一、概述
Collections:集合框架的工具类。里面定义的都是静态方法。提供的方法中有可以对list集合进行排序,二分查找等方法。
通常常用的集合都是线程不安全的。因为要提高效率。

二、常见操作

1、查找

T max(Collection<? extends T> coll);//根据集合的自然顺序,获取coll集合中的最大元素

T max(Collection<? extends T> coll,Comparator<? super T> comp);//根据指定比较器comp的顺序,获取coll集合中的最大元素

int binarySearch(Lsit<? extends Comparable<? super T>> list,Tkey);//二分法搜索list集合中的指定对象

2、替换

void fill(List<? super T> list, T obj);//将list集合中的全部元素替换成指定对象obj

boolean replaceAll(List<T> lsit,T oldVal,T newVal);//用newVal替换集合中的oldVal值

void swap(Listlist,int i,int j);/在指定列表的指定位置处交换元素

3、排序

void shuffle(List<?> list);//使用默认随机源对list集合中的元素进行随机排序

void sort(List<T> list);//根据自然顺序对list集合中的元素进行排序

void sort(List<T> list,Comparator<? super T> c);//根据指定比较器c的排序方式对list集合进行排序

4、反转

reverse(List<?> list);//反转list集合中元素的顺序

Comparator reverseOrder();//返回一个比较器,强行逆转了实现Comparable接口的对象的自然顺序

Comparator reverseOrder(Comparator<T> cmp);//返回一个比较器,强行逆转了指定比较器的顺序

5、同步的集合

List<T>synchronizedList(List<T> list);//返回支持的同步(线程安全的)List集合

Map<K,V>synchronizedList(Map<K,V> m);//返回支持的同步(线程安全的)Map集合

三、Collections和Collectio的区别

Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。

它有两个常用的子接口:

List:对元素都有定义索引。有序的。可以重复元素。

Set:不可以重复元素。无序

Collections是集合框架中的一个工具类。该类中的方法都是静态的。提供的方法中有可以对list集合进行排序,二分查找等方法

通常常用的集合都是线程不安全的。因为要提高效率。如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。

练习:

/*
使用Collections中的fill对list集合中的部分元素替换成指定元素。
思路:
	1、将List集合中要替换的部分元素取出,并存入另一个集合。
	2、将原集合中要替换的元素移除。
	3、用fill方法将要替换的元素进行替换。
	4、将取出的部分增加进集合。
*/
import java.util.*;

class  FillTest
{
	public static void main(String[] args) 
	{
		List<String> list = new ArrayList<String>();

		list.add("abc");
		list.add("ab");
		list.add("abcd");
		list.add("a");
		list.add("abcde");

		try
		{
			fillSome(list,1,5,"heima");
		}
		catch (InputException e)
		{
			System.out.println(e.toString());
		}
		System.out.println(list);
	}

	//替换部分元素方法
	public static void fillSome(List<String> list,int start,int end,String s)throws InputException
	{
		if(start>=end)
			throw new InputException("没有要替换的元素");//如果输入的值小于或等于start,则抛出异常
		
		//定义一个新集合
		List<String> li = new ArrayList<String>();

		//因为每移除一次,后面的元素就会补上,所以这里用y来控制次数
		for (int x=start,y=start;y<end;y++)
		{
			li.add(list.get(x));//将需要替换的元素增加到新集合
			list.remove(x);//移除需要替换的元素
		}
		Collections.fill(li,s);//替换成需要的元素s
		
		list.addAll(start,li);//将替换的部分增加进原集合
	
	}
}
//自定义异常
class InputException extends Exception
{
	InputException(String message)
	{
		super(message);
	}
}

第三讲   Arrays
一、概述
Arrays是用于操作数组的工具类。里边的方法也全是静态的
把数组变成List集合的好处:可以使用集合的思想和方法来操作数组中的元素。如:contains,get,indexOf,subList等方法。

二、常见方法

1、Lsit<T> asList(T... a);//将数组转换为集合

注意:

a、将数组转换成集合,不可使用集合的增删方法,因为数组的长度是固定的。如果进行增删操作,则会产生UnsupportedOperationException的编译异常。

b、如果数组中的元素都是对象,则变成集合时,数组中的元素就直接转为集合中的元素。

c、如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。

2、binarySearch():二分查找方法,fill():替换方法,sort():排序方法等

特点:可对数组元素进行相应操作,可以接受除boolean之外的其他各种基本数据类型及有序的引用类型数组的参数,且还可以对指定元素的范围,并可根据指定比较器进

行相应的操作。

如:sort(T[]a,Comparator<? super T> c)

fill(int[]a,int from,int to)等

3、String toString();//可以接收各种数组类型参数,并返回指定数组内容的字符串表现形式。

示例:

import java.util.*;

class ArraysDemo 
{
	public static void main(String[] args) 
	{
		//int[] arr = {2,3,4};
		//System.out.println(Arrays.toString(arr));//转换为字符串形式

		String[] arr = {"abc","dd","ffff"};

		List<String> list = Arrays.asList(arr);
		sop("contains:"+list.contains("dd"));//判断是否存在"dd"这个元素
		//list.add("qq");

		sop(list);

		//int[] nums = {2,3,4};
		Integer[] nums = {2,3,4};

		List<Integer> list1 = Arrays.asList(nums);
		sop(list1);
	}
	public static boolean myContains(String[] arr,String key)
	{
		for(int x=0;x<arr.length;x++)
		{
			if(arr[x].equals(key))
				return true;
		}
		return false;
	}
	//打印方法
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
三、集合变数组

Collection接口中的toArray方法。

 <T> T[]toArray(T[] a);将集合变为指定类型的数组。

1、指定类型的数组到底要定义多长呢?

当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组。长度为集合的size。

当指定类型的数组长度大于了集合的size,就不会新创建了数组。而是使用传递进来的数组。

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

2、为什么要将集合变数组?

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

示例:

import java.util.*;
class CollectionToArray 
{
	public static void main(String[] args) 
	{
		ArrayList<String> list = new ArrayList<String>();
		list.add("tom01");
		list.add("tom02");
		list.add("tom03");
		//将集合变为String数组
		String[] arr = list.toArray(new String[list.size()]);
		sop(Arrays.toString(arr));//利用Arrays操作数组的方法
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}


第四讲   扩展知识---1.5版本新特性
一、高级for循环
1、格式
for(数据类型 变量名 : 被遍历的集合(Collection)或者数组){}
2、说明
a、对集合进行遍历。只能获取集合元素。但是不能对集合进行操作。
b、迭代器除了遍历,还可以进行remove集合中元素的动作。如果是用ListIterator,还可以在遍历过程中对集合进行增删改查的动作。
3、传统for和高级for的区别

高级for有一个局限性。必须有被遍历的目标(集合或数组)

传统for遍历数组时有索引。

建议在遍历数组的时候,还是希望是用传统for。因为传统for可以定义标。

示例:

import java.util.*;

class ForEachDemo 
{
	public static void main(String[] args) 
	{

		//定义一个ArrayList集合
		ArrayList<String> al = new ArrayList<String>();

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


		for(String s : al)
		{
			//s = "kk";
			System.out.println(s);
		}

		System.out.println(al);
		
		//传统for与高级for遍历数组
		int[] arr = {3,5,1};

		for(int x=0; x<arr.length; x++)
		{
			System.out.println(arr[x]);
		}
		for(int i : arr)
		{
			System.out.println("i:"+i);
		}

		//定义一个HashMap集合
		HashMap<Integer,String> hm = new HashMap<Integer,String>();

		hm.put(1,"a");
		hm.put(2,"b");
		hm.put(3,"c");
		//keySet取出方式的高级for遍历
		Set<Integer> keySet = hm.keySet();
		for(Integer i : keySet)
		{
			System.out.println(i+"::"+hm.get(i));
		}
		//entrySet取出方式的高级for遍历
		for(Map.Entry<Integer,String> me : hm.entrySet())
		{
			System.out.println(me.getKey()+"------"+me.getValue());
		}
	}
}


二、方法的可变参数

如果一个方法在参数列表中传入多个参数,个数不确定,那么每次要复写该方法。这时可以用数组作为形式参数,但是传入时,每次都要一个数组对象,作为实际参数。在

JDK1.5版本之后,就提供了一个新特性:可变参数。

可变参数其实就是上一种数组参数的简写形式。不用每一次都手动的建立数组对象。只要将要操作的元素作为参数传递即可。隐式将这些参数封装成了数组。

注意:在使用时,可变参数一定要定义在参数列表最后面。

示例:

class ParamMethodDemo 
{
	public static void main(String[] args) 
	{
		show("haha",2,3,4,5,6);	
	}
	public static void show(String str,int...arr)
	{
		System.out.println(arr.length);
	}
	
	public static void show(int a,int b)
	{
		System.out.println(a+","+b);
	}
}

三、静态导入

1、写法

import static  java.util.Arrays.*;//导入的是Arrays这个类中的所有静态成员。

import static  java.lang.System.*;//导入了System类中所有静态成员。

没加static导入的是类,加上static导入的是某一类中所有的静态成员。这样写在调用该类的静态方法时可以不用再写类名。如:Arra.sort(数组);就可以直接写sort(数组)。

2、注意

当导入的两个类中有同名成员时,需要在成员前加上相应的类名。

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

示例:

import static  java.util.Arrays.*;//导入的是Arrays这个类中的所有静态成员。

import static  java.lang.System.*;//导入了System类中所有静态成员。

class  StaticImport //extends Object  当没有指定继承时,所有类默认继承Object
{
	public static void main(String[] args) 
	{

		out.println("haha");//打印输出时可以直接省略数学System
		int[] arr = {3,1,5};

		sort(arr);//使用Arra工具类的方法sort时就可以省略书写Array
		int index = binarySearch(arr,1);
		//因为toString方法都具备,为了区分,必须写具体调用者
		out.println(Arrays.toString(arr));
		System.out.println("Index="+index);

	}
}


------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值