第十二章 Java高级应用---集合框架

一、集合框架概述

JDK提供的集合API位于java.util内

1.1 生活中的容器

1.2 数组的特点与弊端

面向对象语言就是对事物进行对象化,为了对多个对象进行操作,需要将对象进行存储,而之前使用的数组对象存在一定的弊端;

数组的特点:

  1. 数组初始化后,长度就确定了;
  2. 数组中添加的元素是依次紧密排序有序的可重复的
  3. 数组声明的类型,就决定了进行元素初始化时的类型,数组中元素的类型保持与初始化一致
  4. 数组中可存放基本数据类型值,也可以存储引用数据类型的变量;

数组的弊端:

  1. 数组初始化后,长度就不可变,不便于扩展;
  2. 数组中提供的属性和方法少,不便于进行添加、删除、插入、获取元素个数等操作,且效率不高;
  3. 数组存储数据的特点单一,只能存储有序的、可以重复的数据;

Java集合框架中的类可以用于存储多个对象,还可用于保存具有映射关系的关联数组;

1.3 Java集合框架体系

Java集合可分为Collection和Map两大体系(即Java集合 = Collection接口 + Map接口):
在这里插入图片描述

Collection接口

Collection接口:用于存储一个一个的数据,也称为单列数据集合;
在这里插入图片描述
Collection接口实现路线:

  1. Collection接口—List子接口—ArrayList(主要实现类)、LinkedList、Vector实现类
    List子接口:用来存储有序的,可重复的数据(主要用来替换数组,“动态”数组)
    实现类:ArrayList(主要实现类),LinkedList,Vector;

  2. Collection接口—Set子接口—HashSet(主要实现类)、LinkedHashSet、TreeSet实现类
    Set子接口:用来存储无序的,不可重复的数据;
    实现类:HashSet(主要实现类),LinkedHashSet,TreeSet

Map接口

在这里插入图片描述

Map接口用于存储具有映射关系“key-value对”的集合,即一对一对的数据,也称双列数据集合(类似于高中的函数、映射)。
实现类:HashMap(主要实现类)、LinkedHashMap、TreeMap、Hashtable、Properties

1.4 集合的使用场景

在这里插入图片描述

二、Collection接口及方法

  • JDK不提供此接口的任何直接实现,而是提供更具体的子接口;
  • Collection接口是List和Set接口的父接口,该接口里定义的方法既可用于操作Set集合,也可用于操作List集合。

2.1 添加

  1. add(E obj):添加元素对象到当前集合中;
  2. addAll(Collection other):添加other集合中的所有元素对象到当前集合中;
package gather;

import java.util.ArrayList;
import java.util.Collection;

public class TestCollection {
    public static void main(String[] args) {
        TestCollection tc=new TestCollection();
        tc.testAdd();
        System.out.println();
        tc.testAddAll();
    }
//    添加
    public void testAdd(){
        Collection coll=new ArrayList();
        coll.add("小小");
        coll.add("笑笑");
        coll.add("晓晓");
        System.out.println("coll:"+coll);
    }

    public void testAddAll(){
        Collection c1=new ArrayList();
        c1.add(1);
        c1.add(2);
        c1.add(3);
        System.out.println("c1集合元素的个数:"+c1.size());
        System.out.println("c1="+c1);

        Collection c2=new ArrayList();
        c2.add(4);
        c2.add(5);
        c2.add(6);
        System.out.println("c2集合元素个数:"+c2.size());
        System.out.println("c2:"+c2);

        Collection c3=new ArrayList();
        c3.add(7);
        c3.add(8);
        c3.add(9);
        System.out.println("c3:"+c3);

//        add()和addAll()区别
       c1.add(c3);    //添加的是对象
        System.out.println("c1.add(c3):"+c1);  //[1, 2, 3, [7, 8, 9]]
        c1.addAll(c3);  //添加的是对象中的各元素
        System.out.println("c1.addAll(c3):"+c1);  //[1, 2, 3, 7, 8, 9]
    }
}

2.2 判断

  1. int size():获取当前集合中实际存储的元素个数
  2. boolean isEmpty():判断当前集合是否为空集合;
  3. boolean contains(Object obj):判断当前集合中是否存在一个与obj对象equals返回true的元素;
  4. boolean containsAll(Collection coll):判断coll集合中的元素是否在当前集合中都存在,即coll集合是否是当前集合的“子集”;
  5. boolean equals(Object obj):判断当前集合与obj是否相等
package gather;

import java.util.ArrayList;
import java.util.Collection;

public class TestCollection_judge {
    public static void main(String args[]){
        TestCollection_judge.testJudge();
    }
    public static void testJudge(){
        Collection c1=new ArrayList();
        c1.add(1);
        c1.add(2);
        c1.add(3);
        c1.add(4);
        System.out.println("c1:"+c1);   //c1:[1, 2, 3, 4]
        System.out.println("c1中元素的个数:"+c1.size());   //c1中元素的个数:4
        System.out.println("c1是否为空:"+c1.isEmpty());   //c1是否为空:false
        System.out.println("c1中是否包含1:"+c1.contains(1));  //true

        Collection c2=new ArrayList();
        c2.add(1);
        c2.add(3);
        c2.add(6);
        System.out.println("c1中是否包含c2中的元素:"+c1.containsAll(c2)); //false
        System.out.println("c1集合与c2集合是否相等:"+c1.equals(c2));  //false
    }
}

2.3 删除

  1. void clear():清空集合元素;
  2. boolean remove(Object obj):从当前集合中删除第一个找到的与obj对象equals返回true的元素;
  3. boolean removeAll(Collection coll):从当前集合中删除所有与coll集合中相同的元素;
  4. boolean retainAll(Collection coll):从当前集合中删除两个集合中所有不同的元素,使得当前集合仅保留与coll集合中的元素相同的元素,即当前集合中仅保留两个集合的交集;
package gather;

import java.util.ArrayList;
import java.util.Collection;

