集合
1.集合框架概述
-
集合 Collection The Collection in Java is a framework that provides an architecture to store and manipulate the group of objects.
数组同样也是对多个数据进行存储操作的结构(此时的存储指内存层面的此时,不涉及持久化的存储)
-
数组存储的特点
- 长度固定:一旦初始化完毕,其长度就不可修改
- 数组类型固定:数组定义好后,只能操作指定类型的数据
-
数组存储的弊端
- 长度不可修改:初始化后,同一个数组对象长度不可再修改
- 增删改效率低
- 缺乏属性或方法
- 无法满足无序、不可重复的需求:数组的存储特点是有序、可重复
-
集合的优点
- 动态长度
- 增删改效率高
- 相应属性或方法
- 有无序、不可重复的Set接口,也有有序、可重复的List接口
-
接口继承树
2. Collection接口
2.1 概述
Collection是单列数据,定义了存取一组对象的方法的集合。
Collection接口是List、Set和Queue接口的父接口,在JDK1.5之前,集合会丢掉容器中所有对象的数据类型,在JDK1.5加了泛型之后,集合可以记住容器中所有对象的数据类型。
2.2 方法
-
添加
add(Object obj)
addAll(Collection coll)
-
获取有效元素的个数
int size()
-
清空 集合
void clear()
-
是否是空集合
boolean isEmpty()
-
是否包含某个元素
boolean contains(Object obj)
:是通过元素的equals方法来判断是否是同一个对象boolean containsAll(Collection c)
:也是调用元素的equals方法来比较的。比较集合中是否包含c集合中的所有元素 -
删除
boolean remove(Object obj)
:通过元素的equals方法判断是否是要删除的那个元素。只会删除找到的第一个元素boolean removeAll(Collection coll)
:取当前集合的差集 -
取两个集合的交集
boolean retainAll(Collection c)
:把交集的结果存在当前集合中,不影响c -
集合是否相等(注意顺序)
boolean equals(Object obj)
-
转成对象数组
Object[] toArray()
-
获取集合对象的哈希值
hashCode()
-
遍历
iterator()
:返回迭代器对象,用于集合遍历
2.3 集合和数组的转换
-
集合到数组:Collection的
toArray()
方法Collection coll1 = new ArrayList();
coll1.add(123);
coll1.add("abc");
coll1.add(new Person("Tom", 18));
Object[] os = coll1.toArray();
for (Object o : os) {
System.out.println(o);
}
/*Output
123
abc
Person{name='Tom', age=18}
*/ -
数组到集合:Arrays的
asList()
方法Collection coll2 = new ArrayList();
String[] str = new String[]{"AA", "BB", "CC"};
coll2 = Arrays.asList(str);
coll2.forEach(String -> System.out.println(String));
/*Output
AA
BB
CC
*/-
深入Arrays的asList()方法
首先查看asList()方法的源码
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}返回的ArrayList类是Arrays的私有类ArrayList,它同样实现了AbstractList接口
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
...
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
....
}可以看到,Arrays中的ArrayList和List接口的ArrayList类是不同的
String[] str = new String[]{"AA", "BB", "CC"};
//此时不再向上转型
ArrayList coll3 = new ArrayList();
coll3 = Arrays.asList(str);//报错
-
3.Iterator迭代器接口
3.1 概述
-
Iterator迭代器主要用于遍历Collection集合中的元素
在设计模式中,迭代器提供一种方式访问一个容器对象中各个元素,而又不暴露该对象的内部细节
-
Collection接口继承了java.lang.Iterable接口,该接口有一个Iterator()方法,每次调用Iterator()方法都会返回一个全新的Iterator对象
3.2 方法
Iterator方法
Modifier and Type | Method and Description |
---|---|
default void | forEachRemaining(Consumer action) Performs the given action for each remaining element until all elements have been processed or the action throws an exception. |
boolean | hasNext() Returns true if the iteration has more elements. |
E | next() Returns the next element in the iteration. |
default void | remove() Removes from the underlying collection the last element returned by this iterator (optional operation). |
Code
使用hasNext()、next()、remove()方法
public class IteratorTest {
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Hello"));
coll.add(false);
Iterator iterator = coll.iterator();
//remove方法
while (iterator.hasNext()){
Object o = iterator.next();
if(o.equals(123)){
iterator.remove();
}
}
iterator = coll.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
/*Output:
456
Person{name='Jerry', age=20}
Hello
false
*/
}
}
3.3 遍历集合的四种方式
先构建一个集合,并添加测试数据
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Hello"));
coll.add(false);
方式一:使用Iterator结合while循环
Iterator iterator = coll.iterator();
//方式一:使用while循环
while(iterator.hasNext()){
System.out.println(iterator.next());
}
方式二:使用foreach语句,本质还是调用Iterator迭代器
for (Object o : coll){
System.out.println(o);
}
方式三:使用Iterator中的forEachRemaining()方法结合Lambda表达式
Iterator iterator = coll.iterator();
//方式三:使用forEachRemaining()方法
iterator.forEachRemaining((Object o)-> System.out.println(o));
//再次遍历输出为空
iterator.forEachRemaining((Object o)-> System.out.println(o));
方式四:使用集合中的forEach()方法结合Lambda表达式
//方式四:使用forEach()方法
coll.forEach((Object o)-> System.out.println(o));
//forEach()方法可多次遍历
coll.forEach((Object o)-> System.out.println(o));
方法引用:
coll.forEach(System.out::println);
参考博客:方法引用
4.Collection子接口之一:List接口
4.1 List接口概述
- List中元素可有序、可重复
4.2 List接口方法
List除了Collection接口外,还增加了一些根据索引来操作集合元素的
void add(int index, Object ele)
:在index位置插入ele元素boolean addAll(int index, Collection eles)
:从index位置开始将eles中 的所有元素添加进来Object get(int index)
:获取指定index位置的元素int indexOf(Object obj)
:返回obj在集合中首次出现的位置int lastIndexOf(Object obj)
:返回obj在当前集合中末次出现的位置Object remove(int index)
:移除指定index位置的元素,并返回此元素Object set(int index, Object ele)
:设置指定index位置的元素为eleList subList(int fromIndex, int toIndex)
:返回从fromIndex到toIndex位置的子集合
4.3 List三个实现类
- java.util.Arraylist:JDK1.2开始,最主要、最常用的实现类,底层使用Object[] elementData存储,线 程不安全但效率高
- java.util.LinkedList:JDK1.2开始,一般使用在频繁增删的场景,底层使用双向链表存储
- java.util.Vector:JDK1.1开始,线程安全但效率低,底层也是使用Object[] elementData存储
4.3.1 List实现类之一:ArrayList
- JDK1.8之前:类似饿汉式,直接创建容量为10的Object数组,扩容时以原先数组的1.5倍起
- JDK1.8:类似懒汉式,第一次调用时才创建容量为10的Object数组,扩容时同JDK1.8之前
4.3.2 List实现类之二:LinkedList
底层是双向链表
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
4.3.3 List实现类之三:Vector
不常用
5. Collection子接口之二:Set接口
5.1 Set接口概述
5.1.1 Set特性
-
Set中元素无序、不可重复
- 无序性:Set的底层也是数组,它存储数据的规则是按照数据的哈希值来决定的,所以这也决定了元素存放位置的数组索引不等于添加顺序。
- 不可重复:保证添加的元素按照
equals()
方法判断时,不能返回true
-
Set判断两个对象相关不是用
==
,而是用equals()
方法Set判断两个对象相关是用
equals()
方法,如果类没有重写equals()
方法,那么它会调用Object类中的equals()
方法,Object的equals()
方法底层仍是使用==
-
Set中没有额外定义新的方法,使用的都是Collection声明的方法
5.1.2 Set添加元素的过程
以HashSet为例:
向HashSet添加元素a时,首先调用元素a所在类的hashCode()方法,得到a的hash值,接着使用该hash值经过某种算法计算出a应该在HashSet底层数组的存放位置
如果该存放位置为空,则直接添加元素a
如果存放位置有b,则调用a所在类的equals方法进行比较
如果相等,则添加失败
如果不等,则添加a(以链表的方式添加,JDK8中会让b仍存在原来的数组中,然后指向a)