集合概述
集合的本质是容器,之前的数组,StringBuilder,都属于简单的容器。但是他们不适用于很多场景,比如数组,创建的时候需要有长度,StringBuilder存储完之后自动给你转换为数组。
为了适用于不同的场景,我们需要多种不同的容器。
在现实生活中,我们装不同的东西使用不同的容器,即使装同一种东西在不同的场合,也需要不同的容器。
比如我们喝水用水杯,而烧水时用茶壶,洗脚用盆!
虽然你也可以直接用茶壶喝,这属于找茬,那这样盆能不能喝水?
集合的特点
- 集合是用于存储对象的容器(但是不能存储基本数据类型,组数可以)
- 集合的长度是可变的(数组的长度不可变)
集合的根接口-Collection
Collection是集合层次结构中的根接口,我们在学习框架体系时,学习顶层,使用时用底层
集合的本质是存储对象的容器。
Collerction既然是集合框架的顶层接口(跟接口)那么他就比如定义了集合的共性方法。
- 添加元素
- boolean add(E e) 添加一个元素
- 添加集合 boolean addAll(Collection<? extends E> c) 添加一堆元素
- 删除元素
- boolean remove(Object o) 删除一个
- boolean removeAll(Collection<?> c) 删除一堆
- void clear() 删除所有元素
- 判断元素
- boolean contains(Object o)是否包含某个对象
- boolean containsAll(Collection<?> c) 是否包含某一堆对象
- boolean isEmpty() 是否为空(集合中没有元素返回true)
- 获取元素
- int size() 返回此 collection 中的元素数
- Iterator iterator()返回在此 collection 的元素上进行迭代的迭代器(迭代器是专门用于取出集合容器的工具,当需要获取容器中的元素时,就使用该工具)
- 其他方法
- boolean retainAll(Collection<?> c)移除此 collection 中未包含在指定 collection 中的所有元素(获取交集)
- Object[] toArray()集合转为相应类型的数组
迭代器 Iterator
Iterator是对 collection 进行迭代的迭代器(取出集合元素的工具)
- 首先使用Collection中的 Iterator iterator()方法获取迭代器。
- 再使用迭代器对集合进行元素的操作。
- boolean hasNext() 是否有可以迭代的元素。
- E next() 迭代下一个元素
- void remove()从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)
- 迭代器两种使用方式的比较
public static void iteratorTest() {
Collection coll = new ArrayList();
coll.add("a1");
coll.add("a2");
coll.add("a3");
//使用迭代器的第一种方式
Iterator iterator = coll.iterator();
while (iterator.hasNext()) {
System.out.println("iterator.next() = " + iterator.next());
}
//使用迭代器的第二种方式
for(Iterator it2=coll.iterator();it2.hasNext();){
System.out.println("it2.next() = " + it2.next());
}
}
从实际使用的角度,第二种要优于第一种,在实际开发中,代码不会只有这么一点,而第一个在使用完之后,迭代器仍然会占用内存空间,而第二种则在迭代完之后就释放了。
而迭代器的实现是每种容器通过内部类自己实现的
eg:这是在ArrayList中实现迭代器的源代码
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor;
int lastRet = -1;
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
集合使用规则和技巧
是否唯一
- 是:使用Set
- 是否需要指定顺序
- 需要:TreeSet
- 不需要:HashSet
- 想要一个和存储顺序一致的集合:LinkedHashSet
- 是否需要指定顺序
- 否:使用List
- 是否需要频繁增删
- 需要:LinkedList
- 不需要:ArrayList
- 是否需要频繁增删
各个容器的结构和所属的体系
- List
- |–ArrayList
- |–LinkedList
- Set
- |–HashSet
-|–TreeSet
- |–HashSet
- 后缀名就是该集合所属的体系。
- 前缀名就是该集合的数据结构。
各种集合的特点
- Array:数组,查询快,有角标
- Link:链表,增删快
- hash:哈希表 唯一性,元素需要覆盖hashCode和equals方法
- tree:二叉树,排序,实现Comparable或者Comparator接口