public class TestCollection_clear {
    public static void main(String[] args) {
        TestCollection_clear.testClear();

    }
    public static void testClear(){
        Collection c1=new ArrayList();
        c1.add(1);
        c1.add(2);
        c1.add(3);

        Collection c2=new ArrayList();
        c2.add(1);
        c2.add(3);
        c2.add(5);

        System.out.println("c1:"+c1);  //[1, 2, 3]
        System.out.println("c2:"+c2);  //[1, 3, 5]

//        c1.clear();
//        System.out.println("清除后的c1:"+c1);  //[]

//        c1.remove(2);
//        System.out.println("删除c1中的1:"+c1);  //[1, 3]

//        c1.removeAll(c2);
//        System.out.println("删除c1中与c2相同的元素:"+c1);  //[2]

        c1.retainAll(c2);
        System.out.println("删除c1中与c2中不同的元素:"+c1);  //[1, 3]
    }
}

2.4 其他

  1. Object[] toArray():返回包含当前集合中所有元素的数组;
  2. hashCode():获取集合对象的哈希值;
  3. iterator():返回迭代器对象,用于集合遍历;
package gather;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

public class TestCollection_other {
    public static void main(String[] args) {
        TestCollection_other.other();
    }
    public static void other(){
        Collection c1=new ArrayList();
        c1.add(1);
        c1.add(2);
        c1.add(3);
        System.out.println("集合c1:"+c1);  //[1, 2, 3]

//        集合转换为数组,集合的toArray()方法
        Object[] objects=c1.toArray();   //集合c1转换成数组objects
        System.out.println("用数组返回coll中所有元素:"+ Arrays.toString(objects));  //[1, 2, 3]

//        数组转换为集合,调用Arrays的asList(Object ...objs)
        Object[] arr1=new Object[]{123,"AA","aa"};
        Collection list=Arrays.asList(arr1);
        System.out.println("用集合转换为数组:"+list);  //[123, AA, aa]
    }
}

三、Iterator(迭代器)接口

3.1 Iterator接口

在程序开发中,经常需要遍历集合中的所有元素,针对这种需求,JDK专门提供了一个接口java.util.Iterator。
Iterator接口也是Java集合中的一员,但它与Collection、Map接口有所不同。

Iterator与Collection、Map接口的区别

  1. Collection接口与Map接口主要用于存储元素
  2. Iterator,被称为迭代器接口,本身并不提供存储对象的能力,主要用于遍历Collectiion中的元素
  • Collection接口继承了java.lang.Iterator接口,该接口有一个iterator()方法,那么所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象;
  • public Iterator iterator():获取集合对应的迭代器,用来遍历集合中的元素的;
  • 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前;

3.2 Iterator接口的常用方法如下:

  1. public E next():返回迭代的下一个元素;
  2. public boolean hasNext():如果仍有元素可迭代,则返回true;
  3. void remove():使用Iterator迭代器删除元素,java.util.Iterator迭代器中的方法;
    注意:
  • 在调用it.next()方法之前必须要调用it.hasNext()进行检测,若不调用,且下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常。
  • Iterator可删除集合的元素,但遍历过程中通过迭代器remove方法,不是集合对象的remove方法;
  • 如果还未调用next()或在上一次调用next()方法之后已经调用了remove()方法,再调用remove()都会报IllegalStateException;
  • Collection 已经有remove(xx)方法了,为什么Iterator迭代器还要提供删除方法呢?因为迭代器的remove()可以按指定的条件进行删除。
package gather;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class TestIterator {
   public static void main(String[] args) {
       TestIterator.testIterator();
   }
   public static void testIterator(){
       Collection c1=new ArrayList();  //创建集合对象
       c1.add(1);
       c1.add(2);
       c1.add(3);
       System.out.println("c1;"+c1);
       System.out.println();

       Iterator c2=c1.iterator();  //获取迭代器对象
       System.out.println(c2.next());
       System.out.println(c2.next());
       System.out.println(c2.next());
//        System.out.println(c2.next());
       System.out.println();

       Iterator c3=c1.iterator();  //获取迭代器对象
       while(c3.hasNext()){   //判断是否还有元素可进行迭代
           System.out.print(c3.next()+"\t");  //取出下一个元素
           System.out.println();

       Iterator c4=c1.iterator();
       while(c4.hasNext()){
           Object obj=c4.next();
           if(obj.equals("1")){
               c4.remove();
           }
       }
       }
   }
}

3.3 迭代器的执行原理

Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素;
图示原理:
在这里插入图片描述

3.4 foreach循环

foreach循环(也称增强for循环)是JDK5.0中定义的一个高级for循环,专门用来遍历数组和集合的,其增强for的内部原理其实是Iterator迭代器
foreach循环的语法格式:

for(元素的数据类型 局部变量 : Collection集合或数组){
//操作局部变量的输出操作
}

//这里局部变量就是一个临时变量,自己命名即可

package gather;

import java.util.ArrayList;
import java.util.Collection;

public class TestForeach {
    public static void main(String[] args) {
        TestForeach.testForeach();
    }
    public static void testForeach(){
        Collection c1=new ArrayList();
        c1.add(1);
        c1.add(2);
        c1.add(3);
        for(Object c:c1){
            System.out.println(c);
        }
        int[] nums={1,2,3,4,5,6};
        for (int num:nums
             ) {
            System.out.println(num);
        }
    }
}

foreach增强for循环用于Collection和数组,通常只进行遍历元素,不要再遍历的过程中对集合元素进行增删操作。

四、Collection子接口1—List

4.1 List接口特点

  1. 鉴于Java中数组用来存储数据的局限性,我们通常使用java.util.List代替数组
  2. List集合类中元素有序,且可重复,集合中的每个元素都有其对应的顺序索引;
  3. JDK API中List接口的实现类:ArrayList、LinkedList和Vector;

4.2 List接口方法

List除了从Collection集合继承的方法外,List集合里添加了一些根据索引来操作集合元素的方法;

插入元素

  • void add(int index,Object ele):在index位置插入ele元素;
  • boolean addAll(int index,Collection eles):从index位置开始将eles中的所有元素添加进来;
public static void testAdd(){
        //        创建List对象
        List<Integer> list=new ArrayList<Integer>();
//        在尾部添加指定元素
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        System.out.println("list集合:"+list);

//        在指定位置插入元素
        list.add(2,6);
//        list.add(6,2);  //插入的位置一定要在创建插入位置的内,否则出现IndexOutOfBoundException异常
        System.out.println("在指定索引位置添加元素:"+list);

        Collection c1=new ArrayList();
        c1.add(11);
        c1.add(22);
        c1.add(33);

//        在指定位置插入对象中的所有元素
        list.addAll(0,c1);
        System.out.println("在指定索引位置添加对象:"+list);
    }

