Java SE集合部分--16.List接口、Set接口、Collections集合工具类

版权声明:转载请注明原始链接 https://blog.csdn.net/sswqzx/article/details/82869925

学习目标

List集合

数据结构

Set接口

Collections

一、List接口

1、概述

java.util.List 接口继承自Collection 接口、有序可重复

List接口实现类、ArrayList、LinkedList

常用方法:

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

 演示:

package com.blog.test;

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

public class Test {
    public static void main(String[] args) {
        // 创建List集合对象
        List<String> list = new ArrayList<String>();
// 往 尾部添加 指定元素
        list.add("小亚");
        list.add("小天");
        list.add("不高兴");
        System.out.println(list);
// add(int index,String s) 往指定位置添加
        list.add(1,"没头脑");
        System.out.println(list);
// String remove(int index) 删除指定位置元素 返回被删除元素
// 删除索引位置为2的元素
        System.out.println("删除索引位置为2的元素");
        System.out.println(list.remove(2));
        System.out.println(list);
        list.set(0, "三毛");
        System.out.println(list);
// String get(int index) 获取指定位置元素
// 跟size() 方法一起用 来 遍历的
        for(int i = 0;i<list.size();i++){
            System.out.println(list.get(i));
        }
//还可以使用增强for
        for (String string : list) {
            System.out.println(string);
        }
    }
}

2、ArrayList

说明java.util.ArrayList 集合数据存储的结构是数组结构。

特点:增删慢,查找快,
常用方法:

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

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

public class Test {
    public static void main(String[] args) {
        // List 接口接收.
        List<String> list = new ArrayList<String>();
        list.add("张三");
        list.add("李四");
        list.add("王五");

        // 1. add(int index, E e);
        // 需求 : 将 `赵六` 添加到张三后面
        list.add(1, "赵六");

        // 2. remove(int index);
        // 需求 : 删除王五
        list.remove(3);

        // 3. set(int index, E e);
        // 需求 : 将李四修改为田七
        list.set(2, "田七");

        // 4. get(int index);
        // 需求 : 查询 1 元素
        String name = list.get(1);
        System.out.println(name);

        System.out.println("list = " + list);

        // 遍历 List 集合  (size + get)
        for (int i = 0; i < list.size(); i++) {
            String n = list.get(i);
            System.out.println("n = " + n);
        }

    }
}

3、LinkedList

说明:java.util.LinkedList 集合数据存储的结构是双向链表结构增删快、查询慢

头尾操作:

常用方法:

1.	addFirst(E e);  将元素添加到链表的开头.
2.	addLast(E e);   将元素添加到链表的结尾.
3.	getFirst(E e);  获取链表头部的元素.
4.	getLast(E e);   获取链表的尾部元素.
5.	removeFirst(E e); 删除链表的头部元素.
6.	removeLast(E e);  删除链表的尾部元素.
7.   public E pop() :从此列表所表示的堆栈处弹出一个元素。
8.    public void push(E e) :将元素推入此列表所表示的堆栈。
9.    public boolean isEmpty() :如果列表不包含元素,则返回true。

演示:

package com.blog.test;

import java.util.LinkedList;

public class Test {
    public static void main(String[] args) {
        LinkedList<String> link = new LinkedList<String>();
//添加元素
        link.addFirst("abc1");
        link.addFirst("abc2");
        link.addLast("abc3");
        System.out.println(link);
// 获取元素
        System.out.println(link.getFirst());
        System.out.println(link.getLast());
// 删除元素
        System.out.println(link.removeFirst());
        System.out.println(link.removeLast());
        System.out.println(" = ==");
        while (!link.isEmpty()) { //判断集合是否为空
            System.out.println(link.pop()); //弹出集合中的栈顶元素
        }
        System.out.println(link);

    }
}

二、Java中的数据结构

1、线性表

线性表:`内存地址连续`、ArrayList 数组列表集合底层就是数组结构. 数组结构也被称为 `线性表`

特点:增删慢,查找快

2、单链表结构

单链表:由一系列结点node组成,一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域

特点:查询慢  增删快

HashSet:为单链表(底层是由HashMap支持的)

