集合框架的意义
对于一般的数组,是定长的线性存储结构,所以对于数据量不确定的对象,使用数组存储就不再适用了,集合框架就是对此提出的解决方案
从上图我们可以知道,Java集合框架类型分为两大类:Collection 和 Map,这一章我们主要简单了解一下 Collection 及其子类
Collection 接口存储对象可以是不唯一的,无序的
List 接口存储的对象可以是不唯一的,但是有序的
Set 接口存储对象是唯一且无序的
Map 接口存储对象以键值对的形式存在,提供 key 到 value 的映射
ArrayList
List 接口继承自 Collection 接口,常涉及的子类包括:ArrayList、LinkedList,两者最大的区别在于实现方式:前者采用数组
ArrayList 实现了长度可变的数组,在内存中分配连续的空间,因此遍历元素和随机访问元素的效率较高
常用方法如下
用法举例如下
public class TestArrayList {
public static void main(String[] args) {
// 当未使用泛型时,可以混合存储数据或对象
ArrayList numList = new ArrayList();
// 若不指定存储位置,默认在集合结尾处添加
numList.add(1);
numList.add("2");
numList.add(3.0);
// 指定位置,数据插入,而非覆盖
numList.add(1, "666");
// 查看元素,需向上转型
Object o = numList.get(2);
System.out.println(o);
System.out.println(numList.get(1));
// 计算大小
System.out.println(numList.size());
// 遍历集合
for (int i = 0; i < numList.size(); i++) {
System.out.print(numList.get(i) + " ");
}
System.out.println();
// 增强for遍历
for (Object num : numList) {
System.out.print(num + " ");
}
System.out.println();
// 查找
System.out.println(numList.contains(777));
// 当泛型确定类型时,不能容纳其他类型数据或对象
ArrayList<Student> studentList = new ArrayList();
// 当处理对象时
studentList.add(new Student("tom"));
studentList.add(new Student("jerry"));
studentList.add(new Student("kitty"));
Student tom = new Student("tom");
// 注意比较存储对象和存储值的区别
System.out.println(studentList.contains(tom));
// 删除元素
// 方法1:通过下标,返回对象
System.out.println(studentList.remove(2));
// 方法2:通过对象引用删除,该方法是无法删除的
// 因为tom变量中保存的地址值,不在studentList里面
System.out.println("remove:" + studentList.remove(tom));
// 方法3:先查找到要删除的元素
Student foundStudent = null;
for (Object stuObj : studentList) {
// 由于student对象保存到集合时,做了类型擦除(向上转型为Object)
// 所以取出对象时,要做强转
Student stu = (Student) stuObj;
if ("tom".equals(stu.getName())) {
foundStudent = stu;
break;
}
}
// 再进行删除
if (foundStudent != null) {
System.out.println("remove:" + studentList.remove(foundStudent));
}
}
}
ArrayList扩容机制
我们可以将 ArrayList 理解为可变长数组,这得益于其独有的扩容机制
我们只需要知道 ArrayList 扩容机制为 1.5 ,我们来看看它的源码
private void grow(int minCapacity) {
// overflow-conscious code
// oldCapacity为旧容量,newCapacity为新容量
int oldCapacity = elementData.length;
// 将oldCapacity右移一位,其效果相当于oldCapacity/2
// 再加上原值,即扩充了1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
LinkedList
LinkedList 实现方法不同于 ArrayList ,采用的是链表结构
由于LinkedList由链表实现,LinkedList 提供对头部和尾部元素进行添加和删除操作的方法 ,也可以在集合任何位置(头部、中间、尾部)添加、获取、删除集合对象
因此,插入、删除操作频繁时,可使用 LinkedList 来提高效率
常用方法如下:
使用方法两者别无二致,我们不再赘述
用法举例如下
public class TestLinkedList {
public static void main(String[] args) {
LinkedList studentList = new LinkedList();
studentList.addLast(new Student("tom1"));
studentList.addLast(new Student("tom2"));
studentList.addFirst(new Student("tom3"));
System.out.println(studentList.getFirst());
System.out.println(studentList.getLast());
System.out.println(studentList.get(1));
studentList.removeFirst();
}
}