获取元素

  • Object get(int index):获取指定index位置的元素;
  • List subList(int fromIndex,int toIndex):返回fromIndex到toIndex集合;
//    获取元素
    public static void testGet(){
        List<Integer> list=new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        System.out.println("list:"+list);
//        获取指定位置的元素
        System.out.println("获取指定索引位置的元素:"+list.get(2));
//        获取指定索引位置的子集
        System.out.println("获取指定索引位置的子集合:"+list.subList(0,2));
    }

获取元素索引

    • int indexOf(Object obj):返回obj在集合中首次出现的位置;
  • int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置;
//    获取指定元素的索引
    public static void testIndex(){
        List<Integer> list=new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(2);
        list.add(3);
        System.out.println(list);
        System.out.println("获取指定元素的首次出现位置的索引:"+list.indexOf(3));   //首次出现的位置
        System.out.println("获取指定元素的最后出现位置的索引:"+list.lastIndexOf(3));  //末次出现的位置
    }

删除和替换元素

  • Object remove(int index):移除指定index位置的元素,并返回此元素
  • Object set(int index,Object ele):设置指定index位置的元素为ele;
public static void testDelete(){
        List<Integer> list=new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(2);
        list.add(1);
        System.out.println("删除集合中索引所对应的指定元素:"+list.remove(1));
        System.out.println("删除指定元素后的集合:"+list);
    }
    public static void testSet(){
        List<Integer> list=new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        System.out.println("替换集合中索引所对应的指定元素:"+list.set(1,6));
        System.out.println("替换后的集合:"+list);
    }

4.3 List接口的主要实现类–ArrayList

  1. ArrayList是List接口的主要实现类
  2. 本质上,ArrayList是对象引用的一个“变长”数组;
  3. Arrays.asList(…):方法返回的List集合,既不是ArrayList实例,也不是Vector实例,其返回值是一个固定长度的List集合;

4.4 List的实现类–LinkedList

对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高,这是由底层采用链表(双向链表)结构存储数据决定的。

特有的方法

  1. void addFirst(Object obj)
  2. void addLast(Object obj)
  3. Object getFirst()
  4. Object getLast()
  5. Object removeFirst()
  6. Object removeLast()

4.5 List的实现类–Vector(向量)

  • Vector是一个古老的集合,JDK1.0就有了,大多数操作与ArrayList相同,区别之处在于Vector是线程安全的;
  • 在各种List中,最好把ArrayList作为默认选择,当插入、删除频繁时,使用LinkedList,Vector总是比ArrayList慢,所以尽量避免使用;

特有方法

  1. void addElement(Object obj)
  2. void insertElementAt(Object obj,int index)
  3. void setElementAt(Object obj,int index)
  4. void removeElement(Object obj)
  5. void removeAllElements()

4.6 练习

练习1:学生信息录入

题目
•定义学生类,属性为姓名、年龄,提供必要的getter、setter方法,构造器,toString(),equals()方法。
•使用ArrayList集合,保存录入的多个学生对象。
•循环录入的方式,1:继续录入,0:结束录入。
•录入结束后,用foreach遍历集合。
•代码实现;
效果图
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/49b0c806b9e640e6af0d961a4b262143.png)
代码
package gather.list;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Scanner;

public class TrainList {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);   
        ArrayList stus=new ArrayList();   //create students information set
        for(;;){        //operation
            System.out.println("选择操作(录入:1,结束:0)");
            int choice=sc.nextInt();     //choice operation type
            
            if(choice==1){               //judge operation type
                System.out.print("姓名:");  //name
                String stuName=sc.next();

                System.out.print("年龄:");  //age
                int stuAge=sc.nextInt();

                Student stu=new Student(stuName,stuAge);   //create single student information Object
                stus.add(stu);
            }
            else if(choice==0){
                break;
            }
            else{
                System.out.println("您的选择有误,请重新输入!");
            }
        }
        for(Object stu:stus){    //output students information
            System.out.println(stu);
        }
    }
}
class Student{   //create student Object
    private String name;
    private int age;

    public void setName(String name){
        this.name=name;
    }
    public String getName(){
        return name;
    }
    public void setAge(int age){
        this.age=age;
    }
    public int getAge(){
        return age;
    }

