集合
第一节:概念
- 概念
集合:就是一个存储数据的容器。
集合与数组一样,也是一个容器,与数组的区别:
1 数组长度固定,集合的长度不固定。
2 数组可以存储基本类型和引用类型,集合中存储的元素类型只能是引用类型。
-
集合框架的介绍(Collection)
-
Map集合的框架结构
-
集合和数组相比:
相同点:都是数据的容器,在一个数组或集合中可以存储多个数据
不同点:
-
元素:数组中的元素都只能是相同的类型,集合中的元素类型可以不同
数组中的可以存储基本类型和引用类型,集合只能存储引用类型
-
长度:数组的长度是固定的,一旦初始化长度后就不能改变。
集合的长度可以修改,可以删除元素和添加元素
-
第二节:Collection接口
Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些
collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
List派系:可以重复、有序
Set派系:不能重复、无序
常用方法:
方法名 | 描述 |
---|---|
boolean add(E e) | 确保此 collection 包含指定的元素(可选操作)。 |
boolean addAll(Collection<? extends E> c) | 将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。 |
void clear() | 移除此 collection 中的所有元素(可选操作)。 |
boolean contains(Object o) | 如果此 collection 包含指定的元素,则返回true。 |
boolean containsAll(Collection<?> c) | 如果此 collection 包含指定 collection 中的所有元素,则返回 true。 |
boolean equals(Object o) | 比较此 collection 与指定对象是否相等。 |
boolean isEmpty() | 如果此 collection 不包含元素,则返回true。 |
iterator() | 返回在此 collection 的元素上进行迭代的迭代器。 |
boolean remove(Object o) | 从此 collection 中移除指定元素的单个实例,如果存在的话(可选作)。 |
boolean removeAll(Collection<?> c) | 移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。 |
int size() | 返回此 collection 中的元素数。 |
Object[] toArray() | 返回包含此 collection 中所有元素的数组。 |
第三节:迭代器Iterator
迭代器相当于一个游标,最初获取迭代器时,迭代器的位置在所有元素的前面,每迭代一个元素,迭代器向后移动一 个位置
原理:
使用:
方法名 | 描述 |
---|---|
hasNext() | 判断迭代器是否存在下一个元素可以迭代器 |
next() | 迭代器迭代下一个元素 |
remove() | 从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。 |
第四节:List接口
方法名 | 描述 |
---|---|
add(int index, E element) | 在列表的指定位置插入指定元素(可选操作)。 |
addAll(int index, Collection<? extends E> c) | 将指定 collection 中的所有元素都插入到列表中的指定位置 |
containsAll(Collection<?> c) | 如果列表包含指定 collection 的所有元素,则返回true。 |
get(int index) | 返回列表中指定位置的元素。 |
indexOf(Object o) | 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。 |
lastIndexOf(Object o) | 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。 |
listIterator() | 返回此列表元素的列表迭代器(按适当顺序)。 |
remove(int index) | 移除列表中指定位置的元素(可选操作)。 |
set(int index, E element) | 用指定元素替换列表中指定位置的元素(可选操作)。 |
subList(int fromIndex, int toIndex) | 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。 |
list接口存储的特点:
1 相对有序存储,可以存储相同元素(不排重),可以通过下标访问集合元素
2 List接口中可以使用独有的迭代器ListIterator,具有反向遍历的功能
第五节:ArrayList实现类
ArrayList类是List接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括null在内的所有元素。
存储特点:
相对有序存储,可以存储相同元素(不排重),可以通过下标访问集合元素,通过数组实现的集合
存储结构:数组
代码实现:
public class ArrayListDemo {
public static void main(String[] args) {
//创建一个ArrayList集合
ArrayList<String> list = new ArrayList<>();//构造方法中的泛型可以省略
list.add("zhangsan");//向集合中添加元素
list.add("lisi");
list.add("wangwu");
System.out.println(list.isEmpty());//判断list集合是否为空集合
System.out.println(list.size());//查看集合中元素的个数
System.out.println(list.get(1));//获取集合中下标为1的元素
System.out.println(list.set(1,"zhaoliu"));//修改集合中下标为1的元素
System.out.println(list.contains("wangwu"));//查看"wangwu"是否是集合中的元素
list.remove("wangwu");//删除集合中"wangwu"元素
list.remove(1);//删除集合中下标为1的元素
//for循环遍历集合
for(int i=0; i<list.size(); i++){
System.out.println(list.get(i));
}
//使用Iterator迭代器遍历
Iterator<String> it = list.iterator();
//获取迭代器
while(it.hasNext()){
System.out.println(it.next());
}
//使用ListIterator迭代器遍历
ListIterator<String> lit = list.listIterator();
while(lit.hasNext()){
System.out.println(lit.next());
}
//反向遍历
while(lit.hasPrevious()){
System.out.println(lit.previous());
}
}
}
第六节:LinkedList类
LinkedList类是List接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括null)。
存储结构: 双向链表
存储特点: 相对有序存储,可以存储相同元素(不排重),可以通过下标访问集合元素,通过
链表实现的集合
使用:
public class Demo5 {
public static void main(String[] args) {
//创建集合
LinkedList<String> linkedList=new LinkedList<>();
//1添加元素
linkedList.add("苹果");
linkedList.add("葡萄");
linkedList.add("西瓜");
linkedList.add("芒果");
linkedList.add("桃子");
System.out.println("元素个数:"+linkedList.size());
System.out.println("打印:"+linkedList.toString());
//2删除
// linkedList.remove(0);
// System.out.println("删除之后:"+linkedList.toString());
//3遍历
//3.1for
//3.2foreach
//3.3迭代器
System.out.println("-----------迭代器-----------");
Iterator<String> it = linkedList.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
//3.4 列表迭代器
System.out.println("-----------列表迭代器-----------");
ListIterator<String> lit = linkedList.listIterator();
while(lit.hasNext()) {
System.out.println(lit.next());
}
//3.5降序迭代器
System.out.println("-----------降序迭代器-----------");
Iterator<String> dit = linkedList.descendingIterator();
while(dit.hasNext()) {
System.out.println(dit.next());
}
//4判断
System.out.println("isEmpty:"+linkedList.isEmpty());
System.out.println("苹果:"+linkedList.contains("苹果"));
//5查找位置
System.out.println("桃子的位置:"+linkedList.indexOf("桃子"));
}
}
ArrayList和LinkedList的总结
ArrayList存储结构是数组,LinkedList存储结构是双向链表。
ArrayList集合适用在对元素查询、遍历操作,不适合插入和删除。
LinkedList集合适用在对元素插入和删除操作,不适合遍历和查找。
第七节:Vector
Vector类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。但是Vector 的大小可以根据需要增大或缩小,以适应创建 Vector后进行添加或移除项的操作。
public static void main(String[] args) {
//创建集合
Vector<String> vector=new Vector<>();
//1添加元素
vector.add("xxx");
vector.add("yyy");
vector.add("zzz");
System.out.println(vector.toString());
//2删除
// vector.remove(0);
// System.out.println("删除之后:"+vector.toString());
//3遍历 //3.1for //3.2foreach //3.3迭代器 //3.4枚举器
Enumeration<String> elements = vector.elements();
while(elements.hasMoreElements()) {
System.out.println(elements.nextElement());
}
ArrayList与LinkedList、Vector三种实现类存储的比较
a.功能基本相同
b.底层存储结构:ArrayList是数组,LinkedList是链表,Vector是数组
c.Vector是一个古老的集合,从JDK1.0开始就有了,Vector存在一些方法名比较长的方法, xxxElement
d.Vector是线程安全的,效率低,ArrayList是线程不安全的,效率高,推荐使用 ArrayList【Collections工 具类中有相应的方法可以将ArrayList改为线程安全的】
e.ArrayList查找遍历比较快,LinkedList插入删除比较快
- ArrayList :主要实现类 。语法结构: ArrayList list = new ArrayList();
特点:① 数组结构实现,查询快,增删慢(增删一个元素,后面的元素都要移动位置)
② JDK1.2版本,运行效率快、效率不安全(对比另一个实现类Vector的add方法讲解) - Vector : 特点:①数据结构实现,查询快,增删慢(方法和ArrayList类似);
②JDK1.0版本,运行效率慢、线程安全(主要区别在于一个关键字synchronized,可举例说明线程安全和效率的关系) - LinkedList: 链表结构实现,增删快,查询慢。通过图示对比链表和顺序表的区别
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QTahkiiN-1588649158308)(图片\linkedlist.png)]
list的扩容
new ArrayList()
=> Object[] elementData = {};
初始长度为 0
当第一次 调用 add方法时, 把elementData数组长度初始为10
当elementData不足于存储数据时 ,会新建一个数组,长度为原来的1.5倍
原来的数组长度 int oldCapacity = elementData.length;
新的长度 int newCapacity = oldCapacity + (oldCapacity >> 1);
1.list的底层数据结构是 数组!(有序连续存储,有下标,可重复,长度固定)
2.看源码得知 Object[] 数组名 elementData, 长度为0 elementData ={};
3.当增加元素调用add 方法时。会初始 elementData 长度为 10。
4.当list集合中元素个数大于10时,会调用grow方法实现扩容。
5.在原有的数组长度+原来的数组长度的0.5倍 换句话说 扩容后的数组长度为原来 的1.5倍
源码:int newCapacity = oldCapacity + (oldCapacity >> 1);
6. 最后 通过 Arrays.copyof方法 复制原有数组中的元素到新数组中,长度是原来的1.5倍。
总结:list 的存储数据结构 可以说是动态数组!
第八节:泛型
- 概念: 参数化类型、类型安全的集合,强制集合元素的类型必须一致。
- 特点:
- 编译时即可检查,而非运行时抛出异常
- 访问时,不必类型转换(拆箱)
- 不同泛型之间引用不能相互赋值,泛型不存在多态。
高级应用:
实例泛型 、接口泛型和 静态泛型。
实例泛型 举例:
class MyClass<E>{//此时的E就是泛型的一个占位符,源码中常见的有 E T K V 等
//定义一个实例方法,把泛型作为参数传递
public void m1(E e){
}
}
实例泛型在创建对象时具体指明泛型的类型 比如:
MyClass<Integer> mc = new MyClass<Integer>();//此时的泛型就指定为整型
mc.m1(123);
//同样可以指定为其它类型
MyClass<Double> mc2 = new MyClass<Double>();
mc2.m1(12.3);
接口泛型 举例:
interface MyInterface<T>{
void m2(T t);//把泛型类型作参数传递给抽象方法
}
class MyImplClass implements MyInterface<Byte>{ //在写实现类的时候指明具体的泛型类型
@Override
public void m2(Byte t){
}
}
静态泛型 举例:
class MyStaticClass{
public static<E> void method(E e){
System.out.println(e.getClass());//会打印具体传递过来形参的值
}
}
//在实际调用静态方法时,把具体类型传递
MyStaticClass.method(123); //class java.lang.Integer
MyStaticClass.method(12.3);//class java.lang.Double
//此时什么类型都可以接收,但在方法内部会有区别
另,可对静态泛型进行约束
class MyStaticClass{
public static<E extends Animal & Comparable> void method(E e){
// 此时能传进来的类型必须满足两个条件即:继承Animal类,并且实现了Comparable接口(可排序),否则编译错误
}
}
1)<? extends T>:表示T类或者T类的子类 2)<? super T>:表示T类或者T类的父类 3)<?>:表示任意类型