一、集合框架

1、单列集合Collection

集合的内部很多利用的就是数组,主要是为了方便数据的增删改查。

  • 集合只能存储引用类型的数据。
  • 引用类型变量实际上存储的是对象的地址,集合中实际上只存储了元素对象在堆中的地址。
  • 单列集合Collection接口有List、Set、Queue三个子接口。

Collection接口

Collection接口的主要方法

主要方法

add()方法示例:
/**
 * @document: add()方法 往集合中添加一个元素
 * @Author:SmallG
 * @CreateTime:2023/8/4+14:21
 */

public class Demo01 {
    public static void main(String[] args) {
        //创建集合对象 接口不能实例化,需要实现类
        Collection c = new ArrayList();
        System.out.println(c);  //新创建的集合默认是空的

        //往集合中添加数据
        c.add("SmallG");
        c.add("SmallY");
        c.add("666");
        System.out.println(c);
    }
}
contains方法示例:

用于判断给定的元素是否被包含在集合中。

/**
 * @document: contains()方法用于判断一个集合中是否包含一个元素
 * @Author:SmallG
 * @CreateTime:2023/8/4+14:27
 */

public class Demo02 {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        String str1 = new String("Hello");
        String str2 = new String("Hello");
        System.out.println(str1 == str2); //比较的是引用类型的地址 //false
        c.add(str1);
        c.add(str2);

        String str3 = new String("Hello");

        //contains()方法是基于对象的equals()方法的比较
        System.out.println(c.contains(str3));    //true
        System.out.println(c.contains("hello"));
    }
}

string常量池

size、clear、isEmpty方法:
/**
 * @document: collection集合常用方法:
 * size() 返回集合中元素的个数
 * clear() 清空集合
 * isEmpty() 判断集合是否为空
 * @Author:SmallG
 * @CreateTime:2023/8/4+14:39
 */

public class Demo03 {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        System.out.println(c.isEmpty()); //true

        c.add("Java");
        c.add("C++");
        c.add("C#");
        c.add("PHP");
        c.add("Python");
        System.out.println(c.isEmpty()); //false
        //输出集合的大小
        System.out.println(c.size()); //5
        //清空集合
        c.clear();
        System.out.println(c);
    }
}
addAll与ContainsAll方法:
/**
 * @document: Collection的常用方法
 * addAll() 把一个集合中的所有元素添加到另外一个集合中
 * containsAll() 判断一个集合中是否包含另外一个集合中所有的元素
 * @Author:SmallG
 * @CreateTime:2023/8/4+15:03
 */

public class Demo04 {
    public static void main(String[] args) {
        //考试通过的学生名单
        Collection c = new ArrayList();
        c.add("SmallG");
        c.add("SmallY");
        c.add("SmallSmallG");

        //再创建一个集合
        Collection a = new ArrayList();
        a.add("SmallG");
        a.add("SmallY");
        //判断a组同学是否都通过了考试
        boolean pass = c.containsAll(a);
        if (pass) {
            System.out.println("A组全部通过考试");
        } else {
            System.out.println("A组没有全部通过考试");
        }

        //创建b组学生名单
        Collection b = new ArrayList();
        b.add("SmallL");
        b.add("SmallX");
        //把b组所有学生添加到c组学生名单中

        c.addAll(b);
        System.out.println(c);
    }
}

2、Iterator迭代器

用于遍历集合中的所有元素,它的方法有:

  • hasNext():用于判断集合中是否有更多元素
  • next():返回迭代器中的下一个元素
  • remove():从集合中删除最近一次调用next()方法返回的元素
  • **遍历时:Collection的remove()方法不能直接删除集合元素,否则会抛出并发更改异常
/**
 * @document: 迭代器遍历集合
 * 用于遍历集合
 * hasNext() 判断迭代器中是否含有下一个元素
 * Next() 方法取出下一个元素
 * @Author:SmallG
 * @CreateTime:2023/8/4+15:22
 */

public class Demo05 {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        // 往集合中存入数据
        for (int i = 1; i <= 10; i++) {
            c.add(i);
        }
        System.out.println(c);
        //遍历集合 获取集合的迭代器对象
        Iterator iterator = c.iterator();
        //通过迭代器去遍历集合
        while (iterator.hasNext()) {
            int i = (int) iterator.next(); //需要强制类型转换
            System.out.print(i + " ");

            //通过迭代器删除集合中的元素
            if (i % 2 == 0) {
                iterator.remove();
            }
        }
        System.out.println();
        System.out.println(c);
    }
}