    public Student() {
    }

    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

练习2:统计元素出现次数

题目
 1、请定义方法public static int listTest(Collection list,String s)统计集合中指定元素出现的次数
 2、创建集合,集合存放随机生成的30个小写字母
 3、用listTest统计,a、b、c、x元素的出现次数
 4、效果图
效果图

在这里插入图片描述

代码
package gather.list;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;

public class TestList_02 {
    public static void main(String[] args) {
        //1.随机生成含有30个小写字母的集合
        Collection list = new ArrayList();//创建集合
        Random rd = new Random();
        for (int i = 0; i < 30; i++) {
            list.add((char) (rd.nextInt(26) + 97) + "");
        }
        System.out.println("随机生成集合list:"+list);
        System.out.println("a:"+listTest(list,"a"));
        System.out.println("b:"+listTest(list,"b"));
        System.out.println("c:"+listTest(list,"c"));
        System.out.println("x:"+listTest(list,"x"));
    }
    public static int listTest(Collection list,String s){   //计数
        int count=0;
        for(Object obj:list){
            if(s.equals(obj)){
                count++;
            }
        }
        return count;
    }
}

练习3:KTV点歌系统

题目
分别使用ArrayList和LinkedList集合,编写一个KTV点歌系统的程序。在程序中:
•指令1代表添加歌曲
•指令2代表将所选歌曲置顶
•指令3代表将所选歌曲提前一位
•指令4代表退出该系统
要求根据用户输入的指令和歌曲名展现歌曲列表。例如输入指令1,输入歌曲名"爱你一万年",则输出“当前歌曲列表:[爱你一万年]”。
分析
1.为了能够指引用户快速上手操作,首先要将各个指令所表示的含义打印到控制台
2.创建一个集合作为歌曲列表,并向其添加一部分歌曲;
通过ArrayList或LinkedList集合定义的方法操作歌曲列表;
效果图

在这里插入图片描述

代码
package gather.list;

import java.util.ArrayList;
import java.util.Scanner;

/**
 * 分别使用ArrayList和LinkedList集合,编写一个KTV点歌系统的程序。在程序中:
 * •指令1代表添加歌曲
 * •指令2代表将所选歌曲置顶
 * •指令3代表将所选歌曲提前一位
 * •指令4代表退出该系统
 * 要求根据用户输入的指令和歌曲名展现歌曲列表。例如输入指令1,输入歌曲名"爱你一万年",则输出“当前歌曲列表:[爱你一万年]”。
 */
public class TestList_03 {
//        创建歌曲列表
    public static ArrayList musicList=new ArrayList();
    public static Scanner sc=new Scanner(System.in);
    public static void main(String[] args) {
//        添加一部分歌曲至歌曲列表中
        Function.addMusicList();
        boolean flag=true;
        while(flag){
            //        对系统的功能指令进行介绍
            System.out.println("当前歌曲列表:"+musicList);
            System.out.println("===========Welcome To KTV System===========");
            System.out.println("1.添加歌曲");
            System.out.println("2.置顶歌曲");
            System.out.println("3.提前歌曲");
            System.out.println("4.退出系统");
            System.out.println("============================================");

//        输入功能指令
            System.out.println("请输入您的指令:");
            int instruction=sc.nextInt();
            switch (instruction){
                case 1:Function.addMusic();break;
                case 2:Function.setTop();break;
                case 3:Function.setBefore();break;
                case 4:
                       System.out.println("--------退出系统----------");
                       System.out.println("您已退出点歌系统!!!");
                       flag=false;
                       break;
                default:
                    System.out.println("您输入的指令有误,请重新输入!!!");break;
            }
        }
    }
}
class Function{
    //添加部分歌曲
    public static void addMusicList(){
        TestList_03.musicList.add("西楼儿女");
        TestList_03.musicList.add("我的纸飞机");
        TestList_03.musicList.add("不将就");
        TestList_03.musicList.add("我期待的不是雪");
        TestList_03.musicList.add("熬夜");
        TestList_03.musicList.add("悬溺");

    }
    //添加歌曲
    public static void addMusic(){
        System.out.println("请输入要添加的歌曲名称:");
        String musicName=TestList_03.sc.next();  //获取键盘输入的歌名
        TestList_03.musicList.add(musicName);  //添加到歌单
        System.out.println("已添加歌曲:"+musicName);
    }
    //置顶歌曲
    public static void setTop(){
        System.out.println("请输入要置顶的歌曲名称:");
        String musicName=TestList_03.sc.next();  //获取键盘输入内容
        int musicIndex=TestList_03.musicList.indexOf(musicName);  //查找指定歌曲位置
        if(musicIndex<0){  //判断输入歌曲是否存在
            System.out.println("当前列表中没有输入的歌曲!!!");
        }
        else{
            TestList_03.musicList.remove(musicName);    //移除置顶的歌曲
            TestList_03.musicList.add(0,musicName);   //将指定的歌曲放到第一位
            System.out.println("已将歌曲《"+musicName+"》置顶");
        }
    }
    //将歌曲前置一位
    public static void setBefore(){
        System.out.println("请输入要前置的歌曲名称:");
        String musicName=TestList_03.sc.next();
        int musicIndex=TestList_03.musicList.indexOf(musicName);  //查找指定歌曲位置
        if(musicIndex<0){  //判断输入歌曲是否存在
            System.out.println("当前歌曲列表中没有输入的歌曲!!!");
        }
        else if(musicIndex==0){  //判断歌曲已在第一位
            System.out.println("当前歌曲已在最顶部!!!");
        }
        else{
            TestList_03.musicList.remove(musicName);
            TestList_03.musicList.add(musicIndex-1,musicName);
            System.out.println("已将歌曲《"+musicName+"》前置一位");
        }
    }
}

五、Collection子接口2—Set

5.1 Set接口概述

  • Set接口是Collection的子接口,Set接口相较于Collection接口没有提供额外的方法;
  • Set集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set集合中,则添加操作失败。
  • Set集合支持的遍历方式和Collection集合一样:foreach和Iterator;
  • Set的常用实现类有:HashSet、TreeSet、LinkedHashSet;

5.2 Set主要实现类—HashSet

5.2.1 HashSet概述

  • HashSet是Set接口的主要实现类,大多数使用Set集合是都使用这个实现类;
  • HashSet按Hash算法来存储集合中的元素,因此具有很好的存储,查找,删除性能;
  • HashSet具有特点:
  1. 不能保证元素的排列顺序;
  2. HashSet不是线程安全的;
  3. 集合元素可以是null;
  • HashSet集合判断两个元素相等的标准,两个对象通过**hashCode()**方法得到的哈希值相等,并且两个对象的equals()方法返回值为true;
  • 对于存放在Set容器中的对象,对应的类一定要重写hashCode()和equals(Object obj)方法,以实现对象相等规则,即“相等的对象必须具有相等的散列码”;
  • HashSet集合中元素的无序性,不等同于随机性,这里的无序性与元素的添加位置有关。具体来说:在添加每一个元素到数组中时,具体的存储位置是由元素的hashCode()调用后返回的hash值决定的。导致在数组中每个元素不是一次紧密存放的,表现出一定的无序性;

5.2.2 HashSet中添加元素的过程

