Java基础——集合框架(四)

集合的工具类

Collections

是专门对集合进行操作的工具类。

比如说排序:

我们知道,List集合是有序的(按照存进去的顺序进行存储),因为他底层数据结构是数组,有角标,里边有索引,所以也可以有重复元素。

现在如果我们想对List集合中的元素进行排序呢?

//Collections工具类的简单演示
import java.util.*;
public class CollectionsDemo {
	public static void main(String[] args) 
	{
		sortDemo();
	}
	public static void sortDemo()
	{
		String s1 = "dgsch";
		String s2 = "aaa";
		String s3 = "zz";
		String s4 = "qq";
		String s5 = "cdfg";
		List<String> list = new ArrayList<String>();
		list.add(s1);
		list.add(s2);
		list.add(s3);
		list.add(s4);
		list.add(s5);
		sop(list);

		//使用工具类进行排序
		Collections.sort(list);
		sop(list);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}

}

运行结果:

Collections进行List集合的排序

结果可以看出,Collections的sort方法可以使List集合中的元素进行排序,排序方式是自然排序。

现在需求变了,我们要按照字符串的长度进行排序。

可以在Collections的sort方法里传入比较器。

//使用Collections的排序方法,但是用自己定义的排序方式
import java.util.*;
//自定义比较器
class StrLenCompartor implements Comparator<String>
{
	public int compare(String s1,String s2)
	{
		int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
		if (num==0)
			return s1.compareTo(s2);
		return num;
	}
}
public class CollectionsDemo {
	public static void main(String[] args) 
	{
		sortDemo();
	}
	public static void sortDemo()
	{
		String s1 = "dgsch";
		String s2 = "aaa";
		String s3 = "zz";
		String s4 = "qq";
		String s5 = "cdfg";
		List<String> list = new ArrayList<String>();
		list.add(s1);
		list.add(s2);
		list.add(s3);
		list.add(s4);
		list.add(s5);
		sop(list);

		//使用工具类进行排序,将自定义比较器作为参数传递进来
		Collections.sort(list,new StrLenCompartor());
		sop(list);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}

}

运行结果为:

自定义方式排序

运行结果可以看出来,集合按照自定义的方式进行排序。

还有一个方法是可以直接获取集合中元素的最大值,Collections.max(T t),这里就不进行演示了。

集合工具类的二分法查找

//Collections的二分法查找
import java.util.*;