增强for循环

增强for循环

增强for循环缺点:无法确定遍历的下角标。

/**
 * @document: 增强for循环
 * @Author:SmallG
 * @CreateTime:2023/8/4+15:39
 */

public class Demo06 {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        //往集合中添加数据
        for (int i = 1; i <= 10; i++) {
            c.add(i);
        }
        //增强for循环遍历集合
        for (Object o : c) {
            System.out.print(o + " ");
        }
        System.out.println();

        //增强循环遍历数组
        String[] arrs = {"Tom", "SmallG", "Jerry"};
        for (String s : arrs) {
            System.out.println(s);
        }
    }
}

3、泛型机制

泛型的本质是数据类型的参数化

/**
 * @document: 泛型
 * @Author:SmallG
 * @CreateTime:2023/8/4+16:01
 */

public class Demo07 {
    public static void main(String[] args) {
        //创建一个集合  创建的时候添加泛型  使用泛型约束集合中元素的数据类型
        Collection<Integer> c = new ArrayList();
        c.add(80);
        c.add(85);
        c.add(70);

        //使用迭代器
        Iterator<Integer> iterator = c.iterator();
        while (iterator.hasNext()) {
            int i =iterator.next();
            System.out.println(i);
        }
    }
}

二、List集合

1、List集合

List接口直接继承Collection接口,用于定义线性表数据结构,允许出现重复的元素

方法声明功能描述
void add(int index,E element)在列表的指定索引位置插入指定元素
boolean addAll(int index,Collection<? extends E> e)在列表的指定索引位置插入集合e的所有元素
E get(int index)返回列表中指定索引位置的元素
int indexOf(Object o)返回列表中第一次出现指定元素的索引,若不包含该元素则返回-1
int lastIndexOf(Object o)返回列表中最后出现指定元素的索引,若不包含该元素则返回-1
E remove(int index)移除指定索引位置上的元素
E set(int index,E element)用指定元素替换列表中指定索引位置的元素
ListIterator listIterator()返回列表元素的列表迭代器
ListIterator listIterator(int index)返回列表元素的列表迭代器,从指定索引位置开始
List subList(int fromIndex,int toIndex)截取列表元素
default void sort(Comparator<?super E> e)根据指定的比较器规则对集合元素进行排序
Object[] toArray()将集合元素转换为数组

2、ArrayList

list接口的实现类,内部封装了一个长度可变的数组对象,当元素存入的数据超过数组长度,自动扩容。

特点:

  • 动态大小:自动调整空间大小
  • 随机访问:通过索引访问
  • 允许重复元素
  • 支持动态修改:可以添加、删除、插入、替换
  • 迭代和遍历:都支持。

ArrayList常用方法

  • void add(int index,E element):在列表的指定索引位置插入指定元素
  • remove(int index):删除指定位置的元素,并将该元素返回
  • set(index,Element):修改指定位置的数据
  • E get(int index):获取集合中指定指定位置的元素
  • E get(int index,E element):将给定元素存入指定位置,并将原位置的元素返回
  • size():获取集合中数据的个数
  • clear():清空集合
  • isEmpty():判断集合是否为空
/**
 * @document: Arraylist集合
 * @Author:SmallG
 * @CreateTime:2023/8/4+16:13
 */

public class Demo08 {
    public static void main(String[] args) {
        //创建ArrayList集合对象 使用泛型
        ArrayList<String> myList = new ArrayList<>();
        //往集合中添加元素
        myList.add("one");
        myList.add("two");
        myList.add("three");
        System.out.println(myList);
        System.out.println("--------------------");

        //取出集合中指定位置的元素
        String s = myList.get(1);
        System.out.println("索引为1的元素是:" + s);
        System.out.println("--------------------");

        //替换集合中某一位置中的数据 ,返回被替换的数据
        String old = myList.set(0, "SmallG");
        System.out.println("被替换的数据是:" + old);
        System.out.println("集合中的数据有::" + myList);
        System.out.println("--------------------");

        //删除集合中的数据
        String delete = myList.remove(1);
        System.out.println("被删除的数据是:" + delete);
        System.out.println("集合中的数据有::" + myList);
        System.out.println("--------------------");

        //取出集合中的一部分
        List<String> subList = myList.subList(0, 2);//包括0但不包括2
        System.out.println("获取的子集是:" + subList);
        System.out.println("--------------------");

        //增强for循环(foreach)遍历集合
        for (String str : myList) {
            System.out.print(str + " ");
        }
        System.out.println();
    }
}