  1. 当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法得到该对象的hashCode值,然后根据hashCode值,通过某个散列函数决定该对象在HashSet底层数组中的存储位置
  2. 如果要在数组中存储的位置上没有元素,则直接添加成功;
  3. 如果要在数组中存储的位置上有元素,则继续比较:
  • 如果两个元素hashCode值不相等,则添加成功;
  • 如果两个元素的hashCode()值相等,则会继续调用**equals()**方法;
    (1) 如果equals()方法结果为false,则添加成功;
    (2)如果equals()方法结果为true,则添加失败;
  1. 第2步添加成功 ,元素会保存在底层数组中;
  2. 第3步两种添加成功的操作,由于该底层数组的位置已经有元素了,则会通过链表的方式继续链接,存储;
package gather.set;

import java.util.HashSet;
import java.util.Objects;

public class TestSet_01 {
    public static void main(String[] args) {
        HashSet hs = new HashSet();
        hs.add("小小");
        hs.add("晓晓");
        hs.add("小小");
        hs.add("潇潇");
        hs.add("筱筱");
        System.out.println("hs:" + hs);  //不允许重复,无序

        HashSet set=new HashSet();
        set.add(new Time(2021,1,1));
        set.add(new Time(2022,1,1));
        set.add(new Time(2022,1,1));
        set.add(new Time(2023,1,1));
        System.out.println("set:"+set);  //不允许重复,无序
    }
}

class Time {
    private int year;
    private int month;
    private int day;

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    public Time(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public Time() {
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Time time = (Time) o;
        return  year==time.year&&
                month==time.month&&
                day == time.day;
    }

    @Override
    public int hashCode() {

        return Objects.hash(year,month,day);
    }

    @Override
    public String toString() {
        return "Time{" +
                "year=" + year +
                ", month=" + month +
                ", day=" + day +
                '}';
    }
}

效果图
在这里插入图片描述

5.2.3 重写hashCode()方法的基本原则

  1. 在程序运行时,同一个对象多次调用hashCode()方法应该返回相同的值
  2. 当两个对象的equals()方法比较返回true时,这两个对象的hashCode()方法的返回值也应相等;
  3. 对象中用作equals()方法比较的属性Field,都应该用来计算hashCode值。
    注意:
    如果两个元素的equals()方法返回true,但他们的hashCode()返回值不相等,hashSet将会把他们存储在不同的位置,但依然可添加成功。

5.2.4 重写equals()方法的基本原则

  1. 重写equals方法的时候一般都需要同时复写hashCode方法,通常参与计算hashCode的对象的属性也应该参与到equals()中进行计算;
  2. 推荐:开发中直接调用IDEA里的快捷键自动重写equals()和hashCode()方法即可,(快捷键:alt+insert);
    素数的作用可以减少冲突。

5.3 Set主要实现类—LinkdedHashSet

  • LinkedHashSet是HashSet的子类,不允许集合元素重复;
  • LinkedHashSet根据元素的hashCode值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以添加顺序保存的;
  • LinkedHashSet插入性能略低于HashSet,但在迭代访问Set里的全部元素时有很好的性能;
package gather.set;

import java.util.LinkedHashMap;
import java.util.LinkedHashSet;

public class TestLinkedHashSet {
    public static void main(String[] args) {
        LinkedHashSet linkedHashSet=new LinkedHashSet();
        linkedHashSet.add(123);
        linkedHashSet.add(123);
        linkedHashSet.add("一二三");
        linkedHashSet.add('a');
        System.out.println("linkedHashSet:"+linkedHashSet);
    }
}

5.4 TreeSet概述

  • TreeSet是SortedSet接口的实现类,TreeSet可以按照添加的元素的指定属性的大小顺序进行遍历;
  • TreeSet底层使用红黑树结构存储数据;
  • 新增的方法:
  1. Comparator comparator()
  2. Object first()
  3. Object last()
  4. Object lower(Object e)
  5. Object higher(Object e)
  6. SortedSet subSet(fromElement,toElement)
  7. SortedSet headSet(toElement)
  8. SortedSet tailSet(fromElement)
  • TreeSet特点:不允许重复,实现排序(自然排序或定制排序)
  • TreeSet两种排序方法:自然排序和定制排序,默认情况下,TreeSet采用自然排序;

自然排序(默认排序方式)

TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序(默认情况)排序

  1. 如果试图把一个对象添加到TreeSet时,则该对象的类必须实现Comparable接口(TreeSet中);
  2. 实现Comparable的类必须实现compareTo(Object obj)方法,两个对象即通过compareTo(Object obj)方法的返回值来比较大小(对象类中);
//    自然排序
    public static void autoSortedTreeSet(){
        TreeSet treeSet01=new TreeSet();
        treeSet01.add(new User("星星",23));  //将User对象添加到TreeSet,则User类必须要实现Comparable接口
        treeSet01.add(new User("萌萌",21));
        treeSet01.add(new User("晴晴",22));
        Iterator is=treeSet01.iterator();
        System.out.println("======手动排序======");
        while (is.hasNext()){
            System.out.println(is.next());
        }
    }
//该类实现了Comparable接口
class User implements Comparable{
    private String name;
    private int age;

