当前位置 : 主页 > 编程语言 > 其它开发 >

集合框架与迭代器

来源:互联网 收集:自由互联 发布时间:2022-05-30
集合框架 集合是数组的升级,数组也是一种集合,集合是一种容器,用于存放对象的容器。不同数组的是,集合可以存放不同的类型,也不限数量。如果在集合中存放基本数据会自动装
集合框架

集合是数组的升级,数组也是一种集合,集合是一种容器,用于存放对象的容器。不同数组的是,集合可以存放不同的类型,也不限数量。如果在集合中存放基本数据会自动装箱转换成对应的引用类型。

集合存放的是对象的引用(内存地址),对象本身还是在堆中。集合也是一个引用

集合结构

java.util.*该包下存放所有的集合和集合的接口

集合又分三类,有序集合List,无序集合Set,另类是Map接口系列的集合。其中,List和Set都是Collection的子接口。而Collection又是Iterator的子接口,Iterator是迭代器,用于遍历集合中元素的接口;Map系列的集合是以键-值对存储的,Collection系列的集合是单个存储的。

不同的集合,底层对应的数据结构不同,数据结构分:数组、二叉树、链表等。数据结构不同,存储分式不同。

Collection结构图

image-20220505074437066

Map结构图

image-20220505074644743

以上,图中展示的是常用的类,当然还有其他的集合,其中的方法也差不多大同小异,可以自行查阅jdk文档

Q:无序不可重复,无序指的是存储和读取时的顺序,而不是排列顺序。不可重复是指存储的元素不可以重复,比如列表里已经有了1,那么再存进去1,元素个数也不会增加

Iterable接口

是Collection集合的顶层接口,Iterable是迭代接口,用于获取迭代器。

主要方法:

Iterator<T> iterator()

返回一个 T 类型的迭代器

Iterator迭代器

用于遍历集合中的元素。E代表泛型,用于表示未确认的数据类型。

方法

boolean hasNext()

判断容器是否还有可供访问的元素,如果具有更多元素,则返回true

用于判断集合是否还有下一个元素

E next()

让迭代器向前进一位 ,并返回前进反指向的元素。

返回指向的当前元素

例:Collection集合的迭代遍历

Collection list = new ArrayList();

list.add(10.12);
list.add(true);
list.add("String");
list.add(new Object());

//获取迭代器
Iterator iterator = list.iterator();
//判断是否还有下一位元素
while(iterator.hasNext()){
    //前进到下一位,并返回当前元素
    Object o = iterator.next();
    System.out.println(o);
}
/*
10.12
true
String
java.lang.Object@1b6d3586

Process finished with exit code 0*/

Q:迭代器最开始并不是指向集合的第一位,当第一次调用next时迭代器才会进入集合指向第一个元素

Collection接口结构

Collection下又细分Set、List两种。

List系列特点:存储的元素是有序的,先存进去的在读取时先出来,集合中的元素都有对应的下标(索引),可以存在重复的元素

Set系列特点:存储的元素无序,集合中的元素没有下标,且存储的元素不可重复

在没有使用泛型前,Collection可以存储任意的Object子类型,使用泛型后,Collection只能存储某个具体的类型。

Q:集合中不能存储基本类型,如果在添加元素时放的是基本类型,会自动装箱;集合中存储的是对象的引用,不是对象本身

常用方法
boolean add(E e);

向集合中添加元素。如果添加成功,则返回true,否则反之

int size();

返回素合中的元素个数

void clear();

清空该集合的元素

boolean contains(Object o);

判断集合中是否包含指定的元素。包含返回true,否则反之

boolean remove(Object o);

删除集合中指定的元素。删除成功返回true,否则反之

boolean isEmpty();

判断集合是否为空。

Object[] toArray();

将该集合转换为一个数组,返回一个Object类型的数组

例:

Collection colls = new ArrayList();

colls.add(100);
colls.add("string");
colls.add(10.12);
colls.add(new Object());
colls.add(true);

System.out.println(colls.isEmpty());
System.out.println(colls.contains(false));
Object[] objects = colls.toArray();
for (Object o : objects) {
	System.out.println(o);
}

