黑马程序员----集合框架工具类,几个新特性

本文深入解析Java集合框架的使用方法与新特性,包括排序、查找、替换、数组转换及增强for循环、可变参数、静态导入等。同时,提供手写实现部分Collections方法的示例代码。

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

1.Collections

这是一个用来操作集合的工具类,既然是个工具类,也就是说它没有特有属性,也就是说该类不会创建对象,而是使用其内部的静态方法来对集合进行排序,求最值,查找等复杂操作,调用该类方法可以为我们省去大量的自己写方法的时间。

常用方法:

sort方法:对集合List进行排序,两个方式:1.按照集合元素自己的自然顺序,2.传入比较器
max方法:取出List集合中的最大值同样有两种方式:1.按照自然顺序,2.传入比较器
binarySearch方法:使用二分法对List进行元素查找,需要List有序。
fill方法:使用参数替换List中所有元素。
replaceAll方法:使用新值替换所有旧值。
reverse方法:反转List中所有元素。
reverseOrder方法:返回一个逆转了的比较器或者元素的自然顺序。
synchronizedList,synchronizedMap,synchronizedSet,传入不同步的集合返回同步的集合。
内部实现:例如synchronizedList返回一个SynchronizedList对象,该对象实现List接口,该对象所在类内部实现所有List的方法
方法的实现方式是:1.使用同步代码块包起来。2.调用传入的List对象的对应方法
例如SynchronizedList的add方法如下
add(E)
{
synchronized(mutex)
{
list.add();
}
}

shuffle方法:对集合中元素进行随机排放。

2.Arrays

对数组操作的封装类,内部包含的都是跟数组有关的操作,使用该类可以大大减少我们的工作量。

常用方法:

toString方法:
asList方法:
*将数组转为list集合
好处使用集合的思想操作数组
注意将数组变成集合,不可以使用集合的增删方法,因为数组长度不可变
特点如果数组中的元素是引用数据类型,那么就是将数组中的元素作为集合中的元素,如果数组中的元素是基本数据类型,
那么就会将数组本身作为集合中的元素
*扩展:将集合转为数组。
Collection接口的toArray方法。

toArray方法需要传入一个指定类型的数组参数,其中需要指定数组长度:
1.指定的长度小于集合中元素,那么就会开辟新的空间。
2.指定长度大于集合中元素个数,那么就会自动添加null到数组中后几个。
因此指定长度最好就等于集合中元素个数
好处:限定对集合元素的操作。例如我们对外传递只传递数组格式,那么外界就不能添加删除了。


3.Collections,Arrays常用方法测试:

/*
	集合框架工具类:
	1.Collections:
		测试其方法的使用;sort,max,binarySearch,fill(全部替换,实现部分替换),replaceAll,reverse,reverseOrder,shuffle,synchronizedList,synchronizedMap,

synchronizedSet。
		
	2.Arrays:
		数组转集合,用处,方法,注意事项
			Arrays.adList方法,返回一个指定类型的list集合
			注意:不能改变集合的长度,因此一般不能添加和删除
		集合转数组,用处,方法,注意事项
	
*/
package com.helong.test;
import java.util.*;
class MyComp implements Comparator<String>
{
	public int compare(String s1,String s2)
	{
		if(s1.length()==s2.length())
			return s2.compareTo(s1);
		else return s2.length()-s1.length();
	}
}
class Test 
{
	public static void main(String[] args) 
	{
		List<String> list=new ArrayList<String>();
		list.add("adb");
		list.add("b");
		list.add("accb");
		list.add("baaba");
		sop("原始字符串:"+list);
		//使用集合元素的自然顺序排序
		Collections.sort(list);
		sop("自然顺序排序:"+list);
		//打乱集合中的元素
		Collections.shuffle(list);
		sop("打乱集合:"+list);
		//按照字符串长度排序
		Collections.sort(list,new MyComp());
		sop("按照字符串长度逆序:"+list);
		Collections.shuffle(list);
		//二分查找,必须保证有序
		Collections.sort(list);
		sop("自然排序后字符串:"+list);
		sop("元素所在位置:"+Collections.binarySearch(list,"accd"));
		//对于二分查找有一个知识点:如果找不到,那么返回的是key的插入点位置的负值再减1,例如此处accd的插入点为1,负值就是-1再减1就是-2
		sop("元素所在位置:"+Collections.binarySearch(list,"accb"));
		Collections.replaceAll(list,"b","ee");
		sop("b被eee替换后:"+list);
		Collections.reverse(list);
		sop("反转后:"+list);
		//reverseOrder按照自然元素逆向排序
		Collections.sort(list,Collections.reverseOrder());
		sop("逆向排序:"+list);
		//按照比较器的逆序排序
		Collections.sort(list,Collections.reverseOrder(new MyComp()));
		sop("按照长度逆向排序:"+list);
		//使用fill实现部分替换
		myFill(list,1,2,"hahah");
		//数组转成集合
		String[] strs={"adf","vvsd","qwer","xxxx","sdf"};
		List<String> temp=Arrays.asList(strs);
		sop(temp);
		//不能进行添加删除等会改变数组长度的操作
		//并不是不能使用这些方法,而是当在这些方法内因为添加或者删除而造成长度改变时,会报异常
		//证明:当我们删除一个不存在的元素时,是没有报错的,这说明本质不是add或者remove而是长度被改变
		//temp.add("adfaf");
		//temp.remove("adf");
	

	}
	private static void myFill(List<String> list,int start,int end,String str)
	{
		List<String> head=list.subList(0,start);
		List<String> temp=list.subList(start,end);
		List<String> rear=list.subList(end,list.size());
		Collections.fill(temp,str);
		head.addAll(temp);
		head.addAll(rear);
		sop(head);
	}
	private static  void sop(Object obj)
	{
		System.out.println(obj);
	}
}
运行图:



