一、引入
为什么要学集合?有数组不就够了吗。
数组特点 | 缺点 |
---|---|
长度不可变 | 长度不可变 |
只能存放同数据类型 | 增删效率低 |
存储有序,可重复 | 无法获取实际存放元素数量 |
所以要学集合。
- 底层结构是链表的集合增删快,底层结构是数组的查询快
- 可以获取实际存放元素数量
- 可有序,可无序
- 可重复,不可重复
- 集合长度可变
等等
二、简要集合结构图
三、Collection
3.1 常用方法
Collection接口的常用方法:
- 增加:add(E e) addAll(Collection<? extends E> c)
- 删除:clear() remove(Object o)
- 修改:
- 查看:iterator() size()
- 判断:contains(Object o) equals(Object o) isEmpty()
创建对象:接口不能创建对象,利用实现类创建对象:
Collection col = new ArrayList();
集合有一个特点:只能存放引用数据类型的数据,不能是基本数据类型
基本数据类型自动装箱,对应包装类。int—>Integer
col.add(18);
add方法相信大家也没咋注意过吧
transient Object[] elementData; // non-private to simplify nested class access
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
什么是transient关键字?
- transient关键字只能修饰变量,而不能修饰方法和类。
- 一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
- 什么意思呢,就是这个关键字的修饰的变量是不能被直接存的,这个值是计算出来的,不需要存,一般情况下是不能离开JVM的,不能被序列化。
数组转集合
List list = Arrays.asList(new Integer[]{11, 15, 3, 7, 1});
//将另一个集合添加到集合中
col.addAll(list);
asList直接生成一个新列表
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
addAll是数组拷贝,然后size相加
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
clear 清空list
循环将每个因为置为空,帮助GC回收
大小置为0
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
col.remove(15);//删除15这个值的元素
看代码显然只删第一个叫15的元素
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;
}
col2.equals(col3);
判断两个集合是否相等,一个个每一个位对比。
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
ListIterator<E> e1 = listIterator();
ListIterator<?> e2 = ((List<?>) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
instanceof运算符用法
instanceof 是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。null instanceof 任何都是false。
==比较集合,比较的是地址
contains()是否包含元素
@Override
public int indexOf(Object o) {
E[] a = this.a;
if (o == null) {
for (int i = 0; i < a.length; i++)
if (a[i] == null)
return i;
} else {
for (int i = 0; i < a.length; i++)
if (o.equals(a[i]))
return i;
}
return -1;
}
@Override
public boolean contains(Object o) {
return indexOf(o) != -1;
}
3.2 遍历方法
对集合遍历(对集合中元素进行查看)
方式1:普通for循环
/*for(int i= 0;i<col.size();i++){
col. //发现问题了吧,没有get方法!!因为是 Collection接口,没有get方法
}*/
方式2:增强for循环
for(Object o:col){
System.out.println(o);
}
方式3:迭代器 iterator()
Iterator it = col.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//ArrayList类内
public Iterator<E> iterator() {
return new Itr();
}
//ArrayList类的内部类
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
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];
}
....
}