集合高级特性
在前面我们介绍了数组的工具类:Arrays,本节我们开始介绍Collections的工具类
特点:
1 位于java.util.Collections(所以必须导包),所提供的均是静态方法(不需要创建实例对象)
2 一部分专门操纵List类型集合,另个一部分操纵所有的Collections类型或Map类型
注意事项:看API文档时,必须了解相关方法的参数和返回值类型
常用成员方法介绍
public static <T> void sort(List<T> list):排序,默认按照自然顺序
public static <T> int binarySearch(List<?> list,T key):二分查找
public static <T> T max(Collection<?> coll):获取最大值
public static void reverse(List<?> list):反转
public static void shuffle(List<?> list):随机置换
说明:对这些方法的由来感兴趣的话可以看一看底层源码----有助于理解其包装过程
实例1
package demo;
import java.util.ArrayList;
import java.util.Collections;
/**
* @author Orange
* @version 1.8
*/
public class Demo06 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();//默认排序,实现Comparable接口
list.add(3);
list.add(-5);
list.add(1);
list.add(0);
list.add(10);
Collections.sort(list); //排序
System.out.println(list);
int s = Collections.binarySearch(list, 1);//二分查找
System.out.println(s);
Collections.reverse(list); //翻转
System.out.println(list);
Collections.shuffle(list); //随机置换
System.out.println(list);
}
}
实例2
需求:模拟斗地主的洗牌和发牌,牌没有排序
分析:
(1)首先得有容器存储牌,然后生成54张牌
(2)新牌总得洗洗吧!老规则先切牌,再洗两次牌
(3)开始发牌,如何发牌呢?----面向过程的思维
(4)发完牌总得看看手里面的牌,才能决定是否叫地主
package demo;
import java.util.ArrayList;
import java.util.Collections;
/**
* @author Orange
* @version 1.8
*/
public class Demo7 {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<String>();
//买牌---装牌
String[] st={"♠","♥","♦","♣"};//四种花色,静态初始化
String[] stNu={"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
for(int i=0;i<st.length;i++){
for(int j=0;j<stNu.length;j++){
arrayList.add(st[i]+stNu[j]);//将牌存储到牌盒种,"+"是不是太low了,换成contact
}
}
arrayList.add("☀");//大王
arrayList.add("☾");//小王
System.out.println(arrayList);
System.out.println("牌买来了,买牌不容易呀!!!");
for(int i=0;i<2;i++){
Collections.shuffle(arrayList);//洗牌---三次:一人一次
}
System.out.println(arrayList.size());
//发牌前---发给三个人---三个斗地主----每个人的牌是一堆,三个容器接受各自的牌
ArrayList<String> kangKang = new ArrayList<String>();
ArrayList<String> jane = new ArrayList<String>();
ArrayList<String> tony = new ArrayList<String>();
ArrayList<String> cards = new ArrayList<String>();
//正式发牌
for(int i=0;i<arrayList.size()-1;i++){
if(i>arrayList.size()-5){
cards.add(arrayList.get(i));
}else if(i%3==0){
kangKang.add(arrayList.get(i));
}else if(i%3==1){
jane.add(arrayList.get(i));
}else{
tony.add(arrayList.get(i));
}
//注意:if --else if特点:一旦匹配,下面就不再执行了
}
//看牌吧!!!
System.out.println(kangKang);
System.out.println(jane);
System.out.println(tony);
System.out.println(cards);
}
}
说明:牌全是用ArrayList进行储存
升级:我是初学者,有点懒不想自己插牌,你给我按照大小自动生成牌,且按照花色"♠","♥","♦","♣"排列分析:显然现在是要进行排序的,说起排序你可能会想到用TreeMap的有参和无参构造方法实现自然排序和客户端排序;由于TreeMap是对键对象进行排序的,我们可以将新牌设定一个顺序,也即采用键值对的形式,如下所示(图的来源来自网上,有一定错误):
注意一点:与上面练习的的区别就是要进行排序了,先按照大小,后按照花色进行排列,每一张索引对应一张牌。在这个过程中,洗牌的话洗的是索引(将索引单独放到一个ArrayList容器中),给每个人发的也是索引,每个人接受牌的索引所储存的容器也是TreeMap,这样就保证了每个人得到牌的索引已经按照大小和花色进行排列,所以只需要按照牌的索引找牌顺序输出即可
实例2
package demo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.TreeSet;
/**
* @author Orange
* @version 1.8
*/
public class Demo8 {
public static void main(String[] args) {
//牌盒
HashMap<Integer, String> tm = new HashMap<Integer,String>();
//放牌
String[] color={"♠","♥","♦","♣"};//四种花色,静态初始化
String[] num={"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
int index=0;//每张牌的索引
ArrayList<Integer> al = new ArrayList<Integer>();//存储牌的索引
//用增强for循环代替普通for循环---花色
for(String st:num){
for(String str:color){
tm.put(index,st.concat(str));//将牌存储到牌盒种
al.add(index);
index++;
}
}
al.add(++index);
al.add(++index);
/**
* 错误的做法:集合的元素与上一次元素已经不一样了
* 这次:0-----梅花1
* 0-----方砖1
* 0-----红桃1
* 0-----黑桃1
* 分析:与上次的玄机在于先添加牌的大小还是先添加颜色
* 思考?按花色排---然后才是大小
*/
tm.put(++index,"☀");//大王
tm.put(++index,"☾");//小王
//System.out.println(tm);//看看牌盒子的牌的索引
//发牌,老一套----保存各自的牌
TreeSet<Integer> kangKang = new TreeSet<>();
TreeSet<Integer> jane = new TreeSet<>();
TreeSet<Integer> linDa = new TreeSet<>();
TreeSet<Integer> cards = new TreeSet<>();
//洗牌--洗的是索引
for(int i=0;i<2;i++){
Collections.shuffle(al);//洗牌---三次
}
System.out.println(al);//洗好后的牌索引
//发牌---54张牌,其中3张底牌
for(int i=0;i<tm.size();i++){
if(i>tm.size()-4){//三张底牌
cards.add(al.get(i));//得到牌的索引
}else if(i%3==0){
kangKang.add(al.get(i));
}else if(i%3==1){
jane.add(al.get(i));
}else{
linDa.add(al.get(i));
}
}
//得到牌的索引---可以找到牌,将牌添加到底牌中
/*
System.out.println(kangKang);
System.out.println(jane);
System.out.println(linDa);
System.out.println(cards);
说明:输出结果主要说明牌的索引已经自动排序了
*/
//按照花色进行排列,按理说底牌不用排序(思考下怎么处理?)
method("kangKang",tm,kangKang);
method("jane",tm,jane);
method("linDa",tm,linDa);
method("cards",tm,cards);
//如果是按花色呢?集合不变
}
/**
* @param tm
* @param kangKang
* 按照花色进行排列---"♠","♥","♦","♣"
*/
private static void method(String s,HashMap<Integer, String> tm, TreeSet<Integer> name) {
System.out.println(s+"的牌:");
for(Integer in:name){
String string = tm.get(in);
System.out.print(string+" ");
}
System.out.println();
}
}
数组和集合的互换---联系
首先回顾集合与数组的区别
(1)把集合转化为数组
查看API文档的描述:
注意:这个方法的参数是用了可变的参数(jdk5后的特性),而这里可变的参数可以写不确定个数的参数,也可以直接用一个数组替代。记住,如果参数是数组,只能是一个数组,不可以是多个;如果是多个的话,前面就应该换成List<String[]>,里面的String必须换String数组才行。
实例3
package demo;
import java.util.Arrays;
import java.util.List;
/**
* @author Orange
* @version 1.8
*/
public class ArrayToCollections {
//数组转化成集合
public static void main(String[] args) {
Integer[] demo=new Integer[5];
demo[0]=1;
demo[1]=2;
demo[2]=3;
demo[3]=4;
demo[4]=5;
List<Integer> list = Arrays.asList(demo);//数组中的Integer元素直接转化成list集合中的元素,Integer是一个引用类型
System.out.println(list);
}
}
实例4
package demo;
import java.util.Arrays;
import java.util.List;
/**
* @author Orange
* @version 1.8
*/
public class ArrayToCollections {
//多个数组的形式
public static void main(String[] args) {
int[] demo1=new int[5];
demo1[0]=1;
demo1[1]=2;
demo1[2]=3;
demo1[3]=4;
demo1[4]=5;
List<int[]> asList2 = Arrays.asList(demo1);//注意与上述的区别,int[]是一个引用类型
for(int[] s:asList2){//遍历集合中的元素
for(int s1:s){
System.out.print(s1+" ");
}
}
System.out.println();
}
}
思考:分析实例3与实例4的原因?明确一点集合只可以储存引用类型实例5
package demo;
import java.util.Arrays;
import java.util.List;
/**
* @author Orange
* @version 1.8
*/
public class ArrayToCollections {
//多个数组的形式
public static void main(String[] args) {
int[] demo1=new int[5];
demo1[0]=1;
demo1[1]=2;
demo1[2]=3;
demo1[3]=4;
demo1[4]=5;
int[] demo2=new int[5];
demo2[0]=6;
demo2[1]=7;
demo2[2]=8;
demo2[3]=9;
demo2[4]=10;
//多个数组,可变参数的形式
List<int[]> asList = Arrays.asList(demo1,demo2);//自动装箱
for(int[] s:asList){//List集合储存的是引用类型---int[]
for(int s1:s) {
System.out.print(s1+" ");
}
System.out.println();
}
/**
* 刷新了认识:
* foreach可以遍历数组(基本和引用类型)和集合(引用类型)
* asList()方法返回值类型取决于数组中元素的类型
*/
}
}
实例6
package demo;
import java.util.Arrays;
import java.util.List;
/**
* @author Orange
* @version 1.8
*/
public class ArrayToCollections {
// 多个数组的形式
public static void main(String[] args) {
String[] demo1 = new String[5];
demo1[0] = "1";
demo1[1] = "2";
demo1[2] = "3";
demo1[3] = "4";
demo1[4] = "5";
String[] demo2 = new String[5];
demo2[0] = "6";
demo2[1] = "7";
demo2[2] = "8";
demo2[3] = "9";
demo2[4] = "10";
// 多个数组,可变参数的形式
List<String> asList2 = Arrays.asList(demo1); // 参数单个数组
for (String s : asList2) {
System.out.print(s+" ");
}
System.out.println();
List<String[]> asList = Arrays.asList(demo1, demo2);// 参数多个数组
for (String[] s : asList) {
for (String s1 : s) {
System.out.print(s1 + " ");
}
System.out.println();
}
}
}
集合转化为数组
toArray函数有两种形式,一种无参数,一种带参数,注意带参数形式中,要指明数组的大小
方式1 无参的形式
说明:对于此种方法由于返回值类型是Object(表明可以接受任意类型),要还原原始的类型必须向下转型
实例7
package demo;
import java.util.ArrayList;
/**
* @author Orange
* @version 1.8
*/
public class CollectionToArray {
public static void main(String[] args) {
ArrayList<Integer> arrLi = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
arrLi.add(i);
}
//方式1
Object[] array = arrLi.toArray();
for(int i=0;i<array.length;i++){
Integer inte=(Integer)array[i];
/**
* 说明:
* (1)数组存储的是Object类型
* (2)其实将Integer向上转型为Object类型
*/
System.out.print(inte+" ");
}
}
}
方式2 有参的形式
实例8
package demo;
import java.util.ArrayList;
/**
* @author Orange
* @version 1.8
*/
public class CollectionToArray1 {
public static void main(String[] args) {
ArrayList<Integer> arrLi = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
arrLi.add(i);
}
//方式2---不存在转型问题,但必须明确数组存储的类型
//在转换成数组时,在参数中已经创建出了接受集合的数组
//注意:集合的存储类型必须与数组的存储类型相匹配
Integer[] array = arrLi.toArray(new Integer[arrLi.size()]);//一定要指明数组的大小
//遍历
for(Integer a:array){
System.out.print(a+" ");
}
}
}
问题:上面asList方法只能转换成list,怎么转换成Set或Queue呢?
解决思路:集合里面所有的具体类的构造方法都有一个方法的参数是Collection,所以这里已经有了list了,可以将这个list作为参数,直接再通过构造方法new出来一个其他的集合就可以了。