4.手写实现部分Collections方法

/*
sort,max,binarySearch,fill(全部替换,实现部分替换),
replaceAll,reverse,reverseOrder,shuffle
手写工具类实现上述方法处理ArrayList集合

泛型的使用并不熟练
什么时候该用,怎么正确使用限定达到程序要的效果

不懂哪里没有确定集合元素类型导致了编译期间的注意
*/
package com.helong.test2;
import java.util.*;
class MyCollections
{
	//构造函数私有化,严谨
	private MyCollections(){}
	
	private static <T extends Comparable<? super T>> void arrayToList(ArrayList<T> al,T[] temp)
	{
		for(int i=0;i<temp.length;i++)
			al.add(temp[i]);
	}
	//调用方法时能够使用Comparable类及其子类
	//主要作用是将T和Comparable之间产生关系,使用多态特性
	//<T extends Comparable<? super T>>这句具体的限定关系还不明确
	private static <T extends Comparable<? super T>> void listToArray(Comparable[] temp,ArrayList<T> al)
	{
		for(int i=0;i<temp.length;i++)
		{
			temp[i]=al.get(i);
		}
	}
	//==============================================================================
	public static <T extends Comparable<? super T>> void sort(ArrayList<T> al)
	{
		if(al.size()==0)return ;
		if(!(al.get(0) instanceof Comparable))throw new ClassCastException("元素不具有可比性,无法进行排序操作!");
		//默认从小到大排序
		Comparable[] temp=new Comparable[al.size()];
		listToArray(temp,al);
		for(int i=0;i<temp.length-1;i++)
		{
			int k=i;
			for(int j=i+1;j<temp.length;j++)
			{
				if(temp[j].compareTo(temp[k])<0)
					k=j;
			}
			if(k!=i)
			{
				Comparable t=temp[k];
				temp[k]=temp[i];
				temp[i]=t;
			}
		}
		al.clear();
		arrayToList(al,(T[])temp);
	}
	//重载sort方法,提供比较器进行自定义排序顺序
	public static <T extends Comparable<? super T>> void sort(ArrayList<T> al,Comparator<T> comp)
	{
		if(al.size()==0)return ;
		if(!(al.get(0) instanceof Comparable))throw new ClassCastException("元素不具有可比性,无法进行排序操作!");
		//默认从小到大排序
		Comparable[] temp=new Comparable[al.size()];
		listToArray(temp,al);
		for(int i=0;i<temp.length-1;i++)
		{
			int k=i;
			for(int j=i+1;j<temp.length;j++)
			{
				//此处修改为使用比较器方法比较大小
				//将排序方式改为了从大到小
				if(comp.compare((T)temp[j],(T)temp[k])<0)
					k=j;
			}
			if(k!=i)
			{
				Comparable t=temp[k];
				temp[k]=temp[i];
				temp[i]=t;
			}
		}
		al.clear();
		arrayToList(al,(T[])temp);
	}
	//==============================================================================
	public static <T extends Comparable<? super T>> T max(ArrayList<T> al)
	{
		T max=al.get(0);
		for(int i=1;i<al.size();i++)
		{
			if(al.get(i).compareTo(max)>0)
				max=al.get(i);
		}
		return max;
	}
	//==============================================================================
	//使用二分查找元素位置,如果不存在,返回 : -(插入点)-1
	public static <T extends Comparable<? super T>> int binarySearch(ArrayList<T> al,T key)
	{
		sort(al);
		int insertPoint=0;
		for(int min=0,max=al.size()-1,mid=(min+max)/2;min<=max;mid=(min+max)/2)
		{
			int temp=al.get(mid).compareTo(key);
			if(temp==0)
				return mid;
			else if(temp>0)
				max=mid-1;
			else
				min=mid+1;
			insertPoint=min;
		}
		return -insertPoint-1;
	}
	//==============================================================================
	public static <T> void fill(ArrayList<T> al,T newElement)
	{
		int length=al.size();
		al.clear();
		for(int i=0;i<length;i++)
			al.add(newElement);
	}
	//==============================================================================
	public static <T extends Comparable<? super T>> boolean replaceAll(ArrayList<T> al,T oldElements,T newElement)
	{
		boolean flag=false;
		for(int i=0;i<al.size();i++)
		{
			if(al.get(i).equals(oldElements))
			{
				al.set(i,newElement);
				flag=true;
			}
		}
		return true;
	}
	//==============================================================================
	public static <T> void reverse(ArrayList<T> al)
	{
		if(al.size()<=1)return ;
		for(int i=0;i<al.size()/2;i++)
		{
			T temp=al.get(i);
			al.set(i,al.get(al.size()-1-i));
			al.set(al.size()-1-i,temp);
		}
	}
	//==============================================================================
	//思路:al中的元素随机取出放到数组中,最后将数组的值赋回给al
	public static <T extends Comparable<? super T>> void shuffle(ArrayList<T> al)
	{
		Comparable[] temp=new Comparable[al.size()];
		Random random=new Random();
		for(int i=0;i<temp.length;i++)
		{
			int index=random.nextInt(al.size());
			temp[i]=al.get(index);
			al.remove(index);
		}
		arrayToList(al,(T[])temp);
	}
	//==============================================================================
	//该方法作用是:返回一个比较器,强行逆转了元素按自然顺序排序,比较器提供的排序顺序时与自然顺序相反的
	public static <T extends Comparable<? super T>> Comparator<T> reverseOrder()
	{
		return new Comparator<T>(){//注意此处不要忘了T
			public int compare(T t1,T t2)
			{
				return t2.compareTo(t1);
			}
		};
	}
	//==============================================================================
	//该方法作用:通过传入一个比较器,返回与比较器相反的比较器
	//例如将reverseOrder返回值(从大到小排序)传入该方法,那么就会得到一个从小到大排序的比较器
	public static <T extends Comparable<? super T>> Comparator<T> reverseOrder(Comparator comp)//此处Comparator不能设置泛型类型,不懂为啥?
	{
		return new Comparator<T>(){
			public int compare(T t1,T t2)
			{
				return comp.compare(t2,t1);
			}
		};
	}
}
class Test2 
{
	public static void main(String[] args) 
	{
		ArrayList<Integer> array=new ArrayList<Integer>();
		array.add(12);array.add(8);array.add(5);array.add(8);array.add(11);
		sop(array);

		//测试sort方法
		MyCollections.sort(array);
		sop("排序后的集合:"+array);
		//测试max方法
		sop("当前集合中最大值:"+MyCollections.max(array));
		//测试binarySearch方法
		sop("5在集合中的位置:"+MyCollections.binarySearch(array,5));
		sop("4在集合中的位置:"+MyCollections.binarySearch(array,4));
		sop("9在集合中的位置:"+MyCollections.binarySearch(array,9));
		//测试replaceAll方法
		MyCollections.replaceAll(array,8,24);
		sop("使用24替换8:"+array);
		//测试reverse方法
		MyCollections.reverse(array);
		sop("集合反转:"+array);
		//测试shuffle方法
		MyCollections.shuffle(array);
		sop("随机打乱集合:"+array);
		MyCollections.shuffle(array);
		sop("再次随机打乱集合:"+array);
		//测试reverseOrder(),sort(array,comp)
		MyCollections.sort(array,MyCollections.reverseOrder());
		sop("使用reverseOrder返回的比较器对集合进行排序:"+array);
		//测试reverseOrder(comp),将reverseOrder()的返回值作为参数传给reverseOrder(comp)并返回相反的比较器,
		//此处,也就是从小到大排序方式
		MyCollections.shuffle(array);
		sop("随机打乱集合:"+array);
		MyCollections.sort(array,MyCollections.reverseOrder(MyCollections.reverseOrder()));
		sop("将reverseOrder()返回的比较器作为参数传给reverseOrder(comp)得到一个\n相反的比较器作为参数传给sort进行排序:"+array);
		//测试fill方法
		MyCollections.fill(array,88);
		sop("用88填充集合:"+array);
	}
	private static void sop(Object obj)
	{
		System.out.println(obj);	
	}
}