3、双链表结构

双链表:由一系列结点node组成,

一个是存储上一个结点的指、

一个是存储数据元素的数据域,

另一个是存储下一个结点地址的指针域

图解:LinkedList为双链表结构

4、栈结构(先进后出)

栈:stack,又称堆栈,它是运算受限的线性表,仅允许在一端进行插入和删除操作

压栈:push、就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置。
弹栈:pop、就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。

5、队列结构(先进先出)

队列:queue,它同堆栈一样,也是受限的线性表,仅允许在表的一端进行插入,另一端进行删除。

package com.blog.test;

import java.util.LinkedList;
public class Test {
    public static void main(String[] args) {
        LinkedList<String> link = new LinkedList<String>();
        link.offer("aaa");
        link.offer("bbb");
        link.offer("ccc");

        System.out.println("link = " + link);
        
        while (!link.isEmpty()){
            String poll = link.poll();
            System.out.println("poll = " + poll);
        }

    }
}

 

6、红黑树结构

二叉树:binary tree ,是每个结点不超过2的有序树(tree)TreeSet集合

三、Set接口

1、概述

java.util.Set 接口和java.util.List 接口一样,同样继承自Collection 接口

Set 接口中元素,无序,不重复。

Set 集合有多个子类,这里我们介绍其中的java.util.HashSet 、java.util.LinkedHashSet 

2、HashSet

java.util.HashSet 是Set 接口的一个实现类,无序,不重复

java.util.HashSet 底层的实现其实是一个java.util.HashMap 支持

public class HashSetDemo {
public static void main(String[] args) {
//创建 Set集合
HashSet<String> set = new HashSet<String>();
//添加元素
set.add(new String("cba"));
set.add("abc");
set.add("bac");
set.add("cba");
//遍历
for (String name : set) {
System.out.println(name);
}
}
}

 

HashSet集合存储结构是哈希表、JDK1.8以后、希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树

3、 需求 : 存储自定义对象

说明:只要想 Hash 表中存储自定义对象, 那么该自定义对象所属的类就必须重写 `hashCode + equals` 方法.

类必须重写 Object 类的 hashCode 方法, 实现根据 Student 对象的数据内容来计算哈希值, 如果数据相同, 计算的哈希值就应该相同.

关于 HashCode 方法的说明 :

public class HashCodeStudentTest2 {
    public static void main(String[] args) {

        int hashCode1 = new Student("张三", 18).hashCode();
        int hashCode2 = new Student("张三", 18).hashCode();

        System.out.println("hashCode1 = " + hashCode1);
        System.out.println("hashCode2 = " + hashCode2);

        // 请问 : 为什么 String 类计算出来的 `哈希值` 是一样的 ???
        // 解答 : 因为 String 类重写了 Object 类的 `hashCode` 方法.

        int hashCode3 = "张三".hashCode();
        int hashCode4 = "张三".hashCode();
        System.out.println("hashCode3 = " + hashCode3);
        System.out.println("hashCode4 = " + hashCode4);

        int hashCode5 = new String("张三").hashCode();
        int hashCode6 = new String("张三").hashCode();
        System.out.println("hashCode5 = " + hashCode5);
        System.out.println("hashCode6 = " + hashCode6);
    }
}

手动重写 hashCode 与 equals 方法 :

// hashCode 方法 (数据相同, 哈希值就应该相同)
@Override
public int hashCode() {
    // 数据 (name, age)
    return age + name.hashCode();   // age + 字符串哈希方法的返回值   18 + 774889  -> 774907
}

// equals 方法
@Override
public boolean equals(Object obj) {
    // System.out.println("Student 类的 equals 方法被调用...");  测试
    if (this == obj) return true;
    if (obj == null || getClass() != obj.getClass()) return false;
    Student stu = (Student) obj;
    return age == stu.age && Objects.equals(name, stu.name);
}

Student 类的完整代码 :

public class Student {
    // 属性
    private String name;
    private int age;

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public String toString() {
        return "Student{" +
                "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;
    }
}

测试代码:

