学习目录
- 一、集合基本介绍
- 1.基本介绍
- 2.集合的框架体系图☆
- 二、Collection 接口
- 1.Collection接口常用方法
- 2.Iterator(迭代器)
- 3.增强for循环
- 三、List 接口
- 1.List集合类常用方法
- 2.List集合类的循环
- 四、ArrayList底层源码扩容机制
- 五、Vector和LinkedList
- 1.Vector
- 2.LinkedList
一、集合基本介绍
1.基本介绍
为什么引入集合
- 由于数组的长度开始时必须指定,而且一旦指定就不能更改
- 保存的元素必须是同一类型的元素
- 而且使用数组添加、删除元素比较麻烦
集合的特点
- 可以动态保存任意多个对象,使用比较方便
- 提供了一系列方便的操作对象的方法 如:add,get,set
- 使用集合添加、删除新元素代码简洁了很多
2.集合的框架体系图☆
java中的集合类很多,注意分为两大类,如图所示
Collection接口
Map接口
二、Collection 接口
Collection接口实现类的特点
- Collection实现子类可以存放多个元素,每个元素可以是Object
- 有些Collection的实现类,可以存放重复的元素,有些不可以
- 有些Collection的实现类,有些事有序的(List),有些不是有序(Set)
- Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的
1.Collection接口常用方法
import java.util.ArrayList;
class test1{
@SuppressWarnings({"all"}) //去除警告
public static void main(String[] args){
//ArrayList是一个实现Collection接口的子类
ArrayList list = new ArrayList();
//添加元素
list.add("jack");
list.add(10);
list.add(true);
System.out.println("list="+list); //list=[jack, 10, true]
//删除元素
list.remove(0); //删除第一个元素
list.remove(true); //删除指定元素
//判断元素是否存在
System.out.println(list.contains(10)); //true
//获取集合元素个数
System.out.println(list.size()); //1
//判断集合是否为空
System.out.println(list.isEmpty()); //false
//清空集合
list.clear();
System.out.println(list); //[]
//addAll(Collection c)添加多个元素
ArrayList list1 = new ArrayList();
list1.add(1);
list1.add(2);
list.addAll(list1);
System.out.println(list); //[1,2]
//查找多个元素是否存在
list.add("test"); //再添加一个元素
System.out.println(list.containsAll(list1)); //true
//删除多个元素
list.removeAll(list1);
System.out.println(list); //[test]
}
}
2.Iterator(迭代器)
基本介绍
- Iterator对象称为迭代器,注意用于遍历Collection集合中的元素
- 所有实现了Collection接口的集合都有一个Iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器
- Iterator仅用于遍历集合
常用方法
注意:在调用iterator.next()方法之前必须要调用iterator.hasNext()进行检测。若不调用,且下一条记录无效,直接调用iterator.next()会抛出异常
import java.util.ArrayList;
import java.util.Iterator;
class test1{
@SuppressWarnings({"all"})
public static void main(String[] args){
ArrayList list = new ArrayList();
list.add(new Person("张三",18));
list.add(new Person("李四",19));
list.add(new Person("王五",20));
System.out.println("第一次遍历");
Iterator iterator = list.iterator();
while (iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
}
System.out.println("第二次遍历");
//注意:如果想第二次遍历,需要重置的迭代器
iterator = list.iterator();
while (iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
}
}
}
class Person{
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//这个get和set省略了
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.增强for循环
增强for循环,可以代替Iterator迭代器,特点:增强for就是简化版的Iterator本质一样,只能用于遍历集合或数组
基本语法:
for(元素类型 元素名:集合名或数组名){
访问元素
}
import java.util.ArrayList;
class test1{
@SuppressWarnings({"all"})
public static void main(String[] args){
ArrayList list = new ArrayList();
list.add(new Person("张三",18));
list.add(new Person("李四",19));
list.add(new Person("王五",20));
for (Object i: list) {
System.out.println(i);
}
}
}
class Person{
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//这个get和set省略了
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
三、List 接口
基本介绍
- List集合类中元素有序(添加顺序和取出顺序一致)、且可重复
- List集合类中的每个元素都有其对应的顺序索引,即支持索引
- List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素
- 常用的实现类有ArrayList、LinkedList和Vector
1.List集合类常用方法
这里以ArrayList()类为例,LinkedList()和Vector()类似
更多方法可查看API
import java.util.ArrayList;
import java.util.List;
class test1{
@SuppressWarnings({"all"})
public static void main(String[] args){
ArrayList list = new ArrayList();
//add添加元素
list.add("张三");
list.add("张三");
list.add("李四");
//add(int index, Object element):在指定index位置添加元素
list.add(1,"小明"); //索引从0开始的
System.out.println(list); //[张三, 小明, 张三, 李四]
//add(int index, Collection c):在指定index位置将所有元素添加进来
ArrayList list1 = new ArrayList();
list1.add(1);
list1.add(2);
list.addAll(1,list1);
System.out.println(list); //[张三, 1, 2, 小明, 张三, 李四]
//get(int index):获取指定index位置的元素
System.out.println(list.get(0)); //张三
//indexOf(Object obj):返回 obj 在集合中首次出现的位置
System.out.println(list.indexOf("张三")); //0
//lastIndexOf(Object obj):返回 obj 在当前集合中末次出现的位置
System.out.println(list.lastIndexOf("张三")); //4
//remove(int index):移除指定 index 位置的元素,并返回此元素
list.remove(1);
System.out.println(list); //[张三, 2, 小明, 张三, 李四]
//set(int index, Object ele):设置指定 index 位置的元素为 ele , 相当于是替换
list.set(1,"tom");
System.out.println(list); //[张三, tom, 小明, 张三, 李四]
//subList(int fromIndex, int toIndex):返回从 fromIndex 到 toIndex 位置的子集合
List list2 = list.subList(1, 3);
System.out.println(list2); //[tom, 小明]
}
}
2.List集合类的循环
- 方式一:Iterator迭代器
- 方式二:增强for循环
- 方式三:使用普通for循环
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
class test1{
@SuppressWarnings({"all"})
public static void main(String[] args){
//这三个类都是List接口的实现类
// List list = new ArrayList();
List linkedList = new LinkedList();
// List vector = new Vector();
linkedList.add(new Person("张三",21));
linkedList.add(new Person("李四",19));
linkedList.add(new Person("王五",20));
//普通for遍历
for (int i = 0; i < linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
System.out.println("-------------------");
sort(linkedList);
//增强for循环
for (Object o: linkedList) {
System.out.println(o);
}
System.out.println("-------------------");
//迭代器遍历
Iterator iterator = linkedList.iterator();
while (iterator.hasNext()){
Object next = iterator.next();
System.out.println(next);
}
}
//年龄从小到大排序,冒泡排序
public static void sort(List list){
int listSize = list.size();
for (int i = 0; i < listSize; i++) {
for (int j = 0; j < listSize-1; j++) {
Person o = (Person)list.get(j);
Person o1 = (Person)list.get(j + 1);
if (o.getAge()>o1.getAge()){
list.set(j,o1);
list.set(j+1,o);
}
}
}
}
}
class Person{
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "姓名:"+name+"\t"+"年龄:"+age;
}
}
四、ArrayList底层源码扩容机制
结论:
- ArrayList中维护了一个Object类型的数组elementData
- 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData的容量为0,第一次add添加,则扩容elementData为10,如果再需要扩容elementData的容量则为目前elementData容量的1.5倍
- 当创建ArrayList对象时,如果使用的是指定导向的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData的容量是目前elementData容量的1.5倍
import java.util.ArrayList;
class test1{
@SuppressWarnings({"all"})
public static void main(String[] args){
ArrayList list = new ArrayList();
for (int i = 0; i < 10; i++) {
list.add(i);
}
}
}
下面是以上代码的Debug大致流程:
(1)执行ArrayList list = new ArrayList();创建了一个elementData数组={ }
(2)执行list.add,首先把添加的值返回一个Integer类型的,完成装箱操作
(3)按照顺序依次执行
①调用ensureCapacityInternal(int minCapacity)方法,该方法首先调用calculateCapacity(elementData, minCapacity)
②判断elementData是否为空数组如果是空数组,就给一个最小容量DEFAULT_CAPACITY值为10
③然后再调用ensureExplicitCapacity方法再次确定一下是否扩容,然后判断一下最小的容量减去当前集合长度是否>0,如果>0,调用grow(minCapacity)方法进行扩容(也就是说我需要10个容量,当前集合的长度却是0)
(4)进入grow方法后,把集合的长度给oldCapacity,而newCapacity = oldCapacity+ oldCapacity/2(>> 1 表示位运算 向右移动一位),也就是1.5以前的1.5倍,如果newCapacity - minCapacity <0 ;则就把minCapacity 赋值newCapacity=10;
最后执行elementData = Arrays.copyOf(elementData, newCapacity);这条语句把newCapacity复制给elementData
(5)扩容完之后回到add方法中进行增加操作
五、Vector和LinkedList
1.Vector
基本介绍
- Vector底层也是一个对象数组,protected Object[] elementData;
- Vector是线程同步的,即线程安全
- Vector在开发中,如果需要线程同步安全时,则可以考虑使用Vector
Vector的常用方法跟ArrayList类似,具体查看JDK1.8
ArrayList 和 Vector 的比较
底层结构 | 版本 | 线程安全(同步)效率 | 扩容倍数 | |
ArrayList | 可变数组 | jdk1.2 | 不安全,效率高 | 如果无参 第一次容量为10,第二次开始按1.5扩容;如果有参按1.5扩容 |
Vector | 可变数组 | jdk1.0 | 安全,效率不高 | 如果无参 默认为10,满后,按2倍扩容;如果指定大小,则每次直接按2倍扩容 |
2.LinkedList
基本介绍
- LinkedList底层实现了双向链表和双端队列特点
- 可以添加任意元素(元素可以重复),包括null
- 线程不安全,不能实现同步
LinkedList的增删改查
import java.util.LinkedList;
class test1{
@SuppressWarnings({"all"})
public static void main(String[] args){
//增
LinkedList list = new LinkedList();
list.add(1);
list.add(2);
System.out.println(list); //[1, 2]
LinkedList list1 = new LinkedList();
list1.add("java");
list1.add("python");
list.addAll(list1);
System.out.println(list); //[1, 2, java, python]
//删
// list.remove(); //默认删除第一次元素
list.remove(2);
System.out.println(list); //[1, 2, java, python]
//改
list.set(1,"scala");
System.out.println(list); //[1, scala, python]
//获取
System.out.println(list.get(1)); //scala
}
}
ArrayList 和 LinkedList 的比较
底层结构 | 增删效率 | 改查的效率 | |
ArrayList | 可变数组 | 效率低,数组扩容 | 较高 |
LinkedList | 双向链表 | 较高,通过链表追加 | 较低 |