5.集合框架小结

虽然在使用工具类的时候,没有什么问题,但是当自己去实现这些方法时,遇到了很多问题,其中最明显的就是对泛型的使用存在很多问题,尤其是泛型的高级应用,也就是泛型限定的使用非常不好,很多地方不明白为什么使用向上限定或者向下限定,不过还是写出来了,要在以后的学习中重点掌握这一部分,因为泛型是非常重要且实用的一个特性。它使得写出来的程序即有多态般的灵活性,又有自己的安全性。


6.JDK1.5后几个新特性

增强for循环(简化代码书写):

foreach:被循环对象需要实现Iterable接口。

格式:for(集合数据类型 变量名 : 被遍历的集合或者数组){.....}
底层遍历使用的依然是迭代器。
使用这种方法只能获取元素,不能操作集合。
局限性:必须要有一个遍历的集合或数组
建议:遍历数组时使用传统for,因为传统for有下标,而对于数组来说,下标是很重要的特性
用处:如果只是取出集合数组中的元素,那么考虑使用增强for,毕竟其语法简单

/*
增强for循环
for(集合中数据类型 var : 集合或者数组)
{........}
Java升级:简化书写
对于遍历集合来说,它底层使用的依然是迭代器。
与传统for循环比较:
增强for必须要有一个可以遍历的集合或者数组
建议:在遍历数组时,使用传统for,因为传统for有下标
局限:增强for只能获取元素,不能操作集合。
迭代器:不仅可以获取元素,还能remove
列表迭代器:甚至可以增删改查
*/