System.out.println(colls.size());
System.out.println(colls.remove(10.12));
System.out.println(colls.size());

colls.clear();
System.out.println(colls.size());

/*
false
false
100
string
10.12
java.lang.Object@1b6d3586
true
5
true
4
0

Process finished with exit code 0*/
contains、remove方法

以ArrayList源码为例。

contains
public boolean contains(Object o) {
    return indexOf(o) >= 0;
}

public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

由源码可知,contains方法底层是通过被参数去调用equals方法,从而去比较集合中的各个元素

存储到集合的元素强烈建议重写equals方法,不然在判断集合中是否包含某个对象时比较的是地址值

例:contains比较两个String元素

Collection c = new ArrayList();

String s1 = new String("123");
c.add(s1);

String x = new String("123");

System.out.println(c.contains(x));
/*
true

Process finished with exit code 0*/

c.contains(x) == x.equals(s1),而String的equals是比较内容的,也就是 “123” =?= “123” => true,所以上面返回的是true

如果比较的参数类型继承Object没有重写equals,那么其比较的必须是地址值,两个不同的对象去比较equals那么就返回false。

如果比较的参数类型重写了equals,比较的是内容,就算是两个不同的对象,只要他们的内容相同,那么就返回true

remove
public boolean remove(Object o) {
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
}

ArrayList在做删除元素动作时,底层也会做equals校验

如果集合中有多个重复的元素,那么会删除第一个校验成功的元素。

Q:如果存储的元素类型没有重写equals,那么可能无法删除。因为没有重写过equals的类型,其比较的是两个对象的地址值。

例:remove删除ArrayList中的元素

Collection c = new ArrayList();

String s1 = new String("123");
c.add(s1);
String s2 = new String("123");
c.add(s2);

System.out.println(c.size());// 2

Sting x = new String("123");
c.remove(x);
System.out.println(c.size());//1
/*
2
1

Process finished with exit code 0*/

存在重复的元素只会删除第一个与之校验成功的元素。上面删除的是‘s1’

迭代器的remove方法

获取迭代器Iterator时,迭代器会绑定当前状态下的集合。如果集合结构发生了改变,则需要重新获取迭代器,不然会出现:java.util.CocurrentModificationExcetion异常。

Collection list = new ArrayList();

c.add("hello");
c.add("word");
c.add(12153);

Iterator iterator = list.iterator();
while(iterator.hasNext()){
    Object o = iterator.next();
    if (o.equals(10.12))
        iterator.remove(o);
}
/*
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
	at java.util.ArrayList$Itr.next(ArrayList.java:859)
	at com.collection.IteratorBase.main(IteratorBase.java:7)

Process finished with exit code 1*/

在获取了迭代器后禁止再去改变集合结构(add、remove)。因为此时的迭代器无法主动同步集合的操作,java会认为这是线程不安全的

如果想在迭代时删除集合的元素可以使用迭代器的remove方法,它会去同步集合的删除操作。

Collection list = new ArrayList();

c.add("hello");
c.add("word");
c.add(12153);

Iterator iterator = list.iterator();
while(iterator.hasNext()){
    Object o = iterator.next();
    if (o.equals(10.12))
        iterator.remove(o);
}
集合遍历拓展

1.foreach循环

foreach循环可以与任何实现了Iterable接口的对象一起工作。Collection接口继承了Iterable接口,因此,类库中的任何集合都可以使用foreach做元素遍历

Collection list = new ArrayList();

list.add(10.12);
list.add(true);
list.add("String");
list.add(new Object());

System.out.println("-------------");
for (Object obj:
     list) {
    System.out.println(obj);
}

2.forEachRemaining方法

在Java SE 8中,还可以通过调用forEachRemaining方法并提供一个lambda表达式完成对集合遍历

Collection list = new ArrayList();

list.add(10.12);
list.add(true);
list.add("String");
list.add(new Object());

Iterator iterator = list.iterator();
iterator.forEachRemaining(element -> System.out.println(element));

forEachRemaining方法最好不要与next方法混合使用

上一篇:Buuctf-Web-[ACTF2020 新生赛]Include
下一篇:没有了
网友评论