Java初学笔记18
- 一、 集合介绍
- 二、集合的框架体系
- 三、Collection接口
- 四、List接口
- 1. 介绍
- 2. 常用方法
- (1)void add(int index, Object ele):在 index 位置插入 ele 元素
- (2)boolean addAll(int index, Collection eles):从 index 位置开始将 eles 中的所有元素添加进来
- (3)Object get(int index):获取指定 index 位置的元素
- (4)int indexOf(Object obj):返回 obj 在集合中首次出现的位置
- (5)int lastIndexOf(Object obj):返回 obj 在当前集合中最后一次次出现的位置
- (6)Object remove(int index):移除指定 index 位置的元素,并返回此元素
- (7)Object set(int index, Object ele):设置指定 index 位置的元素为 ele
- (8)List subList(int fromIndex, int toIndex):返回从 fromIndex 到 toIndex 位置的子集合
- 五、ArrayList类
- 六、Vector类
- 七、ArrayList类与Vector类的比较
- 八、LinkedList类(链表类)
- 九、ArrayList类与LinkedList类的比较
【难点】
1.理解集合的底层机制
2.阅读原码
3.何时使用何种集合
一、 集合介绍
-
保存多个数据使用的是数组,那么数组有不足的地方
(1)长度开始时必须指定,而且一旦指定,不能更改;
(2)保存的必须为同一类型的元素;
(3)使用数组进行增加/删除元素,比较麻烦;
(4)数组扩容比较麻烦 -
故引出----->集合
(1)可以动态保存任意多个对象,使用比较方便!
(2)提供了一系列方便的操作对象的方法: add、remove、set、get等
(3)使用集合添加,删除新元素更简洁了
二、集合的框架体系
Java 的集合很多,主要分为两大组:
Collection单列集合 与 Map双列集合。
-
Collection 单列集合(存放单个对象)
(1)Collection 接口有两个重要的子接口 List 和 Set , 他们的实现子类都是单列集合
-
Map 双列集合(存放键值对)
(1)Map 接口的实现子类 是双列集合,存放的 K-V
三、Collection接口
1. Collection接口实现类的特点
(1)Collection接口:
public interface Collection extends Iterable
(2)collection实现子类可以存放多个元素,每个元素可以是Object
(3)有些Collection的实现类,可以存放重复的元素,有些不可以
(4)有些Collection的实现类,有些是有序的(List),有些不是有序(Set)
(5)Collection接口没有直接的实现子类,是通过它的子接口Set和 List来实现的
2. Collection接口里面的方法
【以ArrayList类为例演示方法:public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, java.io.Serializable】
List list = new ArrayList();
(1)add:添加单个元素
list.add("jack");
list.add(10);//实际上为list.add(new Integer(10))
list.add(true);
(2)remove:删除指定元素
list.remove(0); //删除第一个元素
list.remove(true);//指定删除某个元素
删除的时候也是要计算hashcode。如果人为的更改了hashcode,将会删除失败!!
(3)contains:查找元素是否存在
System.out.println(list.contains("jack"));//T
(4)size:获取元素个数
System.out.println(list.size()); //2
(5)isEmpty:判断是否为空
System.out.println(list.isEmpty());//F
(6)clear:清空
list.clear();
(7)addAll:添加多个元素
ArrayList list2 = new ArrayList();
list2.add("红楼梦");
list2.add("三国演义");
list.addAll(list2);
(8)containsAll:查找多个元素是否都存在
System.out.println(list.containsAll(list2));//T
(9)removeAll:删除多个元素
list.add("聊斋");
list.removeAll(list2);
System.out.println("list=" + list); //[聊斋]
3. Collection接口遍历元素方式1–>使用Iterator(迭代器)
(1)Iterable接口中,有一个可以返回Iterator接口类型的方法iterator()。iterator()对象称为迭代器,主要用于遍历Collection集合中的元素
(2)Iterator接口中有几个方法:
1)boolean hasNext();//判断是否还有下一个元素
2)E next(); //①指针下移②将下移以后集合位置上的元素返回
注意:在调用iterator.next()方法之前必须要调用iterator.hasNext()进行检测。若不调用,且下一条记录无效,直接调用iterator.next()会抛出NoSuchElementException异常。
(3)所有实现了Collection接口的集合类都有一个iterator()方法,该方法返回一个实现了lterator接口的对象,即可以返回一个迭代器。
(4)Iterator仅用于遍历集合,Iterator本身并不存放对象。
(5)迭代器配合while循环、hasnext()方法、next()方法使用,且hasnext()方法必须在next()方法之前使用,此外当迭代器移动到最后一个位置时候,要想重新遍历,需要重置迭代器
(6)代码示例
接口类型的变量col 可以指向实现了Collection接口类的对象实例
Collection col = new ArrayList();
col.add(new Book("三国演义", "罗贯中", 10.1));
col.add(new Book("小李飞刀", "古龙", 5.1));
col.add(new Book("红楼梦", "曹雪芹", 34.6));
//System.out.println("col=" + col);
//现在希望能够遍历 col 集合
1. 先得到 col 对应的 迭代器
Iterator iterator = col.iterator();
2. 使用 while 循环遍历
// while (iterator.hasNext()) {//判断是否还有数据
// //返回下一个元素,类型是 Object
// Object obj = iterator.next();
// System.out.println("obj=" + obj);
// }
//快捷键,快速生成 while => itit
//显示所有的快捷键的的快捷键 ctrl + j
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println("obj=" + obj)
}
//3. 当退出 while 循环后 , 这时 iterator 迭代器,指向最后的元素
// iterator.next();//NoSuchElementException
//4. 如果希望再次遍历,需要重置我们的迭代器
iterator = col.iterator();
System.out.println("===第二次遍历===");
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println("obj=" + obj);
}
(7)快捷键
快捷键,快速生成 while ,用 itit
显示所有的快捷键的的快捷键 ,用ctrl + j
for循环增强,用I
4. Collection接口遍历元素方式2–>for循环增强
(1)简化版的Iterator
(2)快捷键:for循环增强,I
(3)代码示例:
for (Object object : col){
System.out.println(object);
}
【迭代器练习题】
四、List接口
1. 介绍
(1)List接口是Collection 接口的子接口
(2)List集合类中元素有序(即添加顺序和取出顺序一致)、且元素可重复
(3)List集合中的每个元素都有其对应的顺序索引,即支持索引。索引从0开始。
(4)List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
2. 常用方法
List list = new ArrayList();
list.add("张三丰");
list.add("贾宝玉");
(1)void add(int index, Object ele):在 index 位置插入 ele 元素
在 index = 1 的位置插入一个对象
list.add(1, "大志");
(2)boolean addAll(int index, Collection eles):从 index 位置开始将 eles 中的所有元素添加进来
List list2 = new ArrayList();
list2.add("jack");
list2.add("tom");
list.addAll(1, list2);
(3)Object get(int index):获取指定 index 位置的元素
(4)int indexOf(Object obj):返回 obj 在集合中首次出现的位置
System.out.println(list.indexOf("tom"));//2
(5)int lastIndexOf(Object obj):返回 obj 在当前集合中最后一次次出现的位置
list.add("大志");
System.out.println(list.lastIndexOf("大志"));
(6)Object remove(int index):移除指定 index 位置的元素,并返回此元素
list.remove(0);
(7)Object set(int index, Object ele):设置指定 index 位置的元素为 ele
相当于是替换
list.set(1, "玛丽");
(8)List subList(int fromIndex, int toIndex):返回从 fromIndex 到 toIndex 位置的子集合
注意 [ fromIndex, toIndex )
List returnlist = list.subList(0, 2); // [ 0 , 2 )
五、ArrayList类
1. 介绍
(1)“permits all elements, including null" ArrayList可以加入null,并且多个
(2)ArrayList是由数组来实现数据存储的
(3)ArrayList基本等同于Vector,除了 ArrayList是线程不安全(执行效率高),在多线程情况下,不建议使用ArrayList。
2. ArrayList的底层操作机制
(1)ArrayList中维护了一个的数组elementData,数组类型为Object。
transient Object[] elementData;
(2)当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍,依次都是1.5倍扩容。
(3)如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。依次完后都是1.5倍扩容。
3. ArrayList的底层源码分析(无参构造器)
(1)示例代码:
package demo.arraylist_;
import java.util.ArrayList;
/**
* @Package: demo.arraylist_
* @ClassName: ArrayList_
* @Author: 爱吃凉拌辣芒果
* @CreateTime: 2021/10/19 14:46
* @Description: ArrayList的底层操作机制
* 使用无参构造器创建 ArrayList 对象
*/
public class ArrayList_ {
public static void main(String[] args) {
ArrayList list = new ArrayList();
//使用 for 给 list 集合添加 1-10 数据
for (int i = 1; i <= 10; i++) {
list.add(i);
}
//使用 for 给 list 集合添加 11-15 数据
for (int i = 11; i <= 15; i++) {
list.add(i);
}
list.add(100);
list.add(200);
list.add(null);
}
}
(2)Debug过程分析
【1创建一个空的elementData数组】
其中设计到的几个参数分别为:
(1)size:ArrayList的大小,指包含元素的个数
(2)moCount:被修改的次数
(3)elementData:存储ArrayList元素的数组缓冲器区
(4)default_capacity:默认初始值为10【2.数据装箱】
【3.确保内部容量】
【4.计算容量】
【5.第一次扩容为10】
【6.第一次真正的扩容】
【7.扩容算法】
【8.存入数据】
【9.第2次扩容】
【10.第2次扩容开始】
【11.第2次真正的扩容】
【12.第3次扩容】
【13.第3次扩容存入数据】
六、Vector类
1. 介绍
(1)Vector类的定义说明
public class vectorextends AbstractList
implements List,RandomAccess,cloneable,Serializable
(2)Vector底层也是一个对象数组
protected object[] elementData;
(3)Vector是线程同步的,即线程安全
Vector类的操作方法带有synchronized。
例如:
public synchronized E get(int index){ if (index >= elementCount) throw new ArraylndexOutOfBoundsExceptio (index);return elementData(index);
}
(4)在开发中,需要线程同步安全时,考虑使用Vector
2. Vector的底层操作机制
(1)当创建Vector对象时,如果使用的是无参构造器,则初始elementData容量为10,若满了之后扩容,容量为原来的2倍。
(2)如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为2倍。
七、ArrayList类与Vector类的比较
八、LinkedList类(链表类)
1. 介绍
(1)LinkedList底层实现了双向链表和双端队列特点
(2)可以添加任意元素(元素可以重复),包括null
(3)线程不安全,没有实现同步
2. LinkedList类的底层操作机制
(1)LinkedList底层维护了一个双向链表.
(2)LinkedList中维护了两个属性first和last分别指向首节点和尾节点,
(3)每个节点(Node对象),里面又维护了prev、next、 item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表.
(4)所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。
3. LinkedList类的常用方法
LinkedList linkedList = new LinkedList();
(1)add 末尾添加一个节点元素
linkedList.add(100);
linkedList.add(200);
linkedList.add(300);
linkedList.add(400);
(2)remove() 默认删除的是第一个结点
linkedList.remove();
(3)remove(1) 删除索引为1的节点并返回item
【索引从0开始】
Object remove = linkedList.remove(1);
(4)remove(new Integer(300)) 删除数值为300的节点并返回确认
注意形参传入的为一个对象object
boolean b = linkedList.remove(new Integer(300));
(5)set(1, 999) 修改某个结点对象,将索引为1的对象的item修改为999
【索引从0开始】
linkedList.set(1, 999);
(6)get(1) 得到某个索引为1的结点对象
【索引从0开始】
Object o = linkedList.get(1);
System.out.println(o);
九、ArrayList类与LinkedList类的比较
如何选择ArrayList和LinkedList:
(1)如果我们改、查的操作多,选择ArrayList
(2)如果我们增、删的操作多,选择LinkedList
(3)一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList
(4)在一个项目中,根据业务灵活选择,也可能这样,一个模块使用的是ArrayList,另外一个模块是LinkedList,也就是说,要根据业务来进行选择。