public class HashSetStudentTest {
    public static void main(String[] args) {

        HashSet<Student> set = new HashSet<>();

        // 存储元素
        set.add(new Student("张三", 18));
        set.add(new Student("李四", 28));
        set.add(new Student("王五", 19));
        set.add(new Student("赵六", 20));
        set.add(new Student("张三", 18));
        set.add(new Student("李四", 28));
        set.add(new Student("王五", 19));
        set.add(new Student("赵六", 20));

        // 遍历
        for (Student stu : set) {
            System.out.println(stu);
        }
    }
}

4、LinkedHashSet

具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。

public class LinkedHashSetDemo {
public static void main(String[] args) {
Set<String> set = new LinkedHashSet<String>();
set.add("bbb");
set.add("aaa");
set.add("abc");
set.add("bbc");
Iterator<String> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
结果:
bbb
aaa
abc
bbc

5、可变参数

格式:

修饰符 返回值类型 方法名(参数类型... 形参名){ }
public class VariableArgumentsTest1 {
    public static void main(String[] args) {

        int[] arr = {10, 20, 30, 40, 50};
        int sum = getSum(arr);
        System.out.println("sum = " + sum);

        int sum1 = getSum(10, 20, 30, 40, 50);
        System.out.println("sum1 = " + sum1);
    }

    // 需求 : 定义一个方法, 获取多个整形的累加和
    // 说明 : 可变参数底层就是 `数组`.
    // 注意点 : 可变参数必须是参数列表的 `最后一个参数`.
    // Vararg (可变参数) parameter (形参) must be the last in the list (在参数列表中)
    public static int getSum(int... array) {
        int sum = 0;
        for (int i = 0; i < array.length; i++) {
            sum += array[i];
        }
        return sum;
    }

    /*public static int getSum(int[] array) {
        int sum = 0;
        for (int i = 0; i < array.length; i++) {
            sum += array[i];
        }
        return sum;
    }*/
}

四、Collections集合工具类

1、概述

java.utils.Collections 是集合工具类、工具类中的方法基本全部都是静态的, 因此, 直接可以实用类名调用.

2、常用方法

1.	shuffle(List list); 将集合中的元素进行随机置换.
2.	addAll(Collection<? super T> c, T… elements);  将可变参数的元素添加指定的集合中.
3.	max(Collection c);  获取集合中元素的最大值.
4.	min(Collection c);  获取集合中元素的最小值.
5.	reverse(Collection c); 集合中元素的反转.
6.	sort(List<T extends Comparables> list); 按照元素的 `自然规则` 规则实现元素排序.
7.	sort(List<T> list, Comparator<T> c); 按照元素的 `比较器规则` 规则实现元素排序.

演示:

package com.blog.test;

import java.util.ArrayList;
import java.util.Collections;

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();

        // 1.  addAll(Collection<? super T> c, T… elements);  将可变参数的元素添加指定的集合中.
        Collections.addAll(list, 10, 20, 30, 40, 50, 60, 70, 80, 90);
        System.out.println("list = " + list);

        // 2.  shuffle(List list); 将集合中的元素进行随机置换.
        Collections.shuffle(list);
        System.out.println("list = " + list);

        ArrayList<Integer> list2 = new ArrayList<>();
        Collections.addAll(list2, 66, 967, 34, 45, 44, 55);
        System.out.println("list2 = " + list2);

        // 3.  max(Collection c);  获取集合中元素的最大值.
        Integer max = Collections.max(list2);
        System.out.println("max = " + max);

        // 4.  min(Collection c);  获取集合中元素的最小值.
        Integer min = Collections.min(list2);
        System.out.println("min = " + min);
        
        // 5. sort 排序
        // [33, 55, 66, 77, 88, 99]
        // 比较 : Integer 自然排序 (Comparable<Integer>)
        Collections.sort(list2);        // 排序: 底层就是集合中元素交互.
        System.out.println("list2 = " + list2);

        // 6.  reverse(Collection c); 集合中元素的反转.
        Collections.reverse(list2);
        System.out.println("list2 = " + list2);
    }
}

排序底层实现的交互 :

3、Comparable自然排序

字符串的自然排序 : 字典顺序 (a ~ z)

