集合介绍
数组 vs 集合
- 数组的弊端
(1)【长度固定】长度开始时必须指定,指定后无法更改
(2)【元素类型统一】保存的元素必须为统一类型
(3)【增删麻烦】使用数组进行增加/删除元素操作比较麻烦 - 集合好处
(1)【长度可变】可以动态保存任意多个对象,使用比较方便!
(2)【元素类型可变】保存的元素类型没有限制,可以不统一
(3)【增删简单】使用集合添加,删除新元素的代码简洁了
~~~~~~~~~~~~~~~~~~~ 提供了一系列方便的操作对象的方法:add、remove、set、get等
集合框架图
- 集合主要是两组(单列集合 , 双列集合)
- Collection 接口有两个重要的子接口 List Set , 他们的实现子类都是单列集合
- Map 接口的实现子类 是双列集合,存放的 K-V
- 集合的创建
public class Demo {
public static void main(String[] args) {
//1.List的创建和添加
ArrayList arrayList = new ArrayList();
arrayList.add("hello");
arrayList.add("hello");
//2.Map的创建和添加
HashMap hashMap = new HashMap();
hashMap.put("No.1","jack");
hashMap.put("No.2","mrray");
}
}
Collection接口实现类的常用方法
-
Collertion接口实现类的特点
(1)collection:实现子类可以存放多个元素,每个元素可以是Object
(2)有些Collection的实现类,可以存放重复的元素,有些不可以
(3)有些Collection的实现类,有些是有序的(List),有些不是有序(Set)
(4)Collection接口没有直接的实现子类,是通过它的子接口Set和List来
实现的 -
Collection接口实现类的常用方法总结(ArrayList举例)
(1)添加单个元素:引用变量名.add(实例对象)
(2)删除单个元素:引用变量名.remove(实例对象)
(3)查找单个元素:引用变量名.contians(实例对象)【返回boolean值】
(4)获取元素个数:引用变量名.size()【返回数值】
(5)判断是否为空:引用变量名.isEmpty()【返回boolean值】
(6)清空所有元素:引用变量名.clear()
(7)添加多个元素:引用变量名.addAll(实现集合类的实例对象)
(8)删除多个元素:引用变量名.removeAll(实现集合类实例对象)
(9)查找多个元素:引用变量名.contiansAll(实现集合类实例对象)【返回boolean值】
public class Demo {
public static void main(String[] args) {
//1.List的创建和添加
List list = new ArrayList();
List list2 =list;
//add:()添加单个元素
list.add("hello");
//因为collection实现的子类存放的Object对象,
//所以在存放基本数据类型时,都有一个自动装箱的过程
list.add(10);
list.add(true);
//remove:删除指定元素
list.remove(0);
//cotains:查找元素是否存在 返回的boolean值
System.out.println(list.contains("hello"));
//size:获取元素个数
System.out.println(list.size());
//isEmpty:判断是否为空
System.out.println(list.isEmpty());
//clear:清空
list.clear();
//addAll:添加多个数据,可以放集合
list.add(list);
//containsAll:查找是否有个多个数据存在
System.out.println(list.contains(list));
//removeAll:删除多个元素
System.out.println(list.removeAll(list));
}
}
Collection 接口遍历元素方式
Iterator(迭代器)
- 迭代器的基本介绍
(1)Iterator对象称为送代器,主要用于遍历Collection集合中的元素。
所有实现了Collection接口的集合类都有一个iterator()方法,用以返回
一个实现了Iterator接口的对像,即可以返回一个迭代器。
(2)Iterator仅用于遍历集合,Iterator本身并不存放对象。 - 迭代器的执行原理
(1)需要一个实现Collection接口的类的实例对象
ArrayList arrayList = new ArrayList();
(2)生成一个迭代器【借助使用实现Collection类的ArrayList的实例对象的itrator方法】
Iterator iterator = arrayList.iterator();
(3)用while循环遍历iterator【此处快捷键:itit】
hasNext():用户判断下一处是否有对象,该方法返回的boolean值
next():将指针下移,并返回下移后区域的值
while (iterator.hasNext()) {
~~~~~~~~ Object next = iterator.next();
~~~~~~~~ System.out.println(next);
}
(4)重点提示
在调用iterator.next()方法之前必须要调用literator.hasNext0,进行检测。
若不调用,且下一条记录无效,直接调用iterator.next()会抛出NoSuchElementException异常。
增强for循环
- 增强for循环基本介绍
增强for循环可以代替iteratori迭代器,
特点:增强for就是简化版的iterator遍历。本质一样,只能用于遍历集合或数组 - 基本语法【快捷键 I(大写i )】
for(访问元素的类型 访问元素的引用变量名【自定义】:数组/集合的引用变量名){
~~~~~~ System.out.print(访问元素的引用变量名)
}
List接口
List 接口基本介绍
- List集合类中元素有序(即添加顺序和取出顺序一致)且可重复
- List集合中的每个元素都有其对应的顺序索引,即支持索引。
(1)索引从0开始
(2)使用格式: List接口实现类的引用变量名.get(索引数)
(3)LIst接口的实现类很多,常用的有ArrayList、LinkedList、Vector - List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
List接口的常用方法
(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 位置的元素,并返回此元素
~~~~~~~~~
注意:由于List接口继承Collection接口类,还可以移除指定对象
(7)Object set(int index, Object ele):设置指定 index 位置的元素为 ele , 相当于是替换.
(8)List subList(int fromIndex, int toIndex):返回从 fromIndex 到 toIndex 位置的子集合【左闭右开】
List接口遍历元素方式
Iterator(迭代器)
~~~~~ 见上
增强for循环
~~~~~ 见上
普通for循环
- 使用格式:
for (int i = 0; i < 实现List接口的实例对象名.size(); i++) {
Object o = 实现List接口的实例对象名.get(i);
System.out.print(o+"\t");
}
ArrayList
- 注意事项
(1)permits all elements,including null,ArrayList可以加入null,并且多个
(2)ArrayList是由数组来实现数据存储的
(3)ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高)看源码在多线程情况下,不建议使用ArrayList - 底层机制
(1)ArrayListr中维护了一个Object类型的数组elementData.
transient Object[]elementData; == transient==:表示瞬间,短暂的,表示该属性不会被序列化
(2)当创建ArrayListi对象时,如果使用的是无参构造器,则初始elementData容量为0,
第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍。
(3)如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容
则直接扩容elementData为1.5倍。 - 源码说明
Vector
- Vector和ArrayList的对比
Column 1 | 底层结构 | 版本 | 线程安全(同步)效率 | 扩容倍速 |
---|---|---|---|---|
ArrayList | 可变数组 | jdk1.2 | 不安全 高效率 | 如果有参构造1.5倍, 如果无参第一次按10 第二次按无参开始按1.5倍 |
Vector | 可变数组 | jdk1.0 | 安全 效率不高 | 如果无参,默认10 如果指定大小,则每次按2倍扩 |
LinkedList
- 基本介绍
(1)LinkedList底层实现了双向链表和双端队列特点
双向链表的简单模拟
双端队列
(2)可以添加任意元素(元素可以重复),包括ul
(3)线程不安全,没有实现同步\
-
LinkedList常用方法
(1)Object remove():默认移除第一个元素的元素
(2)三种遍历见上 -
ArrayLis和LinkedList的对比
name | 底层结构 | 增删效率 | 改查效率 |
---|---|---|---|
ArrayList | 可变数组 | 低,数组扩容 | 高 |
LinkedList | 双向链表 | 高,动态扩容 | 低 |
~~~
如何选择
(1)如果我们改查的操作多,选择ArrayList
(2)如果我们增删的操作多,选择LinkedList
(3)般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList
(4)在一个项目中,根据业务灵活选择,也可能这样,一个模块使用的是ArrayList,另
~~~~
外一个模块是LinkedList,也就是说,要根据业务来进行选择
(5)由于ArrayList和LinkedList线程不安全,只有在线程没有并发的时候才选择这两个
Set接口
- Set接口实现类的基本介绍
(1)无序(添加和取出的顺序不一致),没有索引
~~~~ 注意:取出的顺序的顺序虽然不保证是添加的顺序,但是他的固定.
(2)不允许存放重复元素,所以最多包含一个ul川
(3)JDK APIE中Set接口的实现类有:HashSet 、 TreeSet 等 - 常用方法
见上面Collection类实现类的常用方法 - Set接口实现类的遍历方法
可以实现迭代器,增强for循环
由于没有索引,则不能用get()方法,则不能用普通for循环
HashSet
- 基本介绍
(1)构造器走的源码
public HashSet() {
map = new HashMap<>();
}
(2) HashSet 可以存放 null ,但是只能有一个 null,即元素不能重复
(3)HashSet.不保证元素是有序的,拟决于hash后,再确定索引的结果.(即,
保证存放元素的顺序和取出顺序一致)
(4)不能有重复元素对象.在前面Set接口使用已经讲过
Collections工具类
基本介绍
常用方法
(1)Collectirons.reverse( 引用变量名 ) 反转
(2)Collections.shuffe( 引用变量名 ) 对集合进行随机排序
(3)Collections.sort( 引用变量名 ) 自然排序(按圣墟排序)
(3)Collections.sort( 引用变量名 , new Compare( ){
~~~~~~~
@Override
~~~~~~~
public int compare(Object o1, Object o2) {
~~~~~~~~~~~~~~~~~
return ((String) o1).length() - ((String) o2).length();
~~~~~~~~
}
~~
} )
(自定义)按字符串长度顺序排序
import java.util.*;
public class Demo {
public static void main(String[] args) {
//创建一个集合,并添加为测试作准备
ArrayList list = new ArrayList();
list.add("abc");
list.add("a");
list.add("ab");
list.add("abcd");
list.add("abcde");
//(1)自然排序
Collections.sort(list);
System.out.println("(1)自然排序" + list);
//自然排序[a, ab, abc, abcd, abcde]
//(2)自定义长度升序排序【内部类】
Collections.sort(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String) o1).length() - ((String) o2).length();
}
});
System.out.println("(2)自定义长度升序排序【内部类】" + list);
//自定义长度升序排序[a, ab, abc, abcd, abcde]
//(3)自定义长度降序排序【箭头函数】
Collections.sort(list, (Object o1, Object o2) -> {
return ((String) o2).length() - ((String) o1).length();
});
System.out.println("(3)自定义长度降序排序【箭头函数】" + list);
//自定义长度降序排序[abcde, abcd, abc, ab, a]
}
}
(4)Collections.swap( 引用变量名 , 下标1, 下标2 ) 将指定集合实现类实例的两个指的下标的元素交换
(5)Collections. max(引用变量名) 取出自然排序的最大元素,返回元素的类型是Object(min的使用方法类似)
(6)Collections.max( 引用变量名 , new Compare( ){
~~~~~~~
@Override
~~~~~~~
public int compare(Object o1, Object o2) {
~~~~~~~~~~~~~~~~~
return ((String) o1).length() - ((String) o2).length();
~~~~~~~~
}
~~
} )
取出自定义元素长度最大的元素,返回类型是Object
(7)Collections.copy(引用变量名2 , 引用变量名1) 将引用变量名1中的元素,复制进引用变量名2中
注意要保证两者的size相同,可在复制前,将引用变量名2循环添加空内容,保障两者size一样