ArrayList的扩容机制

(1)初始容量

初始容量两种情况:未指定初始长度和手动指定初始长度。

ArrayList初始容量为0,在添加第一个元素时动态扩容为10

手动指定初始长度:通过带参构造器来创建ArrayList对象,如果手动指定了长度,ArrayList的初始容量即为指定的长度,一般情况下,都会用未指定初始长度的ArrayList。

(2)容量增长

当添加元素导致ArrayList长度超过本身的长度时,ArrayList会自动进行容量增长,容量的增长策略是通过创建一个新的更大的数组,并将原有元素复制到新数组中。

(3)复制元素
  • 在进行容量增长时,ArrayList会创建一个新的数组,并将原有的元素复制到新数组中
return elementData = Arrays.copyOf(elementData, newCapacity);
  • 复制元素的操作可能会导致一定的性能开销,特别是存储大量元素的时候,当事先知道要存储的总元素数量时,应使用ArrayList的带参构造器来创建ArrayList,以减少动态扩容带来的性能开销(事实项目要先完成功能,再考虑优化性能)
(4)ArrayList缩容操作

需要手动缩容trimToSize(),根据项目需要进行操作。

ArrayList与数组的转换

ArrayList集合的toArray()方法用于将集合转换为数组(不常用)

注意元素类型要保持一致。

/**
 * @document: ArrayList集合与数组的相互转换 Ai生成
 * @Author:SmallG
 * @CreateTime:2023/8/7+9:45
 */

public class Demo10 {
        public static void main(String[] args) {
            // 创建一个ArrayList集合
            ArrayList<String> arrayList = new ArrayList<>();

            // 添加元素到ArrayList
            arrayList.add("Apple");
            arrayList.add("Banana");
            arrayList.add("Orange");
            arrayList.add("Grapes");

            // 将ArrayList转换为数组
            String[] array = arrayList.toArray(new String[arrayList.size()]);

            // 输出数组元素
            System.out.println("数组元素:");
            for (String item : array) {
                System.out.println(item);
            }

            // 创建一个新的数组
            String[] newArray = {"Pineapple", "Watermelon"};

            // 将数组转换为ArrayList
            ArrayList<String> newArraylist = new ArrayList<>(Arrays.asList(newArray));

            // 输出ArrayList元素
            System.out.println("ArrayList元素:");
            for (String item : newArraylist) {
                System.out.println(item);
            }
        }
}

3、LinkedList

LinkedList概述

线性列表集合,内部维护了一个双向链表,适合于增和删操作,查询效率低。

LinkedList特点

  • 链表结构
  • 动态大小,根据需要自动扩展大小
  • 高效插入和删除
  • 不支持随机访问
  • 遍历操作:可以用迭代器

ArrayList和LinkedList比较示例:

/**
 * @document: LinkedList与ArrayList的集合对比
 * @Author:SmallG
 * @CreateTime:2023/8/7+10:22
 */

public class Demo11 {
    public static void main(String[] args) {
        //定义一个次数 执行十万次迭代
        int iteration = 1000000;
        //创建ArrayList集合
        ArrayList<Integer> arrayList = new ArrayList<>();
        long arrayListStartTime = System.currentTimeMillis();
        //往ArrayList集合中插入数据,从头部插入
        for (int i = 0; i < iteration; i++) {
            arrayList.add(0, i);
        }
        long arraylistEndTime = System.currentTimeMillis();
        long arraylistDuration = arraylistEndTime - arrayListStartTime;
        System.out.println("ArrayList头部插入耗时:" + arraylistDuration);

        //创建LinkedList
        LinkedList<Integer> linkedList = new LinkedList<>();
        //开始时间戳
        long linkedListStartTime = System.currentTimeMillis();
        for (int i = 0; i < iteration; i++) {
            linkedList.addFirst(i);
        }
        long linkedListEndTime = System.currentTimeMillis();
        long linkedListDuration = linkedListEndTime - linkedListStartTime;
        System.out.println("LinkedList头部插入耗时:" + linkedListDuration);
        System.out.println("-------------------------");

        //清空集合,向中间插入数据时linkedList插入效率大大降低
        // 因为LinkedList需要遍历增加了耗时
        arrayList.clear();
        linkedList.clear();

        arrayListStartTime = System.currentTimeMillis();
        //往中间插入数据
        for (int i = 0; i < iteration; i++) {
            arrayList.add(i / 2, i);
        }
        arraylistEndTime = System.currentTimeMillis();
        arraylistDuration = arraylistEndTime - arrayListStartTime;
        System.out.println("ArrayList中间插入耗时:" + arraylistDuration);

        linkedListStartTime = System.currentTimeMillis();
        for (int i = 0; i < iteration; i++) {
            linkedList.add(i / 2, i);
        }
        linkedListEndTime = System.currentTimeMillis();
        linkedListDuration = linkedListEndTime - linkedListStartTime;
        System.out.println("LinkedList中间插入耗时:" + linkedListDuration);
        System.out.println("-------------------------");
        //尾部添加元素
        arrayList.clear();
        linkedList.clear();
        arrayListStartTime = System.currentTimeMillis();
        for (int i = 0; i < iteration; i++) {
            arrayList.add(i);
        }
        arraylistEndTime = System.currentTimeMillis();
        arraylistDuration = arraylistEndTime - arrayListStartTime;
        System.out.println("ArrayList尾部添加元素耗时:" + arraylistDuration);

        linkedListStartTime = System.currentTimeMillis();
        for (int i = 0; i < iteration; i++) {
            linkedList.addLast(i);
        }
        linkedListEndTime = System.currentTimeMillis();
        linkedListDuration = linkedListEndTime - linkedListStartTime;
        System.out.println("LinkedList尾部添加元素耗时:" + linkedListDuration);
    }
}

三、练习

1 重构学生平时分记录程序

请基于所学内容,重构学生平时分记录程序,在原有需求的基础上,满足以下需求:

1、设计一个实体类Record封装每次加分或减分记录。

2、采用集合存储所有的记录。

3、实现数据的持久化存储,包括:

  • 启动程序时,从本地文件加载之前保存的记录;
  • 退出程序前,将记录写入本地文件,覆盖之前保存的记录。

提示:Java支持集合对象的序列化和反序列化操作,但需要注意,集合中存储的类型也需要实现Serializable接口。

程序运行效果参考《学生平时分记录程序_需求规格说明书》。

更新后的程序主流程图如下所示。

练习1

package day01.homework;

import java.io.Serializable;

/**
 * @document: 平时分明细
 * @Author:SmallG
 * @CreateTime:2023/8/4+18:45
 */

public class Score implements Serializable {
    private String name; //姓名
    private String operate; //操作
    private Double score; //本次加分
    private Double lastScore; //最后剩下的分
    private String description; //说明

    @Override
    public String toString() {
        return  name + "," +
                operate + "," +
                score +"," +
                lastScore +"," +
                description;
    }

    public Score() {
    }

    public String getName() {
        return name;
    }

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

    public String getOperate() {
        return operate;
    }

    public void setOperate(String operate) {
        this.operate = operate;
    }

    public Double getScore() {
        return score;
    }

    public void setScore(Double score) {
        this.score = score;
    }

    public Double getLastScore() {
        return lastScore;
    }

    public void setLastScore(Double lastScore) {
        this.lastScore = lastScore;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Score(String name, String operate, Double score, Double lastScore, String description) {
        this.name = name;
        this.operate = operate;
        this.score = score;
        this.lastScore = lastScore;
        this.description = description;
    }
}
package day01.homework;

import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;

/**
 * @document: IO流,主要用于存储
 * @Author:SmallG
 * @CreateTime:2023/8/4+18:51
 */

public class IoStorage {

    static int count = 0;
    static double lastScore = 90.0;

    //存储信息
    public static boolean saveInfo(String path, ArrayList<Score> scores) {
        boolean flag = false;
        try (
                FileOutputStream fos = new FileOutputStream(path);
                ObjectOutputStream oos = new ObjectOutputStream(fos)
        ) {
            oos.writeObject(scores);
            count++;
            if (count>=6){
                flag = false;
            }else{
                flag = true;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return flag;
    }

    //读取信息
    public static ArrayList<Score> readScore(String path) {
        File file = new File(path);
        // 如果文件不存在,则返回一个空集合
        if (!file.exists()) {
            return new ArrayList<Score>();
        }
        try (
                FileInputStream fis = new FileInputStream(path);
                ObjectInputStream ois = new ObjectInputStream(fis)
        ) {
            ois.read();
            return (ArrayList<Score>) ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        //设置存储位置
        String path = "src/day01/homework/scores.csv";
        ArrayList<Score> scores = new ArrayList<>();
        boolean flag = true;
        System.out.println("请输入学生姓名:");
        String name = scanner.next();
        while (flag) {
            System.out.println("----------学生平时分记录程序----------");
            System.out.println("            1 评分明细");
            System.out.println("            2 登记加分");
            System.out.println("            3 登记减分");
            System.out.println("            4 退   出");
            System.out.println();
            System.out.println("            请选择(1-4):");
            int n = scanner.nextInt();
            switch (n) {
                case 1:
                    System.out.println("-------------------当前平时分明细记录-------------------");
                    System.out.println("姓名\t\t操作\t\t本次分数\t\t当前平时分\t\t说明");
                    scores = readScore(path);
                    for (Score score : scores) {
                        System.out.println(score.getName()+"\t\t\t"+
                                score.getOperate()+"\t\t"+
                                score.getScore()+"\t\t\t"+
                                score.getLastScore()+"\t\t\t"+
                                score.getDescription()+"\t");
                    }
                    break;
                case 2:
                    if (count <= 5) {
                        System.out.println("本次加分分值:");
                        double sc = scanner.nextInt();
                        System.out.println("本次加分说明:");
                        String s1 = scanner.next();
                        scores.add(new Score(name,"加分",sc,lastScore+sc,s1));
                        boolean flag1 = saveInfo(path, scores);
                        if (flag1) {
                            System.out.println("加分登记成功");
                        }
                    } else {
                        System.out.println("记录已满,请清理后再进行登记!");
                    }
                    break;
                case 3:
                    if (count <= 5) {
                        Score score = new Score();
                        System.out.println("本次减分分值:");
                        double num = scanner.nextInt();
                        score.setName(name);
                        score.setOperate("减分");
                        score.setScore(num);
                        score.setLastScore(lastScore - num);
                        System.out.println("本次减分说明:");
                        String s1 = scanner.next();
                        score.setDescription(s1);
                        scores.add(score);
                        boolean flag1 = saveInfo(path, scores);
                        if (flag1) {
                            System.out.println("减分登记成功");
                        }
                    } else {
                        System.out.println("记录已满,请清理后再进行登记!");
                    }
                    break;
                case 4:
                    System.out.println("确认是否退出(Y/N):");
                    String s = scanner.next();
                    if (s.equals("y") || s.equals("Y")) {
                        System.out.println("谢谢使用,再见!");
                        flag = false;
                        break;
                    } else if (s.equals("n") || s.equals("N")) {
                        System.out.println("退出取消,继续使用");
                    } else {
                        System.out.println("输入字符有误!");
                    }
                    break;
                default:
                    System.out.println("输入序号有误!");
                    break;
            }
        }


    }

}

2 分解质因数

将一个用户输入的正整数分解质因数。例如:输入90,打印输出90=2×3×3×5。

提示:可以考虑使用递归的思想实现。

程序运行效果如下所示:

练习2

/**
 * @document: 质因子
 * @Author:SmallG
 * @CreateTime:2023/8/5+11:47
 */

public class PrimeFactor {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入一个正整数:");
        //输入
        int n = scanner.nextInt();
        System.out.println("n = " + n);
        prime(n);
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.println("质因子:" + arrayList.get(i));
        }
        System.out.print("n = ");
        for (int i = 0; i < arrayList.size(); i++) {
            if (i == 0) {
                System.out.print(arrayList.get(i));
            } else {
                System.out.print("*" + arrayList.get(i));
            }
        }
    }

    static ArrayList<Integer> arrayList = new ArrayList<>();

    public static ArrayList<Integer> prime(int n) {

        if (n % 2 == 0) {
            n = n / 2;
            arrayList.add(2);
            prime(n);
        } else if (n % 3 == 0) {
            n = n / 3;
            arrayList.add(3);
            prime(n);
        } else if (n % 5 == 0) {
            n = n / 5;
            arrayList.add(5);
            prime(n);
        } else if (n == 1) {

        } else {
            arrayList.add(n);
        }
        return arrayList;
    }
}
最后修改:2023 年 08 月 07 日
如果觉得我的文章对你有用,请随意赞赏