02_Collection

集合

在Java中,指的就是存放数据的容器,是一个载体,可以一次容纳多个对象。

解决Bug的两种方法

    1. 打印
    • System.out.println();
    • log.info();
    1. debug
    • 检查数据

Java的集合类

在这里插入图片描述
Collection

  • 存储一个一个的数据
    • 先理解为一个袋子,往里面装数据。有各种各样的子实现。
  • Collection是最基本的集合接口,一个 Collection 代表一组Object,即 Collection 的元素
    • Java不提供直接实现自Collection的类,只提供继承于的子接口(如List和set)。

Map

  • 存储的是键值对数据
  • 存储key-value结构的数据。
    • key-value结构:就是可以根据一个key,找到一个对应的value。
    • Map 接口存储一组键值对象,提供key(键)到value(值)的映射。

Collection

特点

  1. Collection是顶级接口,用描述数据存储的接口
  2. Collection的一些子实现有序,一些无序
    • 有序和无序是指:存储和读取的顺序
  3. 一些子实现允许存储重复的数据,一些不允许
    • 允许重复:
    • 不允许重复:
  4. 一些子实现允许存储null,一些不允许
    • 允许存储null:
    • 不允许存储null:

API

  1. 增删改查方法
boolean add(E e): // 添加一个元素进入Collection

boolean addAll(Collection<? extends E> c): // 添加一个Collection进目标Collection

boolean remove(Object o)// 删除元素, 只删除第一个出现的(如果存在多个)

boolean removeAll(Collection<?> c)// 删除Collection中的所有存在的元素,会全部删除,如果存在多个

boolean contains(Object o)// 判断是否存在指定元素

boolean containsAll(Collection<?> c)// 判断给定的collection中是否全部存在于目标Collection

boolean retainAll(Collection<?> c)// 将原有collection只保留传入的collection。
  1. 特殊方法
void clear()// 清空collection

boolean equals(Object o)// 判断是否相等

int hashCode()// 计算hashCode

boolean isEmpty(): // 是否为空

int size()// collection里面的元素个数

如果hashcode()没有重写,代表地址值,并且equal()hashcode()要一起重写

重写hashcode()的目的:是为了让hashcode和对象里面的变量有关。

  1. 方便遍历方法
Object[] toArray(): // 将collection转成一个数组,方便遍历,(无参)
// 就是把原有的集合copy成了一个数组

<T> T[] toArray(T[] a)// 类似,只是传入了一个数组 (有参)
// 1. 当传入的数组长度小于集合长度 --- 则只会使用类型,直接copy一份
// 2. 当传入的数组长度等于集合长度 --- 使用传入的数组
// 3. 当传入的数组长度大于集合长度 --- 会使用传入的数组,最后一个元素后面一个,会置为null

Iterator<E> iterator()// 返回一个迭代器

eg:

private static void testToArray() {
    Collection<String> collection = new ArrayList<>();

    collection.add("zs");
    collection.add("ls");
    collection.add("ww");

    // 数组的协变 支持用Object[] ---> 任意类型的数组
    Object[] objects = collection.toArray();
    for (int i = 0; i < objects.length; i++) {
        System.out.println(objects[i]);
    }
}

toArray的源码(有参构造):

public <T> T[] toArray(T[] a) {
  		// a是用来存储数据的数组。
        if (a.length < size)
          	// 1. 当数组长度小于集合的长度时候。只使用传入数组的类型
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
  		// 2. 如果大于等于集合的长度时候,则直接使用这个数组
  		// 直接copy 
        System.arraycopy(elementData, 0, a, 0, size);
  
 		// 3. 并且,如果数组长度大于集合长度。直接把a[size] = null,直接把最后一个元素的后面置为null。
        if (a.length > size)
            a[size] = null;
        return a;
    }

直接使用toArray的弊端

  • 耗费时间,例如:要是拷贝100w大小的数据时间太长
  • 耗费空间,例如:存储100w数据占太多的空间
  • jvm耗时,后续使用完毕还需要gc处理

iterator方法

迭代器(iterator),有时又称光标(cursor)是程序设计的软件设计模式,可在容器对象(container,例如链表或数组)上遍访的接口,设计人员无需关心容器对象的内存分配的实现细节。

注意事项

  • Iterator是个接口,接口只定义规范,我们获取到了iterator,就可以使用这个对象对数据进行遍历。
  • 迭代器相当于只保留了一个标识,可以看成一个搬运工,标识我可以怎么拿到这个数据,不copy数据所有操作的数据都是针对的原有的Collection
  • 比如Collection底层有的是数组,有的是链表。数组的Iterator里面维护的是下标链表的Iterator里面维护的是指针。所有的具体实现都交给具体的子类

方法

boolean hasNext(): // 是否有下一个元素
// 只会返回true false,反复调用,光标不会挪动

E next()// 获取下一个元素
// 挪动光标,返回刚刚扫过的元素
// 如果下一个没有元素,则会报错 NoSuchElementException

void remove()// 删除刚刚遍历过的元素
// 不能直接调用remove,必须要先遍历
// 不可以连续两次调用remove

eg:

private static void testIterator() {
    Collection<String> collection = new ArrayList<>();

    collection.add("zs");
    collection.add("ls");
    collection.add("ww");

	// 先生成一个迭代器
    Iterator<String> iterator = collection.iterator();

    // 是否有下一个元素
    boolean b = iterator.hasNext();
    System.out.println(b); // true

    // 返回下一个元素
    String next = iterator.next();
    System.out.println(next); // zs

    // 删除刚刚遍历过的元素
    iterator.remove();
    System.out.println(collection); // ls ww
}

Q迭代器是个游标,它遍历的时候,被别的线程,把原集合中加了几个元素,减了几个元素,那这时候这次遍历的意义大吗?

A

  • JDK采用了存储一个值的方式,去保证在迭代器使用过程中,原有的集合不被修改(当前线程、其他线程)。

  • 在Collection内部,有一个modCount,用来标识结构变化的次数(get/contains 这种查询不叫结构变化)

  • 生成迭代器的时候,存储这个expectedModCount=modCount,在调用 nextremove时候,会检查
    使用迭代器过程中,如果原结构发生了变化,会报并发修改异常。

  • 所以,不要在迭代器迭代过程中,去修改原集合。要不就是在迭代器生成之前,要不就在迭代器使用完成之后。

  • 并发修改异常

eg:
用iterator遍历的例子:

public class Demo3 {
    public static void main(String[] args) {
        Collection<Student> collection = new ArrayList<>();
        collection.add(new Student("zs",17,89,"20210104"));
        collection.add(new Student("ww",18,79,"20210105"));
        collection.add(new Student("ls",19,99,"20210105"));
        collection.add(new Student("ml",17,91,"20210104"));
        collection.add(new Student("zq",20,85,"20210104"));

        System.out.println("遍历前:" + collection);

        Iterator<Student> iterator = collection.iterator();

        while(iterator.hasNext()){
            if(iterator.next().getAge() == 17){
                iterator.remove();
            }
        }

        System.out.println("遍历后:" +  collection);
    }

Collection的遍历

  1. 使用无参构造方法
Object[] array = collection.toArray();
for (int i = 0; i < array.length; i++) {
    String s = (String) array[i];
    System.out.println(s);
}
  1. 使用有参构造方法
String[] array = collection.toArray(new String[0]);
for (int i = 0; i < array.length; i++) {
    System.out.println(array[i]);
}
  1. 使用foreach循环
for (String s : collection) {
    System.out.println(s);
}
  1. 使用迭代器
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}
  • 29
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coo1heisenberg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值