零、 复习昨日
一、集合框架体系
二、Collection
三、泛型
四、迭代
五、List(ArrayList、LinkedList)
日期解析的方法签名(字符串–>日期)
- Date parse(String s)
日期格式化的方法签名(日期–>字符串)
- String format(Date date)
运行时异常有哪些,什么特点
- RuntimeException及其子类,编码时不用强制处理
编译期异常有哪些,什么特点
- 除了以上的都是,编码时必须强制处理
异常的处理方式哪些,什么区别
- 抛出,抛出后代码不再执行
- 捕获,捕获后还可以执行
finally干什么的
- 释放资源
throw和throws什么区别
- 位置?throw在方法内,throws在方法参数列表()后
- 后面写?throw后跟1个异常对象,throws后面跟多个异常类名
- 作用?throw是抛出异常对象的,throws只是声明可能要抛出异常类型
数组: 存储多个数据的容器
集合(Collection): 存储多个数据的容器

Collection是集合层次的父接口,定义了所有集合共性操作
Collection有两个常用子接口:List,Set
List接口集合,主要特征是有序,允许重复元素的集合
Set接口集合,主要特征是元素去重
List接口有两个常用实现类
Set接口有两个常用实现类
Collection父接口
List是Collection的子接口,有序允许重复的集合
List是接口,不能只能直接用,常用使其子实现类,ArrayList和LinkedList
- 是List接口的实现类,允许重复,有序
- 底层是数组,大小"可变"
- 是不同步,即不保证线程安全
先演示了部分方法,主要对集合元素
增 删 改 查
public static void main(String[] args) {
// 创建空集合
ArrayList list = new ArrayList( );
System.out.println("初始值: " + list);
// 向末尾添加元素
// 有序(插入顺序),允许重复,允许存储不同类型
list.add(4);
list.add(2);
list.add(2);
list.add(5);
list.add("六");
System.out.println("添加值:" + list);
// 向指定下标插入数据
list.add(2, 1);
System.out.println("中间插入:" + list);
// 获得指定下标的元素
Object o = list.get(2);
System.out.println(o);
// 按照下标修改元素
list.set(2, 100);
System.out.println("修改后:" + list);
// 按下下标删除元素
Object old = list.remove(0);
System.out.println("被删除掉的元素:" + old );
System.out.println("删除后的集合:"+list );
}
private static void show2() {
/**
* 集合确实可以允许存储不同类型数据
* 但是大部分情况下,集合只会存储同一类型
* -----------
* 目前这种情况,设计时存储的是Object
* 取出数据也是Object,需要使用对应数据类型时需要强转
* 但是强制转换有风险
* ---------------------
* 所以,在JDK1.5时引入泛型 ,通过泛型就可以解决这个问题
*/
ArrayList list = new ArrayList( );
list.add(1);
list.add(2.0);
list.add("3");
list.add(new Date( ));
double o = (double) list.get(0);
System.out.println(o );
System.out.println("-------------------------" );
/**
* 下面使用泛型来定义集合
* 通过在类名后,指定泛型类型,从而确定该集合只能存储指定类型
* -------------
* 泛型好处: 减少类型转换(强转)
*/
ArrayList<Integer> list2 = new ArrayList<>( );
list2.add(1);// 有了泛型约束,存储时只能是Integer
list2.add(2);
list2.add(3);
Integer i = list2.get(2);// 有了泛型约束,取出就是Integer,无需强转
}
以后,凡是用集合操作,必用泛型!!
/**
* 演示ArrayList其他方法
*/
private static void show3() {
ArrayList<Integer> l1 = new ArrayList<>( );
l1.add(11);
l1.add(22);
l1.add(33);
System.out.println("原始l1:" + l1 );
ArrayList<Integer> l2 = new ArrayList<>( );
l2.add(10);
l2.add(20);
l2.add(30);
// 将另外一个集合中的全部元素加入当前集合
l1.addAll(l2);
System.out.println("addAll后: " + l1);
// 移除当前集合中,存在于参数集合相同的元素
l1.removeAll(l2);
System.out.println("移除后:" + l1 );
// 判断集合是否为空
System.out.println(l1.isEmpty( ));
// 存储的元素的个数
int size = l1.size( );
System.out.println("集合元素个数:" + size );
// 判断集合是否包含某个元素
System.out.println(l1.contains(11));
// 先创建整型数组
Integer[] integers = new Integer[l1.size( )];
// 再将集合转成数组
Integer[] array = l1.toArray(integers);
System.out.println(Arrays.toString(array));
// 清空集合
l1.clear();
System.out.println("清空后: " + l1 );
// 判断集合是否为空
System.out.println(l1.isEmpty( ));
}
集合遍历
// 使用迭代器遍历
public static void main(String[] args) {
/**
* 使用迭代器遍历
*/
ArrayList<Integer> list = new ArrayList<>( );
list.add(4);
list.add(2);
list.add(1);
list.add(3);
// 1)获得迭代器
Iterator<Integer> iterator = list.iterator();
// 2)遍历迭代
while (iterator.hasNext()) {// 判断有无下一个元素,如果有返回true
Integer next = iterator.next( );// 取出下一个元素
System.out.println(next );
}
}
// foreach迭代
public static void main(String[] args) {
/**
* 使用迭代器遍历
*/
ArrayList<Integer> list = new ArrayList<>( );
list.add(4);
list.add(2);
list.add(1);
list.add(3);
// 1)获得迭代器
Iterator<Integer> iterator = list.iterator();
// 2)遍历迭代
while (iterator.hasNext()) {// 判断有无下一个元素,如果有返回true
Integer next = iterator.next( );// 取出下一个元素
System.out.println(next );
}
// 迭代器的简化写法: 增强for循环,也叫foreach
/**
* for(数据类型 变量 : 集合) {
*
* }
*/
for (Integer i : list) {
System.out.println(i );
}
// 遍历数组
int[] arr = {1,2,3,4};
for(int i:arr){ // 冒号左边是遍历得到的结果,不是下标!!!
System.out.println(i);
}
}
- ArrayList底层是数组实现的
- 起始容量(数组长度)默认是10
- 刚new完创建的空集合的,容量是0
- 当第一次加入元素的时候,数组扩容成10
- 当元素放满10个时,当加入第11个时候会触发扩容,扩容为原来的1.5倍(通过 >> 1 右移1位算出来)
- 扩容成1.5倍后,再把原数组的元素拷贝到新数组
// 扩容的源码 (ArrayList.java(
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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);
}
这个函数是用于增长数组容量的。当数组容量不足时,它将根据最小需求容量(minCapacity)来计算新的容量大小,并确保新的容量大于当前需求。若新容量小于需求,则将新容量设置为需求容量。若新容量超过最大数组大小,则调用hugeCapacity方法来处理。最后,通过Arrays.copyOf方法复制原数组到新的容量中。
使用上效率问题
原因
LinkedList也是List实现类,也是允许元素重复,有序的集合
LinkedList也是List实现类,大部分方法与ArrayList一模一样用法,不再演示
略
自习尝试,
除了基本的方法与ArrayList一样之外,LinkedList还提供一些比较特殊的操作头尾的方法
- getFirst getLast
- removeFirst removeLast
- addFirst addLast
public static void main(String[] args) {
LinkedList<Integer> l1 = new LinkedList<>( );
l1.add(11);
l1.add(22);
l1.add(33);
// 获得头 尾操作
Integer first = l1.getFirst( );
Integer last = l1.getLast( );
System.out.println(first );
System.out.println(last );
}
LinkedList底层是双向链表
- 链表在内存中是不连续
- 通过链域里面记录上一个/下一个元素的位置

当通过下标找寻一个元素的时候,并不是直接定位的,是从头或者尾开始一个一个遍历查找对应的元素,也正是因为如此,所以提供了专门操作头尾的方法的,可以直接定位到,方便操作
又因为这个空间数据结构问题,导致了一些特性
- LinkedList查询,更新数据慢
- LinkedList插入,删除的快
- 因为插入/删除元素改变的知识链域的记录信息,没有改变其他元素位置
- 记住集合体系的各自特点
- 牢记ArrayList方法,底层原理
- LinkedList了解原理