    public String getName(){
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    public User(){

    }

    public void setName(String name) {
        this.name = name;
    }

    public User(String name, int age){
        this.name=name;
        this.age=age;

    }

    @Override
    public int compareTo(Object o) {   //实现Comparable接口中的compareTo()方法
        if(this ==o){
            return 0;
        }
        if(o instanceof User){
            User user=(User) o;
            int value=this.age-user.age;
            if(value!=0){
                return value;
            }
            return -this.name.compareTo(user.name);
        }
        throw new RuntimeException("输入的类型不匹配");
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

定制排序(定制排序方式)

如果元素所属的类没有实现Comparable接口,或不希望按照升序(默认情况)的方式排列元素或希望按照其他属性大小进行排序,则考虑使用定制排序,定制排序,通过Comparator接口来实现,需要**重写compare(T o1,T o2)**方法;

  1. 利用int compare(T o1,T o2)方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2;
  2. 要实现定制排序,需要将实现Comparator接口的实例作为形参传递给TreeSet的构造器
    因为只有相同类的两个实例才会比较大小,所以向TreeSet中添加的应该是同一个类的对象;
    对于TreeSet集合而言,它判断了两个对象那个是否相等的唯一标准是:两个对象通过compareTo(Object obj)或compare(Object o1,Object o2)方法比较返回值,返回值为0,则认为两个对象相等。
    public static void manualSorted(){
        Comparator comparator=new Comparator(){
            @Override
            public int compare(Object o1,Object o2){
                if(o1 instanceof User && o2 instanceof User){
                    User u1=(User)o1;
                    User u2=(User)o2;
                    return u1.getName().compareTo(u2.getName());
                }
                throw new RuntimeException("输入的类型不匹配");
            }
        };
        System.out.println("-------手动排序---------");
        TreeSet set=new TreeSet(comparator);
        set.add(new User("Tom",23));
        set.add(new User("Alis",22));
        set.add(new User("Jerry",24));
        set.add(new User("Tommy",21));
        Iterator iterator=set.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
//User对象与自然排序相同

六、Map接口

6.1 Map的概述

Map与Collection并列存在,用于保存具有映射关系的数据:key-value

  1. Collection集合称为单列集合,元素是鼓励存在的(理解为单身)
  2. Map集合是双列集合,元素是成对存在的(理解为夫妻)
  • Map中的key和value都可以是任何引用类型的数据,但常用String类作为Map的“键”;
  • Map接口的常用实现类:HashMap、LinkedHashMap、TreeMap和Properties。其中HashMap是Map接口使用频率最高的实现类
    在这里插入图片描述

6.2 Map中key-value特点

HashMap中存储的key、value的特点如下:

  1. Map中的key用Set来存放,不允许重复,即同一个Map对象对应的类,须重写hashCode()和equals()方法
    在这里插入图片描述
  2. key和value之间存在单向一对一关系,即通过指定的key总能找到唯一的、确定的value,不同key对应的value可以重复。value所在的类要重写equals()方法
  3. key和value构成一个entry,所有的entry彼此之间是无序的,不可重复的。
    在这里插入图片描述

6.3 Map接口的常用方法

6.3.1 添加、修改操作

  1. Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中;
  2. void putAll(Map m):将m中的所有key-value对存放到当前map中;
    //添加、修改操作
//    1.put()方法
    public static void putMethod(){
        HashMap hashMap=new HashMap();
        hashMap.put("小小",12);
        hashMap.put("晓晓",21);
        hashMap.put("筱筱",22);
        hashMap.put("小小",20);   //该操作为修改操作
        System.out.println(hashMap);
    }
//    2.putAll()方法
    public static void putAllMethod(){
        HashMap hm=new HashMap();
        hm.put("晨晨",20);
        hm.put("辰辰",21);
        hm.put("琛琛",22);
        HashMap hm2=new HashMap();
        hm2.put("AA",23);
        hm2.putAll(hm);
        System.out.println(hm2);
    }

6.3.2 删除操作

  1. Object remove(Object key):移除指定key的key-value对,并返回value;
  2. void clear():清空当前map中所有数据;
//    删除操作
    public static void deleteMethod(){
        HashMap hashMap=new HashMap();
        hashMap.put("AA",1);
        hashMap.put("BB",2);
        hashMap.put("CC",3);
        hashMap.put("DD",4);
        System.out.println("原集合:"+hashMap);
        hashMap.remove("DD");
        System.out.println("remove()方法删除key=”DD“:"+hashMap);
        hashMap.clear();
        System.out.println("clear()方法清空集合:"+hashMap);
    }

6.3.3 元素查询的操作

  1. Object get(Object key):获取指定key对应的value;
  2. boolean containsKey(Object key):是否包含指定的key;
  3. boolean containsValue(Object value):是否包含指定的value;
  4. int size():返回map中key-value对的个数;
  5. boolean isEmpty():判断当前map是否为空;
  6. boolean equals(Object obj):判断当前map和参数对象obj是否相等;
//    元素查询
    public static void queryMethod(){
        HashMap hashMap=new HashMap();
        hashMap.put("AA",1);
        hashMap.put("BB",2);
        hashMap.put("CC",3);
        hashMap.put("DD",4);
        hashMap.put("EE",5);
        hashMap.put("FF",6);
        HashMap hashMap1=new HashMap();
        hashMap1.put("AA",1);
        hashMap1.put("BB",2);
        System.out.println("get():"+hashMap.get("FF"));
        System.out.println("containsKey():"+hashMap.containsKey("FF"));
        System.out.println("containsValues():"+hashMap.containsValue(6));
        System.out.println("size():"+hashMap.size());
        System.out.println("isEmpty():"+hashMap.isEmpty());
        System.out.println("equals():"+hashMap.equals(hashMap1));
    }

6.3.4 元视图操作的方法

  1. Set keySet():返回所有key构成的Set集合;
  2. Collection values():返回所有value构成的Collection集合;
  3. Set entrySet():返回所有key-value对构成的Set集合;
//    元视图操作方法
    public static void viewMethod(){
        HashMap hashMap=new HashMap();
        hashMap.put("AA",1);
        hashMap.put("BB",2);
        hashMap.put("CC",3);
        hashMap.put("DD",4);
        hashMap.put("EE",5);
        hashMap.put("FF",6);
        System.out.println("输出所有的key--->keySet():"+hashMap.keySet());
        System.out.println("输出所有的value--->values():"+hashMap.values());
        System.out.println("输出所有的entry(key-value)--->entrySet():"+hashMap.entrySet());
    }

6.4 Map的主要实现类—HashMap

6.4.1 HashMap概述

  • HashMap是Map接口使用频率最高的实现类;
  • HashMap是线程不安全的,允许添加null键和null值;
  • 存储数据采用的哈希表结构,底层使用一维数组+单向链表+红黑树进行key-value数据的存储,与HashSet一样,元素的存储顺序不能保证一致;
  • HashMap判断两个key相等的标准是:两个key的hashCode值相等,通过equals()方法返回true。
  • HashMap判断两个value相等的标准是:两个value通过equals()方法返回true;

练习

练习1:添加喜欢的歌手以及其歌手唱过的歌曲
```java
package gather.map;

import java.util.ArrayList;
import java.util.HashMap;

public class HashMapTest {
    public static void main(String[] args) {
        HashMapTest.singer();
    }
    public static void singer(){
        HashMap singers=new HashMap();
        ArrayList songs1=new ArrayList();
        String singer1="周杰伦";
        songs1.add("双节棍");
        songs1.add("本草纲目");
        songs1.add("夜曲");
        songs1.add("稻香");
        singers.put(singer1,songs1);

        String singer2="陈奕迅";
        ArrayList songs2=new ArrayList();
        songs2.add("浮夸");
        songs2.add("十年");
        songs2.add("红玫瑰");
        songs2.add("好久不见");
        songs2.add("孤勇者");
        singers.put(singer2,songs2);
        System.out.println(singers);
    }
}

运行结果:
在这里插入图片描述

练习2:统计字符串中元素个数
package gather.map.trains;

import java.util.HashMap;
import java.util.Scanner;

/**
 * 统计字符串中每个字符出现的次数
 */
public class WordCountTest {
    public static void main(String[] args) {
        WordCountTest.wordCount();
    }
    public static void wordCount(){
//        String str="abcddeagihkgjaoijiajkrzlnbghrggijlejgojahgni";
        Scanner scanner=new Scanner(System.in);
        System.out.println("请随机输入字符串:");
        String str=scanner.next();
        char[] chars=str.toCharArray();
        HashMap hm=new HashMap();
        for(char c:chars){
            if(!hm.containsKey(c)){
                hm.put(c,1);
            }
            else{
                hm.put(c,(int)hm.get(c)+1);
            }
        }
        for(Object key:hm.keySet()){
            System.out.print(key+"="+hm.get(key)+"\t");
        }
    }
}

6.5 Map的实现类(二)—LinkedHashMap

  • LinkedHashMap是HashMap的子类;
  • 存储数据采用的哈希表结构+链表结构,在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的先后顺序,可保证遍历元素时,与添加的顺序一致;
  • 通过哈希表结构可以保证键的唯一,不重复,需要键所在类重写hashCode()方法,equals()方法;
package gather.map;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public class LinkedHashMapTest {
    public static void main(String[] args) {
        LinkedHashMapTest.testLinkedHashMapMethod();

    }

    /**
     * key相同,新的value会覆盖原来的value
     * 因为String重写了hashCode和equals方法
     */
    public static void testLinkedHashMapMethod(){
        LinkedHashMap linkedHashMap=new LinkedHashMap();
        linkedHashMap.put("AA",12.0);
        linkedHashMap.put("BB",23.0);
        linkedHashMap.put("DD",34.0);
        linkedHashMap.put("CC",45.0);
        linkedHashMap.put("CC",88.0);
//        遍历的顺序与添加时的顺序一致
        System.out.println(linkedHashMap.entrySet());
//        HashMap支持key和value为null值
        String name=null;
        Integer age=null;
        linkedHashMap.put(name,age);

        Set entrySet=linkedHashMap.entrySet();
        for(Object obj:entrySet){
            Map.Entry entry=(Map.Entry)obj;
            System.out.println(entrySet);
        }
    }
}

6.6 Map的实现类(三)—TreeMap

  • TreeMap存储key-value对时,需要根据key-value对进行排序,TreeMap可以保证所有的key-value对处于有序状态
  • TreeSet底层使用红黑树结构存储数据;
  • TreeMap 的 Key 的排序:
  1. 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException;
  2. 定制排序:创建 TreeMap 时,构造器传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口;
  • TreeMap判断两个key相等的标准:两个key通过compareTo()方法或者compare()方法返回0
public class TestTreeMap {
    /*
    * 自然排序举例
    * */
    @Test
    public void test1(){
        TreeMap map = new TreeMap();
        map.put("CC",45);
        map.put("MM",78);
        map.put("DD",56);
        map.put("GG",89);
        map.put("JJ",99);

        Set entrySet = map.entrySet();
        for(Object entry : entrySet){
            System.out.println(entry);
        }

    }

    /*
    * 定制排序
    *
    * */
    @Test
    public void test2(){
        //按照User的姓名的从小到大的顺序排列

        TreeMap map = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if(o1 instanceof User && o2 instanceof User){
                    User u1 = (User)o1;
                    User u2 = (User)o2;

                    return u1.name.compareTo(u2.name);
                }
                throw new RuntimeException("输入的类型不匹配");
            }
        });
        map.put(new User("Tom",12),67);
        map.put(new User("Rose",23),"87");
        map.put(new User("Jerry",2),88);
        map.put(new User("Eric",18),45);
        map.put(new User("Tommy",44),77);
        map.put(new User("Jim",23),88);
        map.put(new User("Maria",18),34);

        Set entrySet = map.entrySet();
        for(Object entry : entrySet){
            System.out.println(entry);
        }
    }
}
class User implements Comparable{
    String name;
    int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public User() {
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    /*
    举例:按照age从小到大的顺序排列,如果age相同,则按照name从大到小的顺序排列
    * */
    @Override
    public int compareTo(Object o) {
        if(this == o){
            return 0;
        }

        if(o instanceof User){
            User user = (User)o;
            int value = this.age - user.age;
            if(value != 0){
                return value;
            }
            return -this.name.compareTo(user.name);
        }
        throw new RuntimeException("输入的类型不匹配");
    }
}

6.7 Map实现类(四)—Hashtable

  • Hashtable是Map接口的古老实现类,JDK1.0就提供了。不同于HashMap,Hashtable是线程安全的。
  • Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构(数组+单向链表),查询速度快。
  • 与HashMap一样,Hashtable 也不能保证其中 Key-Value 对的顺序
  • Hashtable判断两个key相等、两个value相等的标准,与HashMap一致。
  • 与HashMap不同,Hashtable 不允许使用 null 作为 key 或 value。

Hashtable和HashMap的区别

HashMap:底层是一个哈希表(jdk7:数组+链表;jdk8:数组+链表+红黑树),是一个线程不安全的集合,执行效率高
Hashtable:底层也是一个哈希表(数组+链表),是一个线程安全的集合,执行效率低

HashMap集合:可以存储null的键、null的值
Hashtable集合,不能存储null的键、null的值

Hashtable和Vector集合一样,在jdk1.2版本之后被更先进的集合(HashMap,ArrayList)取代了。所以HashMap是Map的主要实现类,Hashtable是Map的古老实现类。

Hashtable的子类Properties(配置文件)依然活跃在历史舞台
Properties集合是一个唯一和IO流相结合的集合

6.8 Map实现类(五)—Properties

  • Properties 类是 Hashtable 的子类,该对象用于处理属性文件;
  • 由于属性文件里的 key、value 都是字符串类型,所以 Properties 中要求 key 和 value 都是字符串类型,常用于处理属性文件;
  • 存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法;
@Test
public void test01() {
    Properties properties = System.getProperties();
    String fileEncoding = properties.getProperty("file.encoding");//当前源文件字符编码
    System.out.println("fileEncoding = " + fileEncoding);
}
@Test
public void test02() {
    Properties properties = new Properties();
    properties.setProperty("user","songhk");
    properties.setProperty("password","123456");
    System.out.println(properties);
}

@Test
public void test03() throws IOException {
    Properties pros = new Properties();
    pros.load(new FileInputStream("jdbc.properties"));
    String user = pros.getProperty("user");
    System.out.println(user);

七、Collections工具类

7.1 常用方法

Collections中提升了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提升了对集合对象设置不可变、对集合对象实现同步控制等方法(均为static方法);

7.1.1 排序操作

  1. reverse(List):反转List中元素的顺序;
  2. shuffle(List):对List集合元素进行随机排序;
  3. sort(List):根据元素的自然顺序对指定List集合元素按升序排序;
  4. sort(List,Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序;
  5. swap(List ,int, int):将指定list集合中的i处元素和j处元素进行交换;

7.1.2 查找

  1. Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
  2. Object min(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素;
  3. Object min(Collection):根据元素的自然顺序,返回给定集合中的最小元素;
  4. Object min(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最小元素;
  5. int binarySearch(List list,T key)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且必须是可比较大小的,即支持自然排序的。而且集合也事先必须是有序的,否则结果不确定。
  6. int binarySearch(List list,T key,Comparator c)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且集合也事先必须是按照c比较器规则进行排序过的,否则结果不确定。
  7. int frequency(Collection c,Object o):返回指定集合中指定元素的出现次数

7.1.3 复制、替换

  1. void copy(List dest,List src):将src中的内容复制到dest中
  2. boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
  3. 提供了多个unmodifiableXxx()方法,该方法返回指定 Xxx的不可修改的视图。

7.1.4 添加

  1. boolean addAll(Collection c,T… elements)将所有指定元素添加到指定 collection 中;

7.1.5 同步

  1. Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题:
package com.cmy.collections;

import org.junit.Test;

import java.text.Collator;
import java.util.*;

public class TestCollections {
    @Test
    public void test01(){
        /*
        public static <T> boolean addAll(Collection<? super T> c,T... elements)
        将所有指定元素添加到指定 collection 中。Collection的集合的元素类型必须>=T类型
        */
        Collection<Object> coll = new ArrayList<>();
        Collections.addAll(coll, "hello","java");
        Collections.addAll(coll, 1,2,3,4);

        Collection<String> coll2 = new ArrayList<>();
        Collections.addAll(coll2, "hello","java");
        //Collections.addAll(coll2, 1,2,3,4);//String和Integer之间没有父子类关系
    }

	@Test
    public void test02(){
/*
 * public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
 * 在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,而且支持自然排序
*  
*  public static <T> T max(Collection<? extends T> coll,Comparator<? super T> comp)
*  在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,按照比较器comp找出最大者
*
*/
        List<Man> list = new ArrayList<>();
        list.add(new Man("张三",23));
        list.add(new Man("李四",24));
        list.add(new Man("王五",25));

        /*
         * Man max = Collections.max(list);//要求Man实现Comparable接口,或者父类实现
         * System.out.println(max);
         */

        Man max = Collections.max(list, new Comparator<Man>() {
            @Override
            public int compare(Man o1, Man o2) {
                return o2.getAge()-o2.getAge();
            }
        });
        System.out.println(max);
    }

	@Test
    public void test03(){
        /*
         * public static void reverse(List<?> list)
         * 反转指定列表List中元素的顺序。
         */
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"hello","java","world");
        System.out.println(list);
        Collections.reverse(list);
        System.out.println(list);
    }
	@Test
    public void test04(){
        /* public static void shuffle(List<?> list) 
         * List 集合元素进行随机排序,类似洗牌,打乱顺序
         */
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"hello","java","world");

        Collections.shuffle(list);
        System.out.println(list);
    }
	@Test
    public void test05() {
        /* public static <T extends Comparable<? super T>> void sort(List<T> list)
         * 根据元素的自然顺序对指定 List 集合元素按升序排序
         * public static <T> void sort(List<T> list,Comparator<? super T> c)
         * 根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
         */
        List<Man> list = new ArrayList<>();
        list.add(new Man("张三",23));
        list.add(new Man("李四",24));
        list.add(new Man("王五",25));
        Collections.sort(list);
        System.out.println(list);
        Collections.sort(list, new Comparator<Man>() {
            @Override
            public int compare(Man o1, Man o2) {
                return Collator.getInstance(Locale.CHINA).compare(o1.getName(),o2.getName());
            }
        });
        System.out.println(list);
    }
	@Test
    public void test06(){
        /* public static void swap(List<?> list,int i,int j)
         * 将指定 list 集合中的 i 处元素和 j 处元素进行交换
         */
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"hello","java","world");

        Collections.swap(list,0,2);
        System.out.println(list);
    }
	@Test
    public void test07(){
        /* public static int frequency(Collection<?> c,Object o)
         * 返回指定集合中指定元素的出现次数
         */
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"hello","java","world","hello","hello");
        int count = Collections.frequency(list, "hello");
        System.out.println("count = " + count);
    }
	@Test
    public void test08(){
        /* public static <T> void copy(List<? super T> dest,List<? extends T> src)
         * 将src中的内容复制到dest中
         */
        List<Integer> list = new ArrayList<>();
        for(int i=1; i<=5; i++){//1-5
            list.add(i);
        }

        List<Integer> list2 = new ArrayList<>();
        for(int i=11; i<=13; i++){//11-13
            list2.add(i);
        }
        Collections.copy(list, list2);
        System.out.println(list);
        List<Integer> list3 = new ArrayList<>();
        for(int i=11; i<=20; i++){//11-20
            list3.add(i);
        }
		//java.lang.IndexOutOfBoundsException: Source does not fit in dest
        //Collections.copy(list, list3);
        //System.out.println(list);
    }
	
	@Test
    public void test09(){
        /*public static <T> boolean replaceAll(List<T> list,T oldVal,T newVal)
         * 使用新值替换 List 对象的所有旧值
         */
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"hello","java","world","hello","hello");
        Collections.replaceAll(list, "hello","song");
        System.out.println(list);
    }
}
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值