package com.helong.foreachdemo;
import java.util.*;
class ForeachDemo 
{
	public static void main(String[] args) 
	{
		ArrayList<String> al =new ArrayList<String>();
		al.add("hl1");
		al.add("hl2");
		al.add("hl3");

		sop("迭代器:");
		for(Iterator<String> it = al.iterator();it.hasNext();)
		{
			sop(it.next());
		}
		sop("传统for:");
		for(int i=0;i<al.size();i++)
		{
			sop(al.get(i));
		}
		sop("增强for:");
		for(String str : al)
		{
			sop(str);
		}

		HashMap<Integer,String> hm=new HashMap<Integer,String>();
		hm.put(1,"ldy1");
		hm.put(2,"ldy2");
		hm.put(3,"ldy3");
		
		sop("keySet迭代器:");
		for(Iterator<Integer> it=hm.keySet().iterator();it.hasNext();)
		{
			Integer temp=it.next();
			sop(temp+":::"+hm.get(temp));
		}

		sop("增强for:");
		for(Integer i : hm.keySet())
		{
			sop(i+"::::"+hm.get(i));
		}

		sop("entrySet迭代器:");
		for(Iterator<Map.Entry<Integer,String>> it=hm.entrySet().iterator();it.hasNext();)
		{
			Map.Entry me=it.next();
			sop(me.getKey()+"--"+me.getValue());	
		}

		sop("增强for:");
		for(Map.Entry<Integer,String> me : hm.entrySet())
		{
			sop(me.getKey()+"---"+me.getValue());
		}
	}
	private static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
运行图:



可变参数(简化代码书写):

取代数组参数的用法,不用每次都建立数组,而是由jvm来自动完成。
定义:show(int... arr)等价于show(int[] arr)
调用:show(1,2,3)等价于 show(new int[]{1,2,3})就是说这一步由jvm来完成
注意:可变参数只能定义在参数列表的最后。
show(int... arr,int i)//错误
show(int... arr,String i)//错误
show(int i,int... arr)//可以

/*
可变参数,JDK1.5新特性
注意:可变参数必须放到参数列表的最后位
*/
package com.helong.paramdemo;
class ParamDemo 
{
	public static void main(String[] args) 
	{
		function(1,2,3);
		function(1,2,3,4,5,6,7);

		//function(1,2,3,"str");
		function("str",1,2,3);
	}
	private static void function(int... arr)
	{
		System.out.println(arr.length);
	}
	private static void function(String str,int... arr)
	{
		System.out.println(arr.length);
	}
}
运行图:


静态导入(简化代码书写):

普通导入:import.....导入的是某个包中的类;
例如 import java.util.*;java的util包中的所有类。
静态导入:import static.....导入的是某个类中的静态成员;
例如 import static java.util.Arrays.*;导入的是Arrays类下的所有静态成员。

//静态导入:导入的是某个类的静态成员
//普通导入:导入的是某个包中的类
package com.helong.staticimportdemo;
import java.util.*;
import static java.util.Arrays.*;
//导入了Arrays类中的静态成员
class StaticImportDemo 
{
	public static void main(String[] args) 
	{
		int[] arr={1,2,3};
		sort(arr);
		System.out.println(Arrays.toString(arr));
	}
}
运行图:

新特性小结:

我们可以看到,这三个新特性的目的都是为了简化代码书写。





------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值