一、集合
1.1 集合介绍
数组: 是一个容器,用来存放数据的
- 定长
- 只能存储同一种数据类型的数据
- int[] 可以存储int值,Student[] 可以存储引用类型
- 只有一个length属性,没有方法,使用时功能简单
集合: 是一个容器,用来存放数据的
- 不定长
- 存各种各样类型
- 只能存储引用类型
- 提供了操作数据的各种方法
1.2 集合划分图示
二、Collection
2.1 Collection介绍
- Collection是
单列
集合层次结构中的根接口 - 一些 集合允许有重复的元素,而另一些则不允许。一些 集合是有序的,而另一些则是无序的
- Collection下面的一些子实现类有些有重复元素,有些没有,有些可以有序,有些无序
2.2 常用方法
- 注:Collection是接口,不能创建对象,为了演示这些API,需要使用子实现类,使用最常用的ArrayList集合来实现方法
说明 | 方法签名 | 返回值 |
---|---|---|
添加元素 | boolean add(E e) | 布尔值 |
添加集合进行批量元素 | boolean addAll(Collection c) | 布尔值 |
根据元素删除 | boolean remove(Object o) | 布尔值 |
根据集合进行删除 | boolean removeAll(Collection c) | 布尔值 |
保留指定数据 | boolean retainAll(Collection c) | 布尔值 |
删除全部数据 | void clear() | 无 |
集合长度 | int size() | int 整型 |
判断是否为空 | boolean isEmpty() | 布尔值 |
判断是否包含 | boolean contains(E e) | 布尔值 |
public static void main(String[] args) {
// Collection是接口,不能直接创建对象
// 但是当做父引用指向子类对象
Collection col = new ArrayList(); // 向上转型
// 存放元素 add(Object o)
col.add(1);// 1--> 自动装箱Integer对象 --> Object
col.add("a");
col.add(new Date( ));
System.out.println(col );
// 再创建集合
Collection col2 = new ArrayList();
col2.add(11);
col2.add(22);
col2.add(33);
// 批量添加 addAll(Collection c)
col.addAll(col2);// 将参数与集合中的所有数据都添加到当前集合
System.out.println(col );
// 移除元素
// boolean remove(Object o) 删除指定元素
boolean r1= col.remove(-11);
System.out.println("删除是否成功:" + r1 );
System.out.println("删除后: "+col );
// boolean removeAll(Collection<?> c)
// 批量删除
// col.removeAll(col2);// 删除指定数据
// System.out.println("批量删除后: " + col );
// 保留全部(反向删除)
// boolean retainAll(Collection<?> c)
col.retainAll(col2);// 保留指定数据,删除其他数据
System.out.println("保留全部"+col );
// 删除全部数据(清空)
// col.clear();
// System.out.println("清空: "+col );
// 获得集合大小(尺寸/容量)
int size = col.size( );
System.out.println(size );
// 判断集合是否为空(没有元素,长度为0即为空)
boolean empty = col.isEmpty( );
System.out.println(empty );
// 判断集合是否包含指定元素
// contains
boolean contains = col.contains(11);
System.out.println("是否包含:" + contains );
}
三、遍历
3.1 迭代
迭代,就是遍历,将集合元素迭代,目的是取出元素.
public static void main(String[] args) {
Collection col = new ArrayList( );
col.add(1);
col.add(2);
col.add(3);
col.add(4);
col.add(5);
col.add(6);
// 遍历(迭代)集合
// 1) 获得迭代器
Iterator iterator = col.iterator( );
// 2) 通过迭代器完成迭代(遍历)
while(iterator.hasNext()){// hasNext() 判断是否有元素
Object o = iterator.next( );// 获取元素,移动指针
System.out.println(o );
}
}
3.2 增强for循环(foreach)
public static void main(String[] args) {
Collection col = new ArrayList( );
col.add(1);
col.add(2);
col.add(3);
col.add(4);
col.add(5);
col.add(6);
// 遍历(迭代)集合
// 1) 获得迭代器
Iterator iterator = col.iterator( );
// 2) 通过迭代器完成迭代(遍历)
while(iterator.hasNext()){// hasNext() 判断有无下一个
Object o = iterator.next( );// next()取出下一个元素
System.out.println(o );
}
// 使用增强for循环,改写迭代器遍历
/**
* for(数据类型 变量:集合/数组){
*
* }
* 1) 冒号右边是写要被遍历的集合或者数组对象
* 2) 每次从集合或者数组取出的值赋值给左边变量
*/
System.out.println("-------" );
for (Object o : col){
System.out.println(o );
}
System.out.println("----------" );
int[] arr = {11,22,33,44};
for (int i : arr){
System.out.println(i );
}
}
四、泛型
-
泛型在集合中主要是用来规定数据类型的.
-
语法: 设计时 <类型> , 例如
<E> <K> ,<K,V> <T>
ps: E,K,V,T这些都是见名知意的简写,其实是可以随意写的
使用时(创建类对象)指定泛型,即指定明确的数据类型<String> <Integer>
-
作用:
- 约束集合存储的数据类型
- 避免数据类型转换
-
泛型: 可以研究泛型类,泛型参数,泛型方法等等…
public static void main(String[] args) {
// 没有泛型
Collection col = new ArrayList();
// 类型没有限制
col.add(1);
col.add("2");
col.add(1.1);
// for (Object o : col){
// String s = (String) o;
// }
// 使用泛型
Collection<String> col2 = new ArrayList<>();
// 就可以限制数据类型
col2.add("A");
col2.add("B");
for (String s : col2){
System.out.println(s );
}
// 使用泛型
Collection<Integer> col3 = new ArrayList<>();
col3.add(1);
col3.add(2);
col3.add(3);
for (Integer i : col3){
System.out.println(i );
}
/**
* 为什么要用泛型?
* 1) 经验: 虽然集合可以存储多种数据类型,但是大部分场景都是只存同一种数据
* 2) 最主要的原因是: 没有泛型,类型太杂,需要使用指定类型还需要强制
* 但是强制还容易报错
* 所以:泛型的好处就会可以约定数据类型,从而减少数据类型转型
*/
}
五、List集合
5.1 List介绍
- List是Collection的子接口
- List是有序集合: 有序是指集合迭代顺序和插入顺序一致
- List集合允许重复元素!!
- List集合提供了可以针对索引(下标)操作元素的方法
5.2 常用方法
- List接口中的方法大部分与父接口Collection中一致,
但是除此之外的方法,确实提了可以通过下标操作元素(CRUD)的方法 - List是接口,没有办法演示其中的方法
- List接口有两个常用的实现类:ArrayList和LinkedList
说明 | 方法标签 | 返回值 |
---|---|---|
根据下标位置加入元素 | void add(int index,E e) | 无 |
根据下标位置移除元素 | E remove(int index) | 返回被删除的元素 |
根据下标位置进行修改 | E set(int index,E e) | 返回被修改的元素 |
根据下标位置获得元素 | E get(int index) | 返回获得的元素 |
5.3 ArrayList[重点]
- ArrayList实现了List接口,即ArrayList也是有序集合,也允许重复元素,且那些关于下标操作集合的方法ArrayList都有!
- ArrayList不保证线程安全
- ArrayList底层是数组,大小可变是指它会扩容(不是真正大小可变)
5.3.1构造方法
- ArrayList() 创建空集合,默认创建了一个长度为10的数组
- ArrayList(Collection c) 创建一个集合,集合内直接就有指定的参数
- ArrayList(int initialCapacity) 创建一个指定初始化容量的数组
ArrayList<Integer> list = new ArrayList<>( );
5.3.2 常用方法:
- 其他的方法上午在Collection中已经学过
- void add(int index,E e)
- E remove(int index)
- E get(int index)
- E set(int index,E e)
public static void main(String[] args) {
// 定义泛型
// 空参构造,创建空集合(默认容量10)
ArrayList<Integer> list = new ArrayList<>( );
// 最基本的添加方法
list.add(3);
list.add(1);
list.add(1);
list.add(4);
list.add(4);
list.add(2);
// 遍历(保证顺序-->有序)
// 允许重复元素
for (Integer i : list) {
System.out.println(i );
}
// 其他常规方法不再演示
// 主要掌握关于下标的方法
// 311442
// 按照下标插入 add(int i,E e)
list.add(3,0);
System.out.println(list );
// 按照下标获得元素(取值) E get(int i)
Integer e = list.get(4);
System.out.println("下标4的值: " + e );
// 按照下标修改值 E set(int i,E e)
Integer old = list.set(4, 10);
System.out.println("修改后的集合:" + list );
System.out.println("返回的数据:" + old );
// 按照下标删除 E remove(int i)
Integer remove = list.remove(4);
System.out.println("删除下标3的数据后:" + list );
System.out.println("返回的数据:" + remove );
}
5.3.3 底层原理[掌握|理解]【面试】
- ArrayList底层是使用数组
,
默认长度是10,但是存储元素多于10时会扩容.
如何扩容的?
- 当加入元素时,先判断加入后会不会超出默认长度
- 如果没有超出默认长度
- add(Object o) 元素直接放最后
- add(int index,Object o) 先将该位置以后的元素依次往后移动一个,然后再将该元素放入该位置
- 当加入元素时,判断加入后长度会不会超出容量,如果超出就要扩容
- 扩容是创建一个新的数组,容量是原来的1.5倍
- 将原来数组的元素依次拷贝到新数组
- 然后再放入新元素
// jdk源码
private void grow(int minCapacity) {
//
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);// 1.5倍
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);
}
/*
给定的代码是一个名为"grow"的方法,用于增加数组的容量。它接受一个参数"minCapacity",表示数组应该具有的最小容量。
以下是代码的逐步解释:
1. 方法首先使用"elementData"数组的"length"属性获取当前容量。
2. 然后通过将旧容量的一半加上旧容量本身来计算新容量。这是使用右移运算符(>>)实现的,它将值除以2。
3. 接下来,它检查新容量减去最小容量是否小于0。如果这个条件为真,说明新容量不足以满足所需的最小容量。在这种情况下,它将新容量设置为等于最小容量。
4. 然后,它检查新容量减去最大数组大小是否大于0。如果这个条件为真,说明新容量超过了数组允许的最大大小。在这种情况下,它调用"hugeCapacity"方法来计算一个在允许范围内的新容量。
5. 最后,它使用"Arrays.copyOf"方法创建一个具有更新容量的新数组。"elementData"数组被赋予新数组,从而增加了其容量。
总之,"grow"方法增加数组的容量以满足最小容量要求,并确保不超过允许的最大大小。
*/
5.3.4 特点[记住]
- ArrayList特点: 1) 有序 2) 重复 3) 查询更新效率高 4) 删除插入效率低
- 应用场景: 适合那些查询频率高的地方. 且基本大部分场景都是经常查不经常删除和插入的,所以呢ArrayList就非常常用!!! 如果以后没有特殊说明,直接就使用ArrayList!!
5.4 LinkedList[熟悉]
- LinkedList是List的实现类,那么LinkedList也是允许重复,有序
且LinkedList集合也有关于下标操作集合的方法,但是还提供了一些关于操作开头和结尾的方法
entData"数组被赋予新数组,从而增加了其容量。
总之,"grow"方法增加数组的容量以满足最小容量要求,并确保不超过允许的最大大小。