说明 : 要求 List 集合中的 T 元素类型, 必须继承自 Comparable 接口. 之前使用 Integer, String 类不报错, 因为这两个类继承了 Comparable 接口.

package com.blog.test;

import java.util.ArrayList;
import java.util.Collections;

public class Test {
    public static void main(String[] args) {
        // 查看字符串本身的排序规则 :  (自然排序)  Comparable<String>
        ArrayList<String> list = new ArrayList<>();
        list.add("Lucy");
        list.add("Tom");
        list.add("Java");
        list.add("Jack");
        list.add("php");
        list.add("Jerry");
        list.add("linux");
        list.add("TeBaoBao");
        // 排序
        Collections.sort(list);

        for (String name : list) {
            System.out.println(name);
        }
    }
}

4、Comparator比较器排序

字符串的自定义排序 :

说明 : 此方法对集合中的 T 类型没有要求, 但是, 第二个参数需要传递一个 Comparator 接口类型的参数.

package com.blog.test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Test {
    public static void main(String[] args) {
        // 查看字符串本身的排序规则 :  (自然排序)  Comparable<String>
        ArrayList<String> list = new ArrayList<>();
        list.add("Lucy");
        list.add("Tom");
        list.add("Java");
        list.add("Jack");
        list.add("php");
        list.add("Jerry");
        list.add("linux");
        list.add("TeBaoBao");
        // 比较器排序 / 整体排序
        // 第二个参数类型为 : Comparator 接口类型
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                /*
                结果1 : o1 比 o2 对象大.      正数 (小 -> 大)
                结果2 : o1 比 o2 对象小.      负数 (大 -> 小)
                结果2 : o1 和 o2 相等.        原来的顺序
                 */
                // 字符串长度 : o1.length() - o2.length();
                return o1.length() - o2.length();
            }
        });

        for (String name : list) {
            System.out.println(name);
        }

    }
}

5、自定义排序

说明 : 创建一个学生类,存储到ArrayList集合中完成指定排序操作。

实现方式一 : 自然排序

Student 类 :

public class Student implements Comparable<Student> {
    // 属性
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "Student{" +
                "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(Student o) {
        // 规则 : 1. 先按年龄 (从小到大)   2. 如果年龄相同 (姓名, 自然排序)
        // 步骤一 : 年龄
        int result = this.age - o.age;
        // 步骤二 : 判断年龄是否相同
        if (result == 0) {
            // 步骤三 : 根据姓名, 实现自然排序 (String -> Comparable 接口中的抽象方法为 compareTo)
            result = this.name.compareTo(o.name);
        }
        // 步骤四 : 返回结果
        return result;
    }
}

测试类 :

package com.blog.test;

import java.util.ArrayList;
import java.util.Collections;

public class Test {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();

        list.add(new Student("Jack", 18));
        list.add(new Student("Rose", 19));
        list.add(new Student("Peter", 16));
        list.add(new Student("Ann", 15));
        list.add(new Student("Tom", 18));
        list.add(new Student("Jim", 19));
        list.add(new Student("Lily", 16));
        list.add(new Student("Jan", 15));

        // 方式一 : 自然排序
        Collections.sort(list);

        // 遍历
        for (Student stu : list) {
            System.out.println(stu);
        }
    }
}

实现方式二 : 比较器排序

Student 类 :

package com.blog.test;

public class Student {
    // 属性
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "Student{" +
                "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;
    }
}

测试类 : 

package com.blog.test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Test {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();
        list.add(new Student("Jack", 18));
        list.add(new Student("Rose", 19));
        list.add(new Student("Peter", 16));
        list.add(new Student("Ann", 15));
        list.add(new Student("Tom", 18));
        list.add(new Student("Jim", 19));
        list.add(new Student("Lily", 16));
        list.add(new Student("Jan", 15));

        // 方式二 : 比较器排序
        Collections.sort(list, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                int result = o1.getAge() - o2.getAge();
                if (result == 0) {
                    result = o1.getName().compareTo(o2.getName());
                }
                return result;
            }
        });
        // 遍历
        for (Student stu : list) {
            System.out.println(stu);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/sswqzx/article/details/82869925