文章目录
1:集合体系图
Collection:单列集合,该接口有两个重要的子接口List Set,他们的实现子类都是单列集合
Map:双列集合,Map接口的实现子类,存放K-V
2:Collection方法
2.1 Collection接口和常用方法
- Collection接口实现类的特点
public interface Collection< E > extends Iterable < E >
1 ) collection实现子类可以存放多个元素, 每个元素可以是Object
2)有些Collection的实现类,可以存放重复的元素,有些不可以
3)有些Collection的实现类,有些是有序的(List), 有些不是有序(Set)
4) Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的
- Collection接口常用方法,以实现子类ArrayList来演示。CollectionMethod.java
1) add:添加单个元素
2) remove:删除指定元素
3) contains:查找元素是否存在
4) size:获取元素个数
5) isEmpty:判断是否为空
6) clear:清空
7) addAll:添加多个元素
8) containsAll:查找多个元素是否都存在9) removeAll:删除多个元素
public class CollectionMethod {
public static void main(String[] args) {
List list=new ArrayList();
// 1) add:添加单个元素
list.add("zlj");
list.add(10);
list.add(true);
// 2) remove:删除指定元素
list.remove(1);
System.out.println("list:"+list);
// 3) contains:查找元素是否存在
System.out.println(list.contains(true));
// 4) size:获取元素个数
System.out.println(list.size());
// 5) isEmpty:判断是否为空
System.out.println(list.isEmpty());
// 6) clear:清空
list.clear();
System.out.println("list:"+list);
// 7) addAll:添加多个元素
ArrayList list2=new ArrayList();
list2.add("西游记");
list2.add("水浒传");
list.addAll(list2);
// 8) containsAll:查找多个元素是否都存在
list.containsAll(list2);
// 9) removeAll:删除多个元素
list.add("java虚拟机");
list.removeAll(list2);
System.out.println("list:"+list);
}
}
2.2 Collection接口遍历元素的方式
2.2.1 使用Iterator(迭代器)基本介绍
-
Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。2)所有实现了Collection接口的集合类都有一个iterator(0方法, 用以返回一个实现了Iterator接口的对象, 即可以返回一个迭代器。
-
Iterator的结构
注意:在调用iterator.next()方法之前必须要调用iterator.hasNext()进行检测。若不调用,且下一条记录无效,直接调用iterator.next()会抛出NoSuchElementException异常。如果希望再次遍历,需要我们重置一个迭代器 -
Iterator仅用于遍历集合, Iterator本身并不存放对象。
实例演示
public class CollectionIterator {
public static void main(String[] args) {
List list=new ArrayList();
list.add(new Book("java虚拟机","300"));
list.add(new Book("java规范","100"));
list.add(new Book("Spring","200"));
//1:先得到list对于的迭代器
Iterator iterator = list.iterator();
//2:使用while循环遍历,判断是否还有数据
while (iterator.hasNext()){
//3:返回下一个元素
System.out.println(iterator.next());
}
}
}
class Book{
private String name;
private String price;
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price='" + price + '\'' +
'}';
}
public Book(String name, String price) {
this.name = name;
this.price = price;
}
}
2.2.2 for循环增强
增强for循环(底层仍然是iterator迭代器),可以代替iterator迭代器,特点:增强for就是简化版的iterator,本质一样。只能用于遍历集合或数组。for循环增强也可以在数组中使用
基本语法
for(元素类型元素名:集合名或数组名){
访问元素
}
实例演示:如上代码的iterator改成for循环增强即可
//..
for (Object book:list){
System.out.println("book="+book);
}
//...
book=Book{name='java虚拟机', price='300'}
book=Book{name='java规范', price='100'}
book=Book{name='Spring', price='200'}
3:List接口和方法
3.1 List接口基本介绍
常用的有ArrayList,LinkedList,Vector
List接口是Collection接口的子接口
-
List集合类中元素有序(即添加顺序和取出顺序一致)、 且可重复,
-
List集合中的每个元素都有其对应的顺序索引,即支持索引。
-
List容器中的元素都对应一 个整数型的序号记载其在容器中的位置, 可以根据序号存取容器中的元素。
案例演示
public class ListMethod {
public static void main(String[] args) {
// List集合类中元素有序(即添加顺序和取出顺序一致)、 且可重复,
List list=new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(3);
System.out.println("list="+list);
//List集合中的每个元素都有其对应的顺序索引,即支持索引。
System.out.println(list.get(3));
}
}
list=[1, 2, 3, 3]
3
3.2 List接口的常用方法
List集合里添加了一些根据索引来操作集合元素的方法
-
void add(int index, Object ele):在index位置插入ele元素
-
boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
-
Object get(int index):获取指定index位置的元素
-
int indexOf(Object obj):返回obj在集合中首次出现的位置
-
int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
-
Object remove(int index):移除指定index位置的元素,并返回此元素
-
Object set(int index, Object ele):设置指定index位置的元素为ele ,相当于是替换.
-
List subList(int fromIndex, int tolndex):返回从fromIndex到tolndex位置的子集合
案例演示
public class ListMethod {
public static void main(String[] args) {
// List集合类中元素有序(即添加顺序和取出顺序一致)、 且可重复,
List list=new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(3);
System.out.println("list="+list);
//List集合中的每个元素都有其对应的顺序索引,即支持索引。
System.out.println(list.get(3));
// 1) void add(int index, Object ele):在index位置插入ele元素
list.add(1,"java");
System.out.println("list="+list);
// 2) boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
List list2= new ArrayList();
list2.add("男");
list2.add("女");
list.addAll(1,list2);
System.out.println("list="+list);
// 3) Object get(int index):获取指定index位置的元素
System.out.println( list.get(1));
//
// 4) int indexOf(Object obj):返回obj在集合中首次出现的位置
System.out.println(list.indexOf(3));
// 5) int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
System.out.println(list.lastIndexOf(3));
// 6) Object remove(int index):移除指定index位置的元素,并返回此元素
list.remove(0);
System.out.println("list="+list);
// 7) Object set(int index, Object ele):设置指定index位置的元素为ele ,相当于是替换.
list.set(0,"man");
System.out.println("list="+list);
// 8) List subList(int fromIndex, int tolndex):返回从fromIndex到tolndex位置的子集合
System.out.println(list.subList(0,3));
}
}
3.3 List接口的三种遍历方式
- 迭代器
- 增强for循环
- 使用普通for循环
案例演示
public class ListFor {
public static void main(String[] args) {
List list=new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(3);
//1.迭代器
System.out.println("======迭代器=======");
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
}
System.out.println("======增强for循环=======");
for (Object object:list){
System.out.println(object);
}
System.out.println("======普通for循环=======");
for (int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
}
4:ArrayList源码剖析
ArrayList的注意事项
-
ArrayList可以加入null,并且加多个
-
ArrayList是由数组来实现数据存储的
-
ArrayList基本等同于Vector ,除了ArrayList是线程不安全(执行效率高)看源码,在多线程情况下,不建议使用ArrayList
ArrayList的底层操作机制源码分析(重点,难点)
先说结论在分析源码
1 ) ArrayList中维护了一个Object类型的数组elementData
transient Object[] elementData//transient 表示短暂的,瞬间,表示该属性不会被序列化
2)当创建对象时,如果使用的是无参构造器,则初始elementData容量为0 (jdk7是10)
3)当添加元素时:先判断是否需要扩容,如果需要扩容,则调用grow方法,否则直接添加元素到合适位置
4)如果使用的是无参构造器,如果第一次添加,需要扩容的话,则扩容elementData为10,如果需要再次扩容的话,则扩容elementData为1.5倍。
5)如果使用的是指定容量capacity的构造器,则初始elementData容量为capacity
6)如果使用的是指定容量capacity的构造器,如果需要扩容,则直接扩容elementData为1.5倍。
当创建对象时,如果使用的是无参构造器案例演示
public class ArrayListSource {
public static void main(String[] args) {
//解读源码
//使用无参构造器创建ArrayList对象
ArrayList arrayList=new ArrayList();
//使用for循环给list添加1-10数据
for (int i=0;i<=10;i++){
arrayList.add(i);
}
//使用for循环给list添加11-15数据
for (int i=11;i<=15;i++){
arrayList.add(i);
}
//使用for循环给list添加16,17,18数据
arrayList.add(100);
arrayList.add(200);
arrayList.add(null);
}
}
源码剖析
Debug
当创建对象时,如果使用的是有参构造器案例演示
源码剖析
Debug
5:Vector源码剖析
Vector注意事项
1)Vector类的定义说明
2) Vector底层也是一个对象数组
protected Object[] elementData;
3 ) Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
4)在开发中需要线程同步安全时,需要考虑使用Vector
案例演示
public class VectorSource {
public static void main(String[] args) {
//无参构造器
Vector<Object> objects = new Vector<>();
for (int i=0;i<10;i++){
objects.add(i);
}
}
}
源码剖析
Debug
6:LinkedList源码剖析
6.1 LinkedList的全面说明和底层操作机制
全面说明
1 ) LinkedList底层实现了双向链表和双端队列特点
2 )可以添加任意元素(元素可以重复),包括null
3 )线程不安全,没有实现同步
LinkedList的底层操作机制
1 ) LinkedList底层维护了一个双向链表.
2 ) LinkedList中维护了两个属性first和last分别指向首节点和尾节点
3)每个节点(Node对象) ,里面又维护了prev、next、 item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表.
4)所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。
模拟双向链表遍历
public class LinkedListDemo {
public static void main(String[] args) {
//模拟一个简单的双向链表
Node zlj = new Node("zlj");
Node zzg = new Node("zzg");
Node lqx = new Node("lqx");
//连接三个节点,形成双向链表
//zlj->zzg->lqx
zlj.next=zzg;
zzg.next=lqx;
//lqx->zzg->zlj
lqx.pre=zzg;
zzg.pre=zlj;
Node first=zlj;//first引用指向zlj,就是双向链表的头节点
Node last=lqx;//last引用指向lqx,就是双向链表的尾节点
//从头到尾进行遍历
System.out.println("============从头到尾进行遍历============");
while (true){
if (first==null) {
break;
}
System.out.println(first);
first=first.next;
}
//从尾到头进行遍历
System.out.println("============从尾到头进行遍历==============");
while (true){
if (last==null){
break;
}
System.out.println(last);
last=last.pre;
}
}
}
//定义一个Node类,Node对象,表示双向链表的一个节点
class Node{
public Object item;//真正存放数据
public Node next;//指向后一个节点
public Node pre;//指向前一个结点
public Node(Object name){
this.item=name;
}
@Override
public String toString() {
return "Node{" +
"item=" + item +
'}';
}
}
============从头到尾进行遍历============
Node{item=zlj}
Node{item=zzg}
Node{item=lqx}
============从尾到头进行遍历==============
Node{item=lqx}
Node{item=zzg}
Node{item=zlj}
模拟双向链表的添加和删除(主要代码和上面一样)
//....
//演示链表添加对象
Node node = new Node("添加元素");
zlj.next=node;
node.next=zzg;
zzg.pre=node;
node.pre=zlj;
//..
============从头到尾进行遍历============
Node{item=zlj}
Node{item=添加元素}
Node{item=zzg}
Node{item=lqx}
/...
//演示链表添加对象
Node node = new Node("添加元素");
zlj.next=node;
node.next=zzg;
zzg.pre=node;
node.pre=zlj;
//演示链表删除对象
zlj.next=zzg;
zzg.pre=zlj;
//..
============从头到尾进行遍历============
Node{item=zlj}
Node{item=zzg}
Node{item=lqx}
6.2 LinkedList源码剖析
linkedList 的add方法源码剖析
public class LinkedListCRUDSource {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add(1);
linkedList.add(2);
System.out.println("linkedList="+linkedList);
}
}
7:List实现类的选择
如何选择ArrayList和LinkedList:
1)如果我们改查的操作多,选择ArrayList
2)如果我们增删的操作多,选择LinkedList
3)一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList
4)在一个项目中,根据业务灵活选择,也可能这样,一个模块使用的是ArrayList,另外一个模块是LinkedList.