您的位置:首页 > 编程语言 > Java开发

Java 进阶,学习笔记-8 Collection 集合,迭代器,增强 for,泛型,可变参数的使用以及集合工具类 Collection 的使用

2020-01-14 02:23 706 查看

本章主要内容有 Collection 集合,迭代器,增强 for,泛型,可变参数的使用以及集合工具类 Collection 的使用

文章目录

  • List 集合
  • Set 集合
  • 可变参数
  • Collections 工具类
  • Collection 集合

    集合和数组都是容器,都是用来储存多个数据的。他们的不同点是数组的长度是固定的,而集合的长度是可变的。数组中存储的都是同一类型的元素,可以存储基本数据类型值,并且对象的类型可以不一样

    在集合中,分为单列集合(

    java.util.Collection
    )和双列集合(
    java.util.Map
    ),这里先来看看单列集合

    Collection 是单列集合类的根接口,它有两个重要的子接口,分别为

    java.util.List
    java.util.Set

    List
    :元素有序,元素可重复。学过 Python 的朋友可以知道,这个特点和 Python 里面的列表一样
    Set
    :元素无序,元素不可重复。这也和 Python 里面的元组相似

    Collection 通用常用方法有:(适用于 List 和 Set)

    public boolean add(E e)
    :把指定的对象添加到当前集合中
    public void clear()
    :清空集合中所有的元素
    public boolean remove(E e)
    :把给定的对象在当前集合中删除
    public boolean contains(E e)
    :判断给定的对象是否包含在集合中
    public boolean isEmpty()
    :判断当前集合是否为空
    public int size()
    :返回集合中元素的个数
    public Object[] toArray()
    :把集合中的元素,存储到数组中

    示例:

    import java.util.ArrayList;
    
    // 定义测试类
    public class Test {
    public static void main(String[] args) throws Exception {
    
    // 用 ArrayList 定义一个单列集合
    ArrayList<String> list = new ArrayList<String>();
    
    // 判断这个集合是否为空
    System.out.println("这个数组是否为空:" + list.isEmpty());
    
    // 添加字符串进这个集合
    System.out.println("添加对象到这个集合当中:");
    list.add("Pluto");
    list.add("Charon");
    
    // 输出这个集合
    System.out.println(list + "\t共 " + list.size() +" 个元素");
    
    // 判断字符串 "Alex" 是否在这个集合当中
    System.out.println("字符串 \"Alex\" 是否在数组中:" + list.contains("Alex"));
    
    // 查看 list 中有多少个对象
    System.out.println("list 中有 " + list.size() + " 个对象");
    
    // 把 list 转换为数组
    Object[] objArray = list.toArray();
    
    // 遍历这个对象数组
    for (int i = 0; i < objArray.length; i++) {
    System.out.print(objArray[i] + " ");
    }
    
    // 清空这个集合
    System.out.println("清空这个集合:");
    list.clear();
    
    System.out.println("list 当中还有 " + list.size() + " 个元素");
    }
    }

    输出:

    这个数组是否为空:true
    添加对象到这个集合当中:
    [Pluto, Charon]	共 2 个元素
    字符串 "Alex" 是否在数组中:false
    list 中有 2 个对象
    Pluto Charon 清空这个集合:
    list 当中还有 0 个元素

    迭代器 Iterator

    什么是迭代:
    迭代是 Collection 集合元素的通用获取方式。流程是在获取元素前要先判断这个集合中有没有元素。如果有的话,就取出元素,然后还要判断这个集合中的元素有没有被获取完,如果没有被获取完的话,那么就一直获取元素,直到元素被获取完。这就被称为迭代。

    在集合操作中,我们经常需要遍历集合中的所有元素,为了方便,JDK 提供了一个接口

    java.util.Iterator
    Iterator
    对象也被称为迭代器

    方法

    public Iterator iterator()
    :获取集合对应的迭代器,用来遍历集合中的元素

    迭代中的常用方法:

    public E next()
    :返回迭代下一个元素
    public boolean hasNext()
    :如果仍有元素,就返回 true

    import java.util.Collection;
    import java.util.ArrayList;
    import java.util.Iterator;
    
    // 定义测试类
    public class Test {
    public static void main(String[] args) throws Exception {
    // 创建一个 ArrayList 对象
    Collection<String> list = new ArrayList<String>();
    // 添加元素
    list.add("Pluto");
    list.add("Charon");
    list.add("AndWan");
    
    // 创建 list 的迭代器
    Iterator<String> iter = list.iterator();
    
    // 迭代元素
    while(iter.hasNext()) {
    System.out.println(iter.next());
    }
    }
    }

    输出:

    Pluto
    Charon
    AndWan

    在上面的代码中,我们是这样来迭代集合的,我们先创建一个集合,然后往里面添加对象。然后通过集合的 iterator 方法来获得迭代器对象。然后用迭代器对象的 hasNext() 方法判断集合中是否存在下一个元素。

    在 Iterator 的 next() 之前,迭代器的索引位置是第一个元素之前,就像在 C 语言中的链表部分,我们都习惯在开始把指针指向链表的头部,而头部为空,头部的下一个元素就是链表的第一个元素。如果 hasNext() 方法返回了 flase,那么就表示已经到达了集合的末尾,终止对集合的遍历

    增强 for

    对于集合元素的遍历,我们还有一种方法叫做增强 for,也被成为 for each 循环,是一个高级的 for 循环,专门用来遍历数组和集合。它的实现原理也是上面我们说的迭代器。所以在遍历的过程中,我们不能对集合的元素进行增删操作

    格式:

    for(元素的数据类型 变量: Collection 集合或者数组) {
    //···
    }

    示例1(遍历集合):

    import java.util.Collection;
    import java.util.ArrayList;
    
    // 定义测试类
    public class Test {
    public static void main(String[] args) throws Exception {
    // 创建一个 ArrayList 对象
    Collection<String> list = new ArrayList<String>();
    // 添加元素
    list.add("Pluto");
    list.add("Charon");
    list.add("AndWan");
    
    for (String s: list) {
    System.out.println(s);
    }
    }
    }

    输出:

    Pluto
    Charon
    AndWan

    示例2(遍历数组):

    // 定义测试类
    public class Test {
    public static void main(String[] args) throws Exception {
    // 创建一个数组
    int[] intArrays = {1, 2, 3, 4, 5};
    
    // 使用增强 for 遍历集合元素
    System.out.print("[ ");
    for (int i: intArrays) {
    System.out.print(i + " ");
    }
    System.out.print(" ]");
    }
    }

    输出:

    [ 1 2 3 4 5  ]

    泛型

    在了解泛型前,先来看看下面这段代码

    import java.util.Collection;
    import java.util.ArrayList;
    import java.util.Iterator;
    
    // 定义测试类
    public class Test {
    public static void main(String[] args) throws Exception {
    // 创建一个 ArrayList 集合
    Collection list = new ArrayList();
    
    list.add("Pluto");
    list.add("AndWan");
    list.add(100);
    
    // 创建 list 的迭代器
    Iterator iter = list.iterator();
    
    while(iter.hasNext()) {
    System.out.println(iter.next());
    }
    }
    }

    上面,创建了一个集合,没有统一集合中数据的类型。有 String,也有 int 类型的。上面的代码,我们可以利用迭代器输出它。
    但如果我要先用一个变量存放每一个元素,然后再进行一些其他的操作的话,我就不知道到底要把这个变量设置成 int 类型还是 String 类型

    import java.util.Collection;
    import java.util.ArrayList;
    import java.util.Iterator;
    
    // 定义测试类
    public class Test {
    public static void main(String[] args) throws Exception {
    // 创建一个 ArrayList 集合
    Collection list = new ArrayList();
    
    list.add("Pluto");
    list.add("AndWan");
    list.add(100);
    
    // 创建 list 的迭代器
    Iterator iter = list.iterator();
    
    while(iter.hasNext()) {
    // 先用一个临时变量来存放当前元素
    String temp = iter.next();
    System.out.println(temp);
    }
    }
    }

    然而上面的代码报错了!!

    由于集合中什么类型的元素都可以存储。单只取出时强制转换时引发 ClassCastException 异常,遇到这种问题我们就可以利用泛型语法来解决它,说白了,泛型提前指定你要存储的数据类型,写在 <> 里面,没有一点的高大尚
    例如:

    Colletion<Integer> list = new ArrayList<Integer>();

    泛型:泛型就是可以在类或方法中预支地使用未知的类型

    Collection<String> list = new ArrayList<String>();

    Collection<String> list = new ArrayList<String>();

    ···
    等等的这些写法都是泛型,上面那些类就属于泛型类

    定义和使用含有泛型的类

    格式

    修饰符 class 类名<代表泛型的变量> {}

    ArrayList 集合是这样定义的

    class ArrayList<E> {
    public boolean add(E e){ ··· }
    
    public E get(int index) { ··· }
    
    ·····
    }

    上面的 E 就是我们的要确定的类型
    如:

    class ArrayList<String> {
    public boolean add(String e) { ··· }
    
    public String get(int index) { ··· }
    
    ······
    }

    我们也可以自定义泛型类

    // 定义自定义泛型类
    public class MyGenericClass<Example> {
    
    // 目前这里的 Example 类代表未知类,后期调用的时候传进来什么类型就是什么类型
    private Example example;
    
    public Example getExample() {
    return example;
    }
    
    public void setExample(Example example) {
    this.example = example;
    }
    }
    
    // 定义测试类
    public class Test {
    public static void main(String[] args) throws Exception {
    // 创建自己定义的泛型对象,传 String 类型
    MyGenericClass<String> genericExample1 = new MyGenericClass<String>();
    genericExample1.setExample("Pluto");
    System.out.println(genericExample1.getExample());
    
    // 创建 Integer 类型的对象
    MyGenericClass<Integer> genericExample2 = new MyGenericClass<Integer>();
    genericExample2.setExample(520);
    System.out.println(genericExample2.getExample());
    }
    }

    含有泛型的方法

    格式:

    修饰符 <代表泛型的变量> 返回值类型 方法名(参数) { ··· }

    下面我们自定义一个在方法中使用泛型的例子

    // 定义一个含有泛型方法的类
    public class MyGenericMethod {
    
    // 这里的 GenericExample 也代表一个未知类型,之后调用传进来什么就是什么类型
    public <GenericExample> void display(GenericExample genericExample) {
    System.out.println(genericExample);
    }
    
    // 带有返回值类型的泛型方法
    public <GenericExample> GenericExample getMethod(GenericExample genericExample) {
    return genericExample;
    }
    }
    
    // 定义测试类
    public class Test {
    public static void main(String[] args) throws Exception {
    // 创建一个刚才我们自定义的含有泛型的方法的对象
    MyGenericMethod genericMethod1 = new MyGenericMethod();
    genericMethod1.display("Pluto");
    
    System.out.println(genericMethod1.getMethod("Charon"));
    }
    }

    含有泛型的接口

    格式:

    修饰符 interface 接口名<代表泛型的变量> { ··· }

    定义一个含有泛型的接口

    // 定义一个含有泛型的接口
    public interface MyGenericInterface<E> {
    
    public abstract void add(E e);
    
    public abstract E getE(E e);
    }
    
    // 定义测试类
    public class Test {
    public static void main(String[] args) throws Exception {
    // 创建一个接口的对象并覆盖重写里面的抽象方法
    MyGenericInterface<String> genericInterfaceImpl = new MyGenericInterface<String>() {
    @Override
    public void add(String s) {
    System.out.println(s);
    }
    
    @Override
    public String getE(String s) {
    return s;
    }
    };
    
    genericInterfaceImpl.add("Charon");
    
    System.out.println(genericInterfaceImpl.getE("Charon"));
    }
    }

    泛型通配符

    泛型通配符:不知道用什么类型来接受的时候,都可以使用

    ?
    ,这个符号就表示未知通配符
    但要注意的是,我们在用集合的时候,我们只能接受数据,而不能往该集合中存储数据

    示例

    import java.util.Collection;
    import java.util.ArrayList;
    import java.util.Iterator;
    
    // 定义测试类
    public class Test {
    // 主函数
    public static void main(String[] args) throws Exception {
    Collection<String> list1 = new ArrayList<String>();
    list1.add("Pluto");
    list1.add("Charon");
    getElement(list1);
    
    Collection<Integer> list2 = new ArrayList<Integer>();
    list2.add(520);
    list2.add(360);
    getElement(list2);
    }
    
    // 接收位置类型的集合,并打印出来,再判断集合中的数据类型
    public static void getElement(Collection<?> list) {
    System.out.print(list.toString());
    Iterator<?> iter = list.iterator();
    if (iter.hasNext()){
    System.out.println( " 接收 " + iter.next().getClass().toString() + " 类型的集合!");
    }else {
    System.out.println("数据为空,无法判断集合中类型!");
    }
    }
    }

    输出:

    [Pluto, Charon] 接收 class java.lang.String 类型的集合!
    [520, 360] 接收 class java.lang.Integer 类型的集合!

    注意:泛型不存在继承关系,如下:

    Collection<Object> list = new ArrayList<String>();

    泛型通配符的高级使用

    在设置泛型的时候,我们还可以设置它的上限和下限,怎么理解呢?就是我们可以设置接收的类型必须是哪个类的子类(上限)或者必须是哪个类的父类(下限)

    示例(设置上限)

    import java.util.Collection;
    import java.util.ArrayList;
    import java.util.Iterator;
    
    // 定义测试类
    public class Test {
    public static void main(String[] args) throws Exception {
    Collection<String> list1 = new ArrayList<String>();
    Collection<Integer> list2 = new ArrayList<Integer>();
    
    getElement1(list1);     // 报错
    getElement1(list2);
    
    }
    
    // 定义一个方法,不做任何操作
    public static void getElement1(Collection<? extends Number> list) {}
    
    }

    上面这段代码中,我们在定义方法

    getElement1
    的时候,接收未知类型的集合,但是这个集合类型必须是 Number 类或继承自 Number,因为 Integer 类是 Number 的子类,所以我们接收了 Integer 会正确执行,但接收了 String 类型却报错的原因

    示例2(设置下限)

    import java.util.Collection;
    import java.util.ArrayList;
    import java.util.Iterator;
    
    // 定义测试类
    public class Test {
    public static void main(String[] args) throws Exception {
    Collection<Integer> list1 = new ArrayList<Integer>();
    Collection<Number> list2 = new ArrayList<Number>();
    Collection<Object> list3 = new ArrayList<Object>();
    
    getElement1(list1);     // 报错
    getElement1(list2);
    getElement1(list3);
    
    }
    
    // 定义一个方法,不做任何操作
    public static void getElement1(Collection<? super Number> list) {}
    }

    上面这段代码中,我们接收一个未知类型的集合,但是这个集合必须是 Number 类或者是 Number 类的父类。Integer 类是 Number 类的子类,所以报错。但 Object 类是一切类的父类,所以不会报错

    案例(三个人轮流摸扑克牌)

    import java.util.Collection;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Iterator;
    
    // 定义测试类
    public class Test {
    public static void main(String[] args) throws Exception {
    // 存储牌的序号
    ArrayList<String> cardNumber = new ArrayList<String>();
    // 存储牌的花色
    ArrayList<String> cardColor = new ArrayList<String>();
    // 存储所有牌
    ArrayList<String> cards = new ArrayList<String>();
    
    // 添加所有牌的序号
    for (int i = 2; i <= 10; i++) {
    cardNumber.add(i + "");     // i 为整型,通过加上一个空字符串,自动转型为 String 类型
    }
    cardNumber.add("J");
    cardNumber.add("Q");
    cardNumber.add("K");
    cardNumber.add("A");
    
    // 添加牌的花色
    cardColor.add("♠");     // 黑桃
    cardColor.add("♥");     // 红心
    cardColor.add("♦");     // 方块
    cardColor.add("♣");     // 梅花
    
    // 组合牌
    for (String cor: cardColor) {
    for (String num: cardNumber) {
    cards.add(cor + num);
    }
    }
    
    // 把小鬼和大鬼添加进牌里面
    cards.add("小☺");
    cards.add("大☺");
    
    // 把牌里面的索引打乱
    Collections.shuffle(cards);
    
    // 创建三个玩家来存储摸到的牌
    Collection<String> player1 = new ArrayList<String>();
    Collection<String> player2 = new ArrayList<String>();
    Collection<String> player3 = new ArrayList<String>();
    // 存储底牌,最后的三张牌
    Collection<String> finalCards = new ArrayList<String>();
    
    // 摸牌
    for (int i = 0; i < cards.size(); i++) {
    // 如果牌只剩三张的话,就放在底牌中
    if (i >= 51) {
    finalCards.add(cards.get(i));
    }else {
    // 三个玩家轮流摸牌
    if (i % 3 == 0)
    player1.add(cards.get(i));
    else if (i % 3 == 1)
    player2.add(cards.get(i));
    else
    player3.add(cards.get(i));
    }
    }
    
    // 看看各个玩家摸到的牌
    System.out.println("玩家1:" + player1 + " ,共 " + player1.size() + " 张牌");
    System.out.println("玩家2:" + player2 + " ,共 " + player2.size() + " 张牌");
    System.out.println("玩家3:" + player3 + " ,共 " + player3.size() + " 张牌");
    System.out.println("底牌:" + finalCards + " ,共 " + finalCards.size() + " 张牌");
    
    }
    
    }

    输出:

    玩家1:[♠8, ♥6, ♠K, ♠A, ♦J, 小☺, ♦5, ♣Q, ♥2, ♠2, ♦3, ♦Q, ♣7, ♣4, ♣K, ♠Q, ♦8] ,共 17 张牌
    玩家2:[♣A, ♣3, ♣9, ♠J, ♥K, ♦10, ♥9, ♠3, ♦7, 大☺, ♥3, ♦A, ♥4, ♥J, ♣10, ♥7, ♠4] ,共 17 张牌
    玩家3:[♣5, ♠6, ♠7, ♥8, ♦6, ♦2, ♥10, ♥A, ♠9, ♠5, ♥Q, ♣J, ♥5, ♠10, ♦4, ♦K, ♣6] ,共 17 张牌
    底牌:[♦9, ♣2, ♣8] ,共 3 张牌

    List 集合

    在上面,我们讲了 Collection 接口的使用,现在来看看他的两个常用子类

    java.util.List
    java.util.Set
    java.util.List
    java.util.Set
    接口继承自
    java.util.Collection

    我们习惯将实现了 List 接口的对象成为 List 集合。List 集合是一种允许出现重复元素的集合,以线性方式存储,在程序中可以通过索引来访问集合中的指定元素。List 还是一种有序的集合,即元素的存入顺序和取出顺序一致

    常用方法:

    public void add(int index, E element)
    :将指定的元素,添加到该集合中的指定位置
    public E get(int index)
    :返回集合中指定位置的元素
    public E remove(int index)
    :溢出列表中指定位置的元素,返回的是被移除的元素
    public E set(int index, E element)
    :用指定的元素替换集合中指定位置的元素,返回值的更新前的元素

    java.util.List
    的子类

    ArrayList 集合

    java.util.ArrayList
    集合数据存储的结构树数组结构,元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据、所以 ArrayList 是最常用的集合

    但是我们不能随意的使用 ArrayList 集合来完成任何需求,这种是不严谨的,不提倡这种用法

    前面我们使用的都是 ArrayList,这里就不多说

    LinkedList 集合

    java.util.LinkedList
    集合数据存储的结构是链表结构。方便元素添加,删除

    LinkedList 是一个双向链表,在数据结构中,我们有单链表和双链表,单链表只有一个指向下一个节点的指针,而双链表除了有一个指向下一个节点的指针还有一个指向前一个节点的指针

    常用方法

    public void addFirst(E e)
    :将指定元素插入此列表的开头
    public void addLast(E e)
    :将指定的元素添加到此列表的结尾
    public E getFirst()
    :返回此列表的第一个元素
    public E getLast()
    :返回此列表的最后一个元素
    public E removeFirst()
    :移除并返回此列表的第一个元素
    public E removeLast()
    :移除并返回此列表的最后一个元素
    public E pop()
    :从此列表所表示的堆栈处弹出一个元素
    public void push(E e)
    :将元素推入此列表所表示的堆栈
    public boolean isEmpty()
    :如果列表为空,返回 true

    示例

    import java.util.LinkedList;
    
    public class Test {
    
    public static void main(String[] args) {
    // 创建一个 LinkedList 对象
    LinkedList<String> link = new LinkedList<String>();
    
    // 往头部添加元素
    link.addFirst("a");
    link.addFirst("b");
    link.addFirst("c");
    System.out.println(link);
    
    link.addLast("1");
    System.out.println(link);
    
    // 删除元素
    System.out.println("删除第一个元素");
    link.removeFirst();
    System.out.println(link);
    System.out.println("删除最后一个元素");
    link.removeLast();
    System.out.println(link);
    
    // 不断弹出栈顶元素
    while (! link.isEmpty())
    link.pop();
    System.out.println(link);
    }
    }

    输出:

    [c, b, a]
    [c, b, a, 1]
    删除第一个元素
    [b, a, 1]
    删除最后一个元素
    [b, a]
    []

    Set 集合

    Set 集合里面的元素无序,并且都会以某种规则保证存入的元素不会出现重复

    HashSet 集合介绍

    java.util.HashSet
    是 Set 接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的。
    java.util.HashSet
    其实是一个
    java.util.HashMap
    支持

    HashSet
    是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。内部保证元素唯一性的方式依赖于:
    HasCode
    equals
    方法

    特点:
    1、不允许存储重复的元素
    2、没有索引,没有带索引的方法,也不能使用普通的 for 循环
    3、是一个无序的集合,存储元素和取出元素的顺序有可能不一致
    4、底层是一个哈希表结构(查询的速度非常的快)

    示例

    import java.util.HashSet;
    
    public class Test {
    
    public static void main(String[] args) {
    // 创建一个 HashSet 集合
    HashSet<String> set = new HashSet<String>();
    
    set.add("abc");
    set.add("123");
    set.add("abc");
    
    System.out.println(set);
    }
    }

    输出:

    [123, abc]

    哈希值
    哈希值是一个十进制的整数,由系统随机给出(就是对象的地址值,只不过这里是十进制表示,它是一个逻辑地址,是模拟出来的地址,不是数据实际存储的物理地址)

    在 Object 类中有一个方法

    hashCode()
    可以获取对象的哈希码值
    这个方法的源码如下:

    public native int hashCode();

    上面的 native 代表该方法调用的是本地操作系统的方法

    获取对象的哈希值

    public class Person {
    private String name;
    private int age;
    
    public Person() {}
    
    public Person(String name, int age) {
    this.name = name;
    this.age = age;
    }
    
    public String getName() {
    return name;
    }
    
    public void setName(String name) {
    this.name = name;
    }
    
    public int getAge() {
    return age;
    }
    
    public void setAge(int age) {
    this.age = age;
    }
    }
    
    // 定义测试类
    public class Test {
    
    public static void main(String[] args) {
    Person p1 = new Person();
    Person p2 = new Person();
    
    System.out.println(p1.hashCode());
    System.out.println(p2.hashCode());
    }
    }

    输出:

    1355531311
    1967205423

    我们之前的 toString 方法,则是返回对象的十六进制的哈希值

    public class Test {
    
    public static void main(String[] args) {
    Person p1 = new Person();
    Person p2 = new Person();
    
    System.out.println(p1.toString());
    System.out.println(p2.toString());
    }
    }

    输出:

    cn.livekeys.demo09.Person@75412c2f
    cn.livekeys.demo09.Person@282ba1e

    注意:
    对于字符串对象而言,它重写了 hashCode 方法,有些不同字符串的哈希值可能相同,原理可以参考 String 中 hashCode 的方法

    HashSet 集合存储数据的结构(哈希表)

    在 jdk 1.8 之前,哈希表 = 数组 + 链表
    在 jdk 1.8 之后,哈希表 = 数组 + 链表 + 红黑树(提高查询的速度)

    数组:根据元素的哈希值进行分组,相同哈希值的元素在一组
    链表:把在相同组的元素用链表链接起来
    红黑树:如果链表的长度超过 8 个的话,就把链表转换为红黑树,提高查询速度

    Set 集合的 add 方法,会调用 hashCode 方法和 equals 方法来判断元素是否重复,如果重复,就不会把元素存储到集合当去,不重复,则存储集合当中去。
    前提:必须重写 hashCode 方法和 equals 方法

    HashSet 存储自定义类型元素
    重写 toString,hashCodee 和 equals 方法

    import java.util.Objects;
    
    public class Person {
    private String name;
    private int age;
    
    public Person() {
    }
    
    public Person(String name, int age) {
    this.name = name;
    this.age = age;
    }
    
    @Override
    public String toString() {
    return "Person{" +
    "name='" + name + '\'' +
    ", age=" + age +
    '}';
    }
    
    @Override
    public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Person person = (Person) o;
    return age == person.age &&
    Objects.equals(name, person.name);
    }
    
    @Override
    public int hashCode() {
    return Objects.hash(name, age);
    }
    
    public String getName() {
    return name;
    }
    
    public void setName(String name) {
    this.name = name;
    }
    
    public int getAge() {
    return age;
    }
    
    public void setAge(int age) {
    this.age = age;
    }
    }
    
    // 定义测试类
    import java.util.HashSet;
    
    public class Test {
    
    public static void main(String[] args) {
    Person p1 = new Person("Pluto", 22);
    Person p2 = new Person("Pluto", 22);
    Person p3 = new Person("Charon", 22);
    
    HashSet<Person> set = new HashSet<Person>();
    set.add(p1);
    set.add(p2);
    set.add(p3);
    System.out.println(set);
    }
    }

    输出:

    [Person{name='Charon', age=22}, Person{name='Pluto', age=22}]

    LinkedHashSet 集合

    java.util.LinkedHashSet
    集合继承自
    HashSet
    集合

    特点:
    底层是一个哈希表(数组 + 链表 / 红黑树)+ 链表,最后那个链表记录元素存储的顺序,保证元素有序

    import java.util.HashSet;
    import java.util.LinkedHashSet;
    
    public class Test {
    
    public static void main(String[] args) {
    // 创建一个 HashSet 对象
    HashSet<String> set = new HashSet<String>();
    set.add("www");
    set.add("abc");
    set.add("abc");
    set.add("Pluto");
    System.out.println("HashSet 存储:" + set);
    
    // 创建一个 LinkedHashSet
    LinkedHashSet<String> linked = new LinkedHashSet<String>();
    linked.add("www");
    linked.add("abc");
    linked.add("abc");
    linked.add("Pluto");
    System.out.println("LinkedHashSet 存储:" + linked);
    }
    }

    输出:

    HashSet 存储:[abc, www, Pluto]
    LinkedHashSet 存储:[www, abc, Pluto]

    上面的代码中,可以看到,HashSet 是无序的,没有重复的元素。LinkedHashSet 是有序的,也是没有重复的元素

    可变参数

    jdk 1.5 之后出现的新特性,使用前提是:当方法的参数列表数据类型确定,个数不确定的时候,就可以使用可变参数

    格式:

    修饰符 返回值类型 方法名(数据类型...变量名) {}

    可变参数的原理:
    可变参数的底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数。传递参数的个数可以使 0 个或多个

    示例

    public class Test {
    
    public static void main(String[] args) {
    int all = sum(10, 4, 5, 6, 6);
    System.out.println(all);
    }
    
    // 定义一个方法,用来求和
    public static int sum(int...arr) {
    int sum = 0;
    for (int temp: arr) {
    sum += temp;
    }
    return sum;
    }
    }

    注意:
    1、一个方法的参数列表,只能有一个可变参数
    2、如果方法的参数有多个,那么可变参数必须写在参数列表的末尾

    在写可变参数的时候,我们还可以这样写

    public static void method(Object...obj){}

    这样的话,就可以接收任意类型的数据了,如下:

    import java.util.Arrays;
    
    public class Test {
    
    public static void main(String[] args) {
    method("pluto", 22, "Charon");
    }
    
    public static void method(Object...obj) {
    System.out.println(Arrays.toString(obj));
    }
    }

    输出:

    [pluto, 22, Charon]

    Collections 工具类

    java.util.Collections
    是集合工具类,用来对集合进行操作

    常用方法

    public static <T> boolean addAll(Collection<T> c, T... elements)
    :往集合里添加一些元素
    public static void shuffle(List<T> list)
    :打乱集合顺序
    public static <T> void sort(List<T> list)
    :将集合元素按照默认规则排序
    public static <T> void sort(List<T> list, Comparator<? super T>)
    :将集合中元素按照指定规则排序

    注意:
    上面传进去的参数只能是 List 集合

    简单使用

    示例1:

    import java.util.Collections;
    import java.util.Collection;
    import java.util.ArrayList;
    
    public class Test {
    
    public static void main(String[] args) {
    Collection<String> list1 = new ArrayList<String>();
    list1.add("a");
    list1.add("b");
    list1.add("c");
    list1.add("d");
    System.out.println(list1);
    
    Collection<String> list2 = new ArrayList<String>();
    Collections.addAll(list2, "a", "b", "c", "d");
    System.out.println(list2);
    }
    
    }
    [a, b, c, d]
    [a, b, c, d]

    示例2:

    import java.util.Collections;
    import java.util.ArrayList;
    
    public class Test {
    
    public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<String>();
    Collections.addAll(list, "a", "b", "c", "d", "e");
    System.out.println("打乱前:" + list);
    Collections.shuffle(list);
    System.out.println("打乱后:" + list);
    
    System.out.println("\n将集合按照默认规则排序:");
    Collections.sort(list);
    System.out.println("排序后:" + list);
    
    }
    
    }

    输出:

    打乱前:[a, b, c, d, e]
    打乱后:[e, b, c, d, a]
    
    将集合按照默认规则排序:
    排序后:[a, b, c, d, e]

    重写默认比较的规则

    我们如果要实现按照指定规则进行排序,那么被排序的集合里面存储的元素,必须实现 Comparator,重写接口中的 compareTo 定义排序的规则

    示例:(按照年龄升序排序)

    public class Person implements Comparable<Person>{
    private String name;
    private int age;
    
    public Person() {
    }
    
    public Person(String name, int age) {
    this.name = name;
    this.age = age;
    }
    
    @Override
    public String toString() {
    return "Person{" +
    "name='" + name + '\'' +
    ", age=" + age +
    '}';
    }
    
    public String getName() {
    return name;
    }
    
    public void setName(String name) {
    this.name = name;
    }
    
    public int getAge() {
    return age;
    }
    
    public void setAge(int age) {
    this.age = age;
    }
    
    // 重写排序的规则
    @Override
    public int compareTo(Person o) {
    return this.getAge() - o.getAge();
    }
    }
    
    // 定义测试类
    import java.util.Collections;
    import java.util.ArrayList;
    
    public class Test {
    
    public static void main(String[] args) {
    Person p1 = new Person("Pluto", 17);
    Person p2 = new Person("Charon", 15);
    Person p3 = new Person("Alex", 25);
    ArrayList<Person> list = new ArrayList<Person>();
    Collections.addAll(list, p1, p2, p3);
    System.out.println(list);
    
    Collections.sort(list);
    System.out.println(list);
    }
    
    }

    输出:

    [Person{name='Pluto', age=17}, Person{name='Charon', age=15}, Person{name='Alex', age=25}]
    [Person{name='Charon', age=15}, Person{name='Pluto', age=17}, Person{name='Alex', age=25}]

    当然,如果你要进行降序排列的话,那么规则你就应该写成

    return o.getAge() - this.getAge()

    按照指定规则排序

    Comparable
    Comparator
    的区别
    Comparable
    :自己(this)和别人(参数)比较,自己需要实现 Comparable 接口,重写比较的方法 CompareTo 方法
    Comparator
    :相当于找一个第三方的裁判,来比较它们

    public class Person implements Comparable<Person>{
    private String name;
    private int age;
    
    public Person() {
    }
    
    public Person(String name, int age) {
    this.name = name;
    this.age = age;
    }
    
    @Override
    public String toString() {
    return "Person{" +
    "name='" + name + '\'' +
    ", age=" + age +
    '}';
    }
    
    public String getName() {
    return name;
    }
    
    public void setName(String name) {
    this.name = name;
    }
    
    public int getAge() {
    return age;
    }
    
    public void setAge(int age) {
    this.age = age;
    }
    
    // 重写排序的规则
    @Override
    public int compareTo(Person o) {
    return this.getAge() - o.getAge();
    }
    }
    
    // 定义测试类
    import java.util.Collections;
    import java.util.ArrayList;
    import java.util.Comparator;
    
    public class Test {
    
    public static void main(String[] args) {
    ArrayList<Person> list = new ArrayList<Person>();
    list.add(new Person("Pluto", 16));
    list.add(new Person("Charon", 20));
    list.add(new Person("Alex", 13));
    
    System.out.println(list);
    
    Collections.sort(list, new Comparator<Person>() {
    @Override
    public int compare(Person o1, Person o2) {
    return o1.getAge() - o2.getAge();
    }
    });
    
    System.out.println(list);
    }
    
    }

    输出:

    [Person{name='Pluto', age=16}, Person{name='Charon', age=20}, Person{name='Alex', age=13}]
    [Person{name='Alex', age=13}, Person{name='Pluto', age=16}, Person{name='Charon', age=20}]

    多规则的定义(如果年龄相同,则按照名字的首字母排序)

    import java.util.Collections;
    import java.util.ArrayList;
    import java.util.Comparator;
    
    public class Test {
    
    public static void main(String[] args) {
    ArrayList<Person> list = new ArrayList<Person>();
    list.add(new Person("Pluto", 16));
    list.add(new Person("Charon", 20));
    list.add(new Person("AndWan", 20));
    list.add(new Person("Alex", 13));
    
    System.out.println(list);
    
    Collections.sort(list, new Comparator<Person>() {
    @Override
    public int compare(Person o1, Person o2) {
    int result = o1.getAge() - o2.getAge();
    if (result == 0)
    result = o1.getName().charAt(0) - o2.getName().charAt(0);
    return result;
    }
    });
    
    System.out.println(list);
    }
    
    }

    输出:

    [Person{name='Pluto', age=16}, Person{name='Charon', age=20}, Person{name='AndWan', age=20}, Person{name='Alex', age=13}]
    [Person{name='Alex', age=13}, Person{name='Pluto', age=16}, Person{name='AndWan', age=20}, Person{name='Charon', age=20}]

    本文章是学习时记录下的笔记,如有错误的地方,请留言指正

    • 点赞
    • 收藏
    • 分享
    • 文章举报
    ilblogs 发布了23 篇原创文章 · 获赞 0 · 访问量 336 私信 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: 
    相关文章推荐