public class CollectionsDemo2 {
	public static void main(String[] args) 
	{
		binarySearchDemo();
	}
	public static void binarySearchDemo()
	{
		String s1 = "dgsch";
		String s2 = "aaa";
		String s3 = "zz";
		String s4 = "qq";
		String s5 = "cdfg";
		List<String> list = new ArrayList<String>();
		list.add(s1);
		list.add(s2);
		list.add(s3);
		list.add(s4);
		list.add(s5);
		sop(list);

		Collections.sort(list,new StrLenCompartor());//先对集合中的元素进行排序
		sop(list);
		int index = Collections.binarySearch(list,"aaa");//调用二分法查找的时候要把集合和查找的元素都传进来
		sop("aaa.index="+index);

		int index2 = Collections.binarySearch(list,"aaaa");
		sop("aaaa.index="+index2);


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

}

运行结果为:

使用二分法查找

运行结果可以发现,当要找的元素不存在时,返回的值不是-1,而是-(插入点)-1; 这样的结果在数组的二分法查找中也是这样的。

而且需要注意的是,使用二分法查找的时候,集合中的元素必须是已经排好序的。

那么,要我们自己定义二分法查找元素呢?

//自定义二分法查找
import java.util.*;

public class CollectionsDemo2 {
	public static void main(String[] args) 
	{
		binarySearchDemo2();
	}
	public static void binarySearchDemo2()
	{
		String s1 = "dgsch";
		String s2 = "aaa";
		String s3 = "zz";
		String s4 = "qq";
		String s5 = "cdfg";
		List<String> list = new ArrayList<String>();
		list.add(s1);
		list.add(s2);
		list.add(s3);
		list.add(s4);
		list.add(s5);
		//首先对集合进行排序,记住,在二分查找之前一定要进行排序,而且在自定义的二分法中,排序规则需要一致。
		Collections.sort(list,new StrLenCompartor());
		sop(list);

		int index = halfSearch(list,"aaa",new StrLenCompartor());
		sop(index);


	}
	/*
	public static int halfSearch(List<String> list,String key)
	{
		int max,min,mid;
		max = list.size()-1;
		min = 0;
		while (max>min)
		{
			mid = (max+min)>>1;
			//取出最中间的元素和给定的元素进行比较
			String str = list.get(mid);
			if (str.compareTo(key)>0)//如果集合中的元素不具备比较性,这一步是不可以进行的。
			{
				max = mid-1;
			}
			else if (str.compareTo(key)<0)
			{
				min = mid+1;
			}
			else
			{
				return mid;
			}
		}
		return -min-1;//如果集合中没有指定的元素,返回-min-1,这里的min是指定元素的插入点
	}
	*/
	public static int halfSearch(List<String> list,String key,Comparator<String> cmpt)
	{
		int max,min,mid;
		max = list.size()-1;
		min = 0;
		while (max>min)
		{
			mid = (max+min)>>1;
			String str = list.get(mid);
			//这里不能直接对元素进行比较,所以用到了参数中传进来的比较器
			//直接使用比较器中的compare方法进行比较
			int num = cmpt.compare(str,key);
			if (num>0)
			{
				max = mid-1;
			}
			else if (num<0)
			{
				min = mid+1;
			}
			else
			{
				return mid;
			}
		}
		return -min-1;//如果集合中没有指定的元素,返回-min-1,这里的min是指定元素的插入点
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}

}
//自定义比较器
class StrLenCompartor implements Comparator<String>
{
	public int compare(String s1,String s2)
	{
		int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
		if (num==0)
			return s1.compareTo(s2);
		return num;
	}
}

运行结果为:

自定义二分法查找元素

运行结果可以看出,集合先按照元素长度进行排序,然后按照自定义二分法查表查到元素的角标位置。

注意:在进行二分法查找之前,一定要进行排序,
在以上示例代码中(假设元素自身没有比较性),二分法查找元素使用到了比较器,排序也用到了比较器,两者比较器必须相同。

集合中元素的替换和反转

//集合中元素的替换和反转
import java.util.*;
public class CollectionsDemo3 {
	public static void main(String[] args) 
	{
		String s1 = "dgsch";
		String s2 = "aaa";
		String s3 = "zz";
		String s4 = "qq";
		String s5 = "cdfg";
		List<String> list = new ArrayList<String>();
		list.add(s1);
		list.add(s2);
		list.add(s3);
		list.add(s4);
		list.add(s5);
		sop(list);//[dgsch, aaa, zz, qq, cdfg]

		//将集合中的元素替换成指定的元素
		//fillDemo(list);
		//sop(list);//[qq, qq, qq, qq, qq]
		

		//反转集合中的元素
		//reverseDemo(list);
		//sop(list);//[cdfg, qq, zz, aaa, dgsch]
		

		//用指定的元素,替换集合中指定的元素。
		raplaceAllDemo(list,"aaa","haha");
		sop(list);//[dgsch, haha, zz, qq, cdfg]


	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
	public static void fillDemo(List<String> list)
	{
		Collections.fill(list,"qq");
	}
	public static void reverseDemo(List<String> list)
	{
		Collections.reverse(list);
	}
	public static void raplaceAllDemo(List<String> list,String s,String port)
	{
		Collections.replaceAll(list,s,port);
	}
}

那么看一个练习,将集合中的指定范围的对象,全部替换成指定的对象,

//练习,已知fill方法可以将集合中的所有元素替换成指定的元素
//那么需求是,要将指定范围的元素换成指定的元素
import java.util.*;
public class CollectionsTest {
	public static void main(String[] args) 
	{
		//先创建集合,在集合中添加字符串对象
		String s1 = "dgsch";
		String s2 = "aaa";
		String s3 = "zz";
		String s4 = "qq";
		String s5 = "cdfg";
		List<String> list = new ArrayList<String>();
		list.add(s1);
		list.add(s2);
		list.add(s3);
		list.add(s4);
		list.add(s5);
		
		//定义两个变量
		int start,end;
		start = 1;
		end = 3;
		//用ListIterator方法对集合进行迭代,
		for (Iterator<String> it = list.listIterator();it.hasNext() ; )
		{
			String s = it.next();
			//只要字符串所在的角标符合条件,将该字符串对象替换成另一个对象。
			if (start<=list.indexOf(s) && list.indexOf(s)<=end)
			{
				Collections.replaceAll(list,s,"zzzzzz");
			}
		}
		

		sop(list);


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

运行结果为:

将指定范围的元素换成指定的元素

反转集合中元素的方法——Collections.reverseOrder()

以上的例子中,使用Collections工具类给List集合进行排序,是可以排的,
但是不可以给Set集合进行排序,因为Set集合有自己的排序方法。
现在如果要对Set集合中已经排序的元素进行反转,该怎么办呢?

用自定义比较器的方法

//给Set集合中的元素进行顺序的转换


import java.util.*;
public class CollectionsDemo4 {
	public static void main(String[] args) 
	{
		//先创建集合,在集合中添加字符串对象
		Set<String> set = new TreeSet<String>(new MyReverse());
		set.add(new String("aaaaa"));
		set.add(new String("bdfg"));
		set.add(new String("vdfeggdc"));
		set.add(new String("cc"));
		set.add(new String("q"));

		//打印集合中的元素
		//sop(set);
		//[aaaaa, bdfg, cc, q, vdfeggdc]*********原始顺序是按照自然顺序进行排序的。

		sop("逆转后的集合顺序为:"+set);
		
	}
	
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

//按照之前学过的传自己比较器的方式,也可以进行顺序的逆转。
//只要把s1和s2的比较顺序调换就行了。

class MyReverse implements Comparator<String>
{
	public int compare(String s1,String s2)
	{
		int num = s2.compareTo(s1);
		return num; 
	}
}

运行结果:

用自定义比较器的方式实现元素顺序的逆转

方法二: 用集合工具类的方法reverseOrder()

反转集合元素的方法概要

//给Set集合中的元素进行顺序的转换


import java.util.*;
public class CollectionsDemo4 {
	public static void main(String[] args) 
	{
		//先创建集合,在集合中添加字符串对象(在创建集合的时候就开始调用工具类的方法)
		Set<String> set = new TreeSet<String>(Collections.reverseOrder());
		//Collections.reverseOrder()能强行逆转集合中的自然比较方法

		set.add(new String("aaaaa"));
		set.add(new String("bdfg"));
		set.add(new String("vdfeggdc"));
		set.add(new String("cc"));
		set.add(new String("q"));

		//打印集合中的元素
		//sop(set);
		//[aaaaa, bdfg, cc, q, vdfeggdc]*********原始顺序是按照自然顺序进行排序的。

		sop("逆转后的集合顺序为:"+set);
		
	}
	
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

运行结果:

使用reverseOrder方法进行集合顺序的反转

但是如果集合不是自然排序,而是用自己定义的比较器进行排序的呢?

//给Set集合中的元素进行顺序的转换


import java.util.*;
public class CollectionsDemo4 {
	public static void main(String[] args) 
	{
		//先创建集合,在集合中添加字符串对象(在创建集合的时候就开始调用工具类的方法,里边可以传入自定义的比较器)
		Set<String> set = new TreeSet<String>(Collections.reverseOrder(new StrLenCompartor()));
		//Collections.reverseOrder(new 比较器)可以逆转比较器中的排序方式

		set.add(new String("aaaaa"));
		set.add(new String("bdfg"));
		set.add(new String("vdfeggdc"));
		set.add(new String("cc"));
		set.add(new String("q"));

		//打印集合中的元素
		//sop(set);
		//[q, cc, bdfg, aaaaa, vdfeggdc]*********只使用比较器的结果是按照长度顺序进行排序的。

		sop("逆转后的集合顺序为:"+set);

		//[vdfeggdc, aaaaa, bdfg, cc, q]**********使用工具类方法,传入比较器的结果是按照长度顺序反转过来的顺序排列的。
		
	}
	
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
//自定义比较器,按照长度由短到长排序
class StrLenCompartor implements Comparator<String>
{
	public int compare(String s1,String s2)
	{
		int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
		if (num==0)
			return s1.compareTo(s2);
		return num;
	}
}

集合中线程安全的问题

我们知道很多升级后的集合存数对象的时候,为了提高效率,都用的是线程不同步的,
那么,如果真的遇到了多线程操作集合的问题呢?
java中的集合工具类(Collections)中有专门提供的线程安全的集合:

线程安全的集合

该方法的牛逼之处在于:你给我一个线程不安全的集合,我返回一个线程安全的集合。

集合工具类中的其他方法:

Collections.swap(List list,int i,int j)将List集合中的指定两个元素交换位置。
Collections.shuffle(List list)将集合中的元素排序方式打乱,每次运行结果都不一样,就像是洗牌的一样。


//shuffle方法的演示
import java.util.*;
public class CollectionsDemo5 {
	public static void main(String[] args) 
	{
		String s1 = "dgsch";
		String s2 = "aaa";
		String s3 = "zz";
		String s4 = "qq";
		String s5 = "cdfg";
		List<String> list = new ArrayList<String>();
		list.add(s1);
		list.add(s2);
		list.add(s3);
		list.add(s4);
		list.add(s5);
		sop(list);

		Collections.shuffle(list);//调用shuffle方法,使集合中的元素顺序打乱

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

运行结果为:

shuffle方法演示

Arrays工具类

专门用来操作数组的工具类
里边全都是静态方法。

Arrays.toString()直接打印数组中的内容:

//Arrays工具类的基本方法演示
import java.util.*;
public class ArraysDemo {
	public static void main(String[] args) 
	{
		int[] arr = {3,6,1};
		sop(Arrays.toString(arr));
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

toString方法演示

List list Arrays.asList(arr):传进来一个数组,返回一个List集合

//Arrays工具类的基本方法演示
import java.util.*;
public class ArraysDemo {
	public static void main(String[] args) 
	{
		String[] strs = {"haha","hehe","nhao","llala","hiahia"};
		//将字符串数组变成List集合
		List<String> list = Arrays.asList(strs);
		sop(list);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

asList方法演示

把数组变成集合有什么好处呢?

可以使用集合的思想和方法来操作数组中的元素。
注意:将数组变成集合,不可以使用集合的增删方法,因为数组的长度是固定的。
contains()
get()
indexOf()
subList()这些方法都可以用。
如果进行增删操作的话会发生异常:UnsupportedOperationException(不支持操作异常)

sop(list.contains("haha"));
//看返回的真假来判断集合中是否存在这样的元素,如果是数组的话需要遍历整个数组。

上边代码证实,存入String类型的数据,将数组变为集合的时候,打印出来集合的元素也是字符串,但是换成int类型的数组的时候打印出来的就是哈希值。

//Arrays工具类的基本方法演示
import java.util.*;
public class ArraysDemo {
	public static void main(String[] args) 
	{
		int[] arr = {3,5,78,1,5,6};
		//将字符串数组变成List集合
		List list = Arrays.asList(arr);
		//如果要写泛型的话应该写成这个样子。
		//List<int[]> list = Arrays.asList(arr);
		sop(list);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

基本数据类型的数组变成集合

如果想要打印出来的值不是哈希值得话,要这样写

//Arrays工具类的基本方法演示
import java.util.*;
public class ArraysDemo {
	public static void main(String[] args) 
	{
		Integer[] arr = {3,5,78,1,5,6};
		//将字符串数组变成List集合
		List<Integer> list = Arrays.asList(arr);
		sop(list);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

基本数据类型转换成List集合

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

集合变数组
使用Collection接口中的toArray方法。

//将集合转变成数组
//使用Collection接口中的toArray方法
import java.util.*;
public class CollectionToArray {
	public static void main(String[] args) 
	{
		List<String> list = new ArrayList<String>();
		list.add(new String("nihao"));
		list.add(new String("shijie"));
		list.add(new String("hello"));
		list.add(new String("world"));

		//开始转变,参数需要一个数组

		String[] strs = list.toArray(new String[4]);

		//将数组中的元素直接打印出来,可以用到Arrays中的toString方法

		System.out.println(Arrays.toString(strs));
	} 
}

集合转换成数组

那么问题也就来了,

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

2,为什么要将集合转变成数组?
为了限定对元素的操作。
数组有固定的长度,一旦确定就不可以再进行增删操作,

增强for循环

格式:

for(数据类型 变量名 : 被便利的集合(Collection)或者数组)
{
}

jdk1.5新特性

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

迭代器除了遍历,还可以进行remove集合元素的动作。
如果是用ListIterator,还可以再遍历过程中对集合进行增删改查的动作。

传统for和高级for有什么区别呢?
高级for有一个局限性,必须有被遍历的目标。
比如说打印100次hello world,还是传统for好使。

简单演示一下增强for循环的用法:

//增强for循环演示
import java.util.*;
public class ForEachDemo {
	public static void main(String[] args) 
	{
		List<String> list = new ArrayList<String>();
		list.add(new String("nihao"));
		list.add(new String("shijie"));
		list.add(new String("hello"));
		list.add(new String("world"));

		//数据类型  变量名   :  被遍历的目标
		for (String s: list)
		{
			System.out.println(s);
		}
	}
}

增强for循环简单演示

增强for循环的应用:

//增强for循环的应用
import java.util.*;
public class ForEachTest {
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
	public static void main(String[] args) 
	{
		//增强for循环遍历数组
		sop("增强for循环遍历数组");
		int[] arr = {2,5,3,8,4};
		for(int i:arr)
		{
			sop("i= "+i);
		}

		//用增强for循环遍历set集合中的元素 
		sop("增强for循环遍历set集合中的元素");
		Set<String> set = new HashSet<String>();
		set.add(new String("abc"));
		set.add(new String("dsaf"));
		set.add(new String("fdfd"));
		set.add(new String("ccc"));
		for(String s: set)
		{
			sop("s....."+s);
		}

		//用增强for循环遍历map集合中的元素
		
		TreeMap<Integer,String> tm = new TreeMap<Integer,String>();
		tm.put(1,"a");
		tm.put(2,"b");
		tm.put(3,"c");
		tm.put(4,"d");

		//方法一,使用keySet方法
		sop("用增强for循环遍历map集合中的元素(keySet方法)");
		Set<Integer> keySet = tm.keySet();
		for(Integer i:keySet)
		{
			System.out.println(i+"--------"+tm.get(i));
		}

		//方法二,使用entrySet方法
		sop("用增强for循环遍历map集合中的元素(entrySet方法)");
		Set<Map.Entry<Integer,String>> entrySet = tm.entrySet();
		for(Map.Entry<Integer,String> me :entrySet)
		{
			System.out.println(me.getKey()+"*******"+me.getValue());
		}
	}
}

运行结果为:

增强for循环的更多应用

可变参数

jdk1.5出现的心特性
使用时注意:可变参数一定要定义在参数列表的最后边。

考虑这样一种情况:

public void show(int a,int b)
{
	System.out.println(a+","+b);
}

类似这样的show方法的功能,如果我需要打印三个参数的值呢?四个五个呢,创建多个重载方法是可以的,但是那样写太多了。
我们可以创建一个数组:

public void show(int[] arr)
{
	System.out.println(Arrays.toString(arr));
}

这样也可以,但是不足之处在于,每次调用该方法都要定义一个数组,不太优。

可变参数方法:只要多个参数类型是同一种(int),可以让多个参数自动装箱封装进一个数组(arr)中去。

如果参数中需要其他的参数,记住可变参数一定要定义在参数列表的最后边。

//可变参数演示
public class ParamMethodDemo {
	public static void main(String[] args) 
	{
		show(2,5,7,5,8,2);
		show("nihao",4,7,4,3,2,9);
	}
	public static void show(int...arr)//可变的参数数量,都会封装进数组中去
	//格式:参数类型...数组名称
	{
		System.out.println(arr.length);
	}

	//如果参数中需要其他类型的参数,将其他类型的参数放在最前边,把可变参数放在最后边
	public static void show(String s,int...arr)
	{
		System.out.println(s+arr.length);
	}
}

静态导入

jdk1.5新特性。
使用集合工具类和数组工具类的时候,每次都要写Collections和Arrays,用很多次就写很多次。

一个一劳永逸的方法就是,静态导入,
因为Collections和Arrays里边都是静态方法,导入类之后,就可以直接调用类中的成员方法了。

具体导入方法和使用实例如下:


import java.util.*;
//在这里静态导入
import static java.util.Arrays.*;//将Arrays 中的静态的成员导入进来
public class StaticImportDemo {
	public static void main(String[] args) 
	{
		int[] arr = {3,5,8,5,3,6};
		//给数组进行排序:
		sort(arr);

		//打印数组中的元素
		System.out.println(Arrays.toString(arr));

		//使用二分法查找元素
		int index = binarySearch(arr,8);
		System.out.println(index);
	}
}

运行结果:
静态导入类

注意:在以上代码中,打印数组中的元素一行中,必须写Arrays.toString(),
因为Arrays类继承的是Object类,而Object里边也有toString方法,
这里认为他是使用的Object中的toString方法,
所以必须在方法前指明类名。

记住:
当雷鸣重复时,需要指定具体的包名。
当方法重名时,需要指定具体的对象或者类。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值