Java复习笔记-17

本文详细介绍了Java中的Collection接口、List接口(包括ArrayList和LinkedList实现),涉及泛型、索引操作、增删元素、数组转换和线程安全性的讨论。还提供了自定义ArrayList和LinkedList的练习示例。
摘要由CSDN通过智能技术生成

集合

1 集合

1.1 概述

Collection 是所有集合的顶级接口。是存放元素的容器。有很多子接口和实现类。不同的接口有不同的特点。不同的实现类有不同的实现方式。

Collection 这个代表泛型,相当于定义号集合中能放哪些数据类型。泛型只能用引用数据类型。

1.2 集合中的常用方法

public static void main(String[] args) {
        Collection<String> collection = new ArrayList<>();
        collection.add("java");
        collection.add("ios");
        collection.add("windows");
        collection.add("go");
        System.out.println(collection);

        Collection<String> collection1 = new ArrayList<>();
        collection1.add("java");
        collection1.add("ios");
        collection1.add("windows");
        collection1.add("go");
        // 比较集合中的元素是否相同
        System.out.println(collection.equals(collection1));
        // 清空集合中存储的所有元素  但是集合的对象还在
        collection.clear();

        // 判断集合是否为空
        System.out.println(collection.isEmpty());

        // 移除集合中的元素,移除成功返回true
        System.out.println(collection1);
        collection1.remove("ios");
        System.out.println(collection1);
        // 获取集合中的元素个数
        System.out.println(collection1.size());
        // 把集合对象转换成数组
//        Object[] objects = collection1.toArray();
//        for (Object object : objects) {
//            System.out.println(object);
//        }

        String[] objects = collection1.toArray(new String[0]);
        for (String str : objects) {
            System.out.println(str);
        }

//        System.out.println(collection);
        // 判断集合中是否包含某一个元素  返回true代表包含 返回false代表不包含
//        System.out.println(collection.contains("go"));

    }

    private static void addDemo() {
        // JDK7之后,如果左边泛型确定了,右边的泛型可以省略
        // 创建集合对象
        Collection<String> collection = new ArrayList<>();
        // 添加元素到集合中
        collection.add("java");
        collection.add("python");
        collection.add("C");
        collection.add("C++");
        collection.add("C#");
        collection.add("golang");
        System.out.println(collection);
    }

1.3 List接口

List接口是一个有序的集合,方法中具有索引,允许存储重复的元素.

1.3.1 List接口中带索引的方法
    public static void main(String[] args) {
        // 创建对象
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        System.out.println(list);

        // 在index索引处插入一个元素
        list.add(1,5);
        System.out.println(list);
//         IndexOutOfBoundsException 索引越界异常
//        list.add(8,6);

        List<String> strings = new ArrayList<>();
        strings.add("UI");
        strings.add("test");
        strings.add("develop");
        strings.add("UI");
        System.out.println(strings);
        // 移除指定的元素
        // 如果移除的是重复元素,那么会移除第一个
//        strings.remove("UI");
//        System.out.println(strings);
        // 移除指定索引处的元素
//        strings.remove(1);
//        System.out.println(strings);

        // 移除指定的所有元素
//        while (strings.contains("UI")){
//            strings.remove("UI");
//        }
//        System.out.println(strings);

        // 找指定元素的第一个索引,找不到就是-1
//        System.out.println(strings.indexOf("UI"));
//        // 移除指定的所有元素
//        while (strings.indexOf("UI") != -1){
//            strings.remove("UI");
//        }

        // 替换指定索引处的元素,并返回替换之前的值
        String str = strings.set(2, "boss");
        System.out.println(str);
        System.out.println(strings);
        // 获取指定索引处的元素
        String str1 = strings.get(2);
        System.out.println(str1);
        // 截取子集合  包含第一个索引,不包含第二个索引 (包头不包尾)
        List<String> strings1 = strings.subList(0, 2);
        System.out.println(strings1);
    }
1.3.2 List接口的实现类–ArrayList

ArrayList是List接口的实现类,具有自己的特点

  • 内部数据结构是数组
  • 查询速度快
  • 增删速度慢
  • 线程不安全的集合

ArrayList底层数组的初始化容量是10

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ElementData是ArrayList的底层数组

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

底层数组扩容机制是 (原来的容量 + 原来容量/2 )

方法

       // 指定ArrayList的初始化容量  指定多少就是多少
        ArrayList<String> list1 = new ArrayList<>(8);
        // 将ArrayList的容量缩小为当前元素的实际的个数
        list1.trimToSize();
1.3.2.1 练习 – 实现ArrayList中的常用方法

自定义ArrayList类的基本结构

public class ArrayListDemo {
    // 存储数据的数组
    private String[] data;
    // 定义无参构造方法
    public ArrayListDemo(){
        // ArrayList底层数组的默认容量是10
        data = new String[10];
    }

    // 定义有参构造
    public ArrayListDemo(int len){
        // 判断初始化容量是否合法
        if (len < 0)
            throw new IllegalArgumentException("arraylist容量不能是负数");
        data = new String[len];
    }

    //记录元素的个数
    private int size = 0;
  • 添加元素方法
// 添加元素方法
    public void add(String str){
        // 判断是否需要扩容
        if (size >= data.length){
            this.grow();
        }
        data[size++] = str;
    }

    // 扩容方法
    private void grow(){
        if (data.length <= 1){
            data = Arrays.copyOf(data,data.length + 1);
        }else {
            // 注意点:这里data.length >> 1一定要加小括号 因为 +的优先级比 >> 高
            data = Arrays.copyOf(data, data.length + (data.length >> 1));
        }
    }
  • 重写toString方法
// [3, 4, 5, 6]
    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("[");
        for (int i = 0;i < size;i++){
            if (i != size - 1){
                stringBuilder.append(data[i]).append(", ");
            }else {
                stringBuilder.append(data[i]);
            }
        }
        stringBuilder.append("]");
        return stringBuilder.toString();
    }
  • 实现插入元素方法 add(int index,String str)
 /**
     * 插入元素方法
     * @param index  插入元素的索引
     * @param str   插入的元素
     */
    public void add(int index,String str){
        // 判断索引是否越界
        if (index < 0 || index > size){
            throw new IndexOutOfBoundsException("数组越界了,skr~");
        }
        // 判断是否需要扩容
        if (size >= data.length){
            this.grow();
        }

        // 方式一:统一把index后面的数据往后挪一位
        for (int i = size - 1;i >= index;i--){
            data[i + 1] = data[i];
        }
        // 方式二:
//        System.arraycopy(data,index,data,index + 1,size - index);
        //设置插入索引位置的字符串
        data[index] = str;
        // 实际元素加1
        size++;
    }
  • 删除指定索引处的元素
public void remove(int index){
        // 判断索引是否越界
        if (index >= size || index < 0) throw new IndexOutOfBoundsException("数组越界了");
        // 方式一:从索引处后面的数据统一向前挪一位
//        System.arraycopy(data,index + 1,data,index,size - index - 1);
        for (int i = index; i < size - 1 ; i++) {
            data[i] = data[i + 1];
        }
        // 实际长度减一
        size--;
    }
  • 删除指定元素
/**
     * 查找字符串首次出现的位置
     * @param str 字符串
     * @return    所在的索引
     */
    public int indexOf(String str){
        for (int i = 0; i < size; i++) {
            if (str == data[i] || str != null && str.equals(data[i])){
                // 字符串和元素相等
                return i;
            }
        }
        // 如果没有找到,返回-1
        return -1;
    }

    /**
     * 删除指定元素
     * @param str  指定的字符串
     */
    public void remove(String str){
        // 找到元素第一次出现的位置
        int index = this.indexOf(str);
        if (index != -1){
            // 删除
            this.remove(index);
        }
    }
  • 其他方法
 /**
     * 判断是否越界
     * @param index
     */
    private void out(int index) {
        // 判断索引是否越界
        if (index >= size || index < 0) throw new IndexOutOfBoundsException("数组越界了");
    }

    /**
     * 判断是否包含指定元素
     * @return true 包含
     */
    public boolean contains(String str){
        return indexOf(str) != -1;
    }

    /**
     * 根据索引获取元素
     * @param index  索引
     * @return  元素
     */
    public String get(int index){
        // 判断是否越界
        this.out(index);
        return data[index];
    }

    /**
     * 判断集合是否为空
     * @return
     */
    public boolean isEmpty(){
        return size == 0;
    }

    /**
     * 替换元素
     */
    public void set(int index,String str){
        // 判断是否越界
        this.out(index);
        data[index] = str;
    }

    /**
     * 获取元素个数
     */
    public int size(){
        return size;
    }

    /**
     * 清空集合
     */
    public void clear(){
        data = new String[10];
        size = 0;
    }
  • 截取子列表
/**
     * 截取子列表
     * @return 子列表
     */
    public ArrayListDemo subList(int fromIndex,int toIndex){

        // 判断参数是否合法
        this.out(fromIndex);
        this.out(toIndex);
        if (fromIndex > toIndex){
            throw new IllegalArgumentException();
        }
        // 创建一个新的要截取的列表
        ArrayListDemo sublist = new ArrayListDemo(toIndex - fromIndex);

        // 拷贝要截取的内容到新数组中
        System.arraycopy(this.data,fromIndex,sublist.data,0,toIndex - fromIndex);
        // 设置新的列表的实际元素个数
        sublist.size = toIndex - fromIndex;
        return sublist;
    }

ArrayList的特点:查询相对简单,增删相对复杂。线程不安全的集合。

1.3.3 List接口的实现类–LinkedList

LinkedList称之为链表,底层是一个双向链表结构。

链表的内存是不连续的

LinkedList的特点:

  • 查询效率相对低
  • 增删效率相对高
  • 是一个线程不安全的集合

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.3.3.1 练习–实现LinkedList的常用方法
  • 基本结构
public class LinkedListDemo {
    // 表示元素结点的个数
    private int size = 0;

    // 头结点
    private Node first;
    // 尾结点
    private Node last;
    
    // 链表不需要扩容,也没有初始容量
//    public LinkedListDemo(){}


    // 定义结点的数据结构 是一个私有的成员内部类
    private class Node{
        // 数据
        String data;
        // 上一个结点的地址
        Node prev;
        // 下一个结点的地址
        Node next;

        // 提供有参构造方法保存成员变量
        public Node(String data,Node prev,Node next){
            this.data = data;
            this.prev = prev;
            this.next = next;
        }
    }
}
  • 添加元素
/**
     * 添加元素
     * @param str
     */
    public void add(String str){
        // 创建结点(将新添加进来的字符串包装成Node对象)
        Node node = new Node(str,null,null);
        // 判断是否是第一次添加元素
        if (size == 0){
            this.first = node;
        }else {
            // 旧的尾结点的next设置成新添加来的结点
            this.last.next = node;
            // 新添加的结点的prev设置成旧的尾结点
            node.prev = this.last;
        }

        // 把新添加的结点设置成尾结点
        this.last = node;
        // 元素个数+1
        size++;
    }
  • 插入元素
/**
     * 插入元素
     */
    public void add(int index,String str){
        // 判断索引是否越界
        if (index > size || index < 0) throw new IndexOutOfBoundsException("索引越界");

        // 插入元素分为三种情况
        // 1.插入到尾部  2. 插入到头部  3.插入到中间
        // 插入到尾部
        if (index == size){
            add(str);
            return;
        }

        Node node = new Node(str,null,null);
        // 插入到头部
        if (index == 0){
            // 将新结点的next设置成原来的头结点
            node.next = this.first;
            // 将头结点的prev设置成新的结点
            this.first.prev = node;
            // 将新结点设置成新的头结点
            this.first = node;
        }else {
            // 插入到中间
            // 先查询要插入索引的元素
            // 获取头结点,一个个向下查询
            Node no = first;
            for (int i = 0; i < index; i++) {
                // 一个个向下查找
                no = no.next;
            }
            // no经过上面的循环之后,就是要插入索引处原来的那个结点
            // no的前一个结点的next属性赋值为新结点
            no.prev.next = node;
            // node的prev设置为no的上一个结点
            node.prev = no.prev;
            // 新结点的next设置为旧结点
            node.next = no;
            // 旧结点的prev设置为新结点
            no.prev = node;
        }
        size++;
    }
  • 根据索引查找结点
public Node getNode(int index){
    //判断是否索引越界
    if(index < 0 || index > size - 1)
        throw new IndexOutOfBoundsException("索引越界");
    //循环找到索引指定的元素
    Node no;
    if(index >= size / 2){
        no = this.last;
        for (int i = 0; i < size - index - 1; i++) {
            no = no.prev;
        }
    }else {
        no = this.first;
        for (int i = 0; i < index; i++) {
            no = no.next;
        }
    }
    return no;
}
  • 根据索引查找元素
    //根据索引查找元素
    public String get(int index){
       return this.getNode(index).data;
    }
  • 根据元素返回索引
//根据元素返回索引
public int indexOf(String str){
    //先看尾是不是
    if(Objects.equals(str, this.last.data)){
        return size - 1;
    } else {
        Node no = this.first;
        for(int i = 0;i < size - 1;i++){
            if(Objects.equals(str, no.data)){
                return i;
            }
            no = no.next;
        }
    }
    //都不是就返回 -1
    return -1;
}
  • 删除指定索引元素
//删除指定索引元素
public void remove(int index){
    //判断是否索引越界
    if(index < 0 || index > size - 1)
        throw new IndexOutOfBoundsException("索引越界");

    if(size == 1){
        this.clear();
        return;
    }
    if(index == size - 1){
        this.last = this.last.prev;
        this.last.next = null;
        size--;
        return;
    }
    if(index == 0){
        this.first = this.first.next;
        this.first.prev = null;
        size--;
        return;
    }
    Node node = this.getNode(index);
    node.prev.next = node.next;
    node.next.prev = node.prev;
    size--;
}
  • 删除指定元素匹配的第一项
//删除指定元素的第一个匹配项
public void remove(String str){
    int i = indexOf(str);
    if(i == -1){
        System.out.println("不存在");
        return;
    }
    remove(i);
}
  • 重写 toString() 方法
@Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("[");


            Node no = this.first;
            for(int i = 0;i < size;i++){
                if(i == 0){
                stringBuilder.append(no.data);
                }else {
                    stringBuilder.append(",").append(no.data);
                }
                no = no.next;
            }

        stringBuilder.append("]");

        return stringBuilder.toString();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值