集合 (集合框架)Collection
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d4b3a85662b2fe27b0aa8feca0e4fd22.png)
Collection 是一个接口(interface),他是一个用来存放对象的数据结构,其中长度可变,而且集合中可以存放不同类型的对象,并提供了一系列操作此对象的方法。
分成对外的接口,接口的实现,以及集合框架的算法。
集合和数组一样,都是用来存储数据的(多个数据);
1. 集合与数组存储数据概述:
集合、数组都是对多个数据进行存储操作的结构,简称Java容器。
说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,.avi,数据库中)
2. 数组存储的特点:
一旦初始化以后,其长度就确定了。
数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。
-
比如:String[] arr;int[] arr1;Object[] arr2;
3. 数组存储的弊端:
-
> 一旦初始化以后,其长度就不可修改。
-
> 数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。
-
> 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
-
> 数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。
-
>数组按照下标遍历,适合查询
4. 集合存储的优点:
-
解决数组存储数据方面的弊端。
-
可变长度,遍历方式丰富
-
适合增删查询。
集合的继承结构
把共性的东西向上抽取,最终形成容器的继承体系结构。(Abstract)
一、Collection 的子接口
1.1 List接口:存储数据有序,可以重复
1.1.1 List接口的实现类:
ArrayList类 (常用):
LinkedList类:
vector类:
1.1.2常用方法
-
boolean add(E e)添加元素
-
boolean addAll(Collection<? extends E> c)把小集合添加到大集合中
-
boolean contains(Object o)如果此collection 包含指定的元素,则返回true。
-
boolean isEmpty() 如果此collection 不包含元素,则返回true
-
boolean remove(Object o) 从此collection 中移除指定元素的单个实例,如果存在的话 。
-
int size() 返回此collection 中元素数(集合的长度)
-
Object[] toArray() 返回包含此collection 中所有元素的数组,(集合转成数组)
-
removeAll(Collection col):差集,从当前集合中移除col中的所有元素
-
retainsAll(Collection col):交集,获取当前集合和col的交集,并返回给当前集合。
-
equals(Object obj):要想返回true,需要当前集合和形参集合的元素都相同
-
hashCode():返回当前对象的哈希值
遍历集合元素的方式
方式一:迭代器Iterator
方式二:增强for循环
方式三:普通循环
迭代器Iterator
遍历集合的方式,Iterator 只是遍历集合,不是容器本身不装东西。
-
Iterator iterator() 返回此collection的元素上进行迭代的迭代器(遍历元素)
常用方法 -
boolean hasNext()//通过迭代器判断集合里是否有元素
-
E next();
代码实现:
泛型 常用来和集合对像一同使用。
本质上就是编译器为了提供更好的可读性而提供的一种小手段。
通过泛型的语法定义来约束集合元素的类型,进行安全检查,把错误显示在编译期
Collection col = new ArrayList();
遍历集合的方式
方式一:通过迭代器Iterator iterator(),— 返回迭代器Iterator,专门用来迭代集合里的元素
//遍历集合
while (it.hasNext()){//hadNext()判断有元素嘛,有的话就返回true.
Integer in = it.next();//next()获取元素。
System.out.print(in+" ");
}
方式二:增强for循环:for(数据类型 变量名 :容器(集合)){}
//方式二:增强for循环:for(数据类型 变量名 :容器(集合)){}
for (Integer in : col){
System.out.println(in);
}
package day05Collection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
/**
* @author yyc
*/
public class CollectionTest1 {
public static void main(String[] args) {
//<E>泛型 常用来和集合对像一同使用。
// 本质上就是编译器为了提供更好的可读性而提供的一种小手段。
// 通过泛型的语法定义来约束集合元素的类型,进行安全检查,把错误显示在编译期
//1.创建集合对象,泛型约束里面的类型是引用类型,不能是基本类型
Collection<Integer> col = new ArrayList<>();//<>前面使用的了泛型。前后保持一致
//col.add("aaa");报错
col.add(23);
//2.常用方法
//①集合添加元素常用add()
col.add(45);
col.add(1);
System.out.println(col);
//col.clear();清空集合
System.out.println(col);
System.out.println(col.contains(5));//判断此集合中是否包含指定数,true.
System.out.println(col.equals(23));//判断集合是否与23是否相等
System.out.println(col.hashCode());//获取col的哈希值,53290
System.out.println(col.remove(23));//从集合col中移除23
System.out.println(col);
System.out.println(col.isEmpty());//判断集合四否为空
System.out.println(col.size());//获取集合的长度
Object[] os = col.toArray();//集合转数组
System.out.println(Arrays.toString(os));//[45, 1]
Collection<Integer> col2 = new ArrayList<>();
col2.add(67);
col2.add(68);
col2.add(69);
col.addAll(col2);//向集合col中添加集合col2
System.out.println(col);
System.out.println(col.size());
System.out.println(col.containsAll(col2));//判断col中是否包含col2
System.out.println(col2.retainAll(col));//求交集(col2 和 col中相同的元素)
//获取集合中的元素
//方式一:通过迭代器Iterator<E> iterator(),--- 返回迭代器Iterator,专门用来迭代集合里的元素
Iterator<Integer> it = col.iterator();//通过集合的迭代器方法获取迭代器引用,迭代器不是容器
//遍历集合
while (it.hasNext()){//hadNext()判断有元素嘛,有的话就返回true.
Integer in = it.next();//next()获取元素。
System.out.print(in+" ");
}
System.out.println();
//方式二:增强for循环:for(数据类型 变量名 :容器(集合)){}
for (Integer in : col){
System.out.println(in);
}
}
}
collections 工具类
概述:专门给collection 集合提供方法的.Collections 是Collection的实现类
-
static boolean addAll(Collection <? super T>c, T …elements) 将所有指定元素添加到指定collection中。
-
static T max(Collection<? extends T> col) 根据其元素的 自然顺序返回给定集合的最大元素
-
static T min(Collection<? extends T> coll, Comparator<? super T> comp) 其元素的 自然顺序返回给定集合的最小元素。
-
static void sort(List list, Comparator<? super T> c) 根据指定比较器产生的顺序对指定列表进行排序。
-
static void reverse(List<?> list) 反转指定列表中元素的顺序。
-
static void swap(List<?> list, int i, int j)在指定列表的指定位置处交换元素
package day05Collection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author yyc
*/
/*
* 测试Collection 的工具类Collections
* */
public class Collections_Test {
public static void main(String[] args){
//1.创建List集合并添加元素
List<Integer> list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list);
//一次性向集合中添加元素。
Collections.addAll(list,15,23,54,65,34);
System.out.println(list);
System.out.println(Collections.max(list));//获取最大值。
System.out.println(Collections.min(list));//获取最小值
//reverse(List list)反转
Collections.reverse(list);
System.out.println(list);
//给集合进行自然排序
Collections.sort(list);
System.out.println(list);//给list集合记性自然排序
Collections.swap(list,0,2);
//给list集合的下标0和下标2的元素交换位置
System.out.println(list);
}
}
2.2List接口
概述:是有序的Collection ,是Collection接口的子接口,可以使用Collection的所有方法,除此之外还做了很多扩展方法,此接口的用户可以对列表中的每个元素的插入位置进行精确的控制,用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的 元素。
特点:
-
元素有序
-
允许存放重复元素
-
元素有索引
-
可以存放null
常用方法
-
ListIterator listIterator() 返回此列表元素的列表迭代器(按适当顺序)。
-
ListIterator listIterator(int index) 返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
-
boolean add(E e) 向列表的尾部添加指定的元素(可选操作)。
-
E set(int index, E element)
用指定元素替换列表中指定位置的元素(可选操作)。 -
List subList(int fromIndex, int toIndex)
返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。
public static void main(String[] args) {
List<String> list = new ArrayList();
list.add("超级英雄");
list.add("开心超人");
list.add("小猪佩奇");
list.add("开心超人");
list.add(null);
list.add("冰雪奇缘");
list.add("齐天大圣孙悟空");
list.add(null);
System.out.println(list);
运行结果
List 特点:元素有序+元素可重复+可以存放多个null +有下标*
package day05Collection.ListTest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* @author yyc
*/
public class ListDeom {
public static void main(String[] args) {
List<String> list = new ArrayList();
list.add("超级英雄");
list.add("开心超人");
list.add("小猪佩奇");
list.add("开心超人");
list.add(null);
list.add("冰雪奇缘");
list.add("齐天大圣孙悟空");
list.add(null);
System.out.println(list);
method2(list);
}
//练习List接口特有的方法
public static void method2(List<String> list){
list.add(4,"绿巨人");//在指定索引出,添加指定元素
System.out.println(list.get(5));//null ,根据下标获取元素
System.out.println(list.indexOf("开心超人"));//获取开心超人第一次出现的索引
System.out.println(list.lastIndexOf("开心超人"));//获取null最后一次出现的索引
System.out.println(list.remove(3));//根据下标移除,返回移除位置的值。
System.out.println(list.set(2,"灭霸"));//把2下标处的元素换成灭霸
List<String> list2 = list.subList(2,5);//截取list从2开始到5结束[2,5)
System.out.println(list);
System.out.println(list2);
//迭代List集合 。方式一:Iterator<E> iterator 继承自-Collection接口
Iterator<String> it = list.iterator();
//遍历迭代器对象
while (it.hasNext()){
String str = it.next();
System.out.print(str +"---");
}
System.out.println();
//迭代List集合 方式二:ListIterator<E> listIterator() -- List接口特有的
ListIterator<String> it2 = list.listIterator();
//遍历列表迭代器
while (it2.hasNext()){
String str = it2.next();
System.out.print(str+"~~~");
}
//逆向遍历之前必须顺序遍历
System.out.println();
while (it2.hasPrevious()){//hasPrevious()是逆向遍历
String str = it2.previous();
System.out.print(str+"---");
}
System.out.println();
//方式三:由于List集合有下标,可以按照下标遍历
for(int i = 0; i < list.size(); i++){
String str = list.get(i);//根据指定下标获取元素
System.out.print(str+"\\\\");
}
System.out.println();
//方式四:增强for循环
for (String s : list){
System.out.print(s +"**");
}
}
}
-
void add(int index, E element) 在列表的指定位置插入指定元素(可选操作)。
-
boolean addAll(Collection<? extends E> c)
添加指定 collection 中的所有元素到此列表的结尾,顺序是指定 collection 的迭代器返回这些元素的顺序(可选操作)。 -
boolean addAll(int index, Collection<? extends E> c)
将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作)。 -
void clear()
从列表中移除所有元素(可选操作)。 -
E get(int index)
返回列表中指定位置的元素。 -
int indexOf(Object o)
返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。 -
E set(int index, E element)
用指定元素替换列表中指定位置的元素(可选操作)。 -
List subList(int fromIndex, int toIndex)
返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图 -
E remove(int index)
移除列表中指定位置的元素(可选操作)。 -
boolean remove(Object o)
从此列表中移除第一次出现的指定元素(如果存在)(可选操作)。
package day05Collection.ListTest;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
/**
* @author yyc
*/
//测试删除集合List集合中200这个元素
//添加元素100,200,300,Integer类型。删除200元素而不是删除下标为200的元素;
public class ListDeom2 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(100);
list.add(200);
list.add(200);
list.add(300);
list.add(200);
list.add(200);
System.out.println(list);
//方式一:删除200
/* for(int i = 0; i < list.size(); i++){
if(i == list.indexOf(200)){//找到200的下标,然后删除该位置的元素。
list.remove(i);
}
}
System.out.println(list);*/
//解决方案:不能传入一个基本类型的变量值,默认当成下标
//System.out.println(list.remove((Integer)200));//只能删除第一个200
//System.out.println(list.remove(Integer.valueOf(200)));//只能删除第一个200,自动装装箱
// System.out.println(list);
ListIterator it = list.listIterator();
while (it.hasNext()){
Integer i = (Integer) it.next();
if (i == 200){
it.remove();
}
}
/*//跳着删除200
for (int i = 0; i < list.size(); i++){
if (list.get(i) == 200){
list.remove(i);
}
}*/
System.out.println(list);
}
}
ArrayList实现类
概述:
-
存放与java.util包下,是 List 集合的实现类
-
内部是用数组存放的数据的,封装了数组的操作,每个元素都有下标
-
内部数组默认初始容量为10, 如果不够会以1.5倍容量增长
-
查询快,增删数据效率会变低
ArrayList 扩容
ArrayList 相当于没指定initalCapacity时就会使用延迟分配对象数组空间,当第一次插入元素时才分配10(默认)个对象空间,假如有20个元素需要添加,那么会在第一次的时候,将ArrayList的容量变为10,之后扩容按照1.5倍增长,就是说当添加第11个元素的时候,ArrayList会继续扩容变为101.5 = 15,当添加第16个元素的时候,继续扩容为151.5 = 22个空间;
-
jdk1.6是创建了一个ArrayList 对象时,直接创建了一个容量为10的数组。
-
jdk1.8是创建了一个ArrayList对象时,创建了一个空数组。是为了优化内存。first element is added 才会扩容。
-
ArrayList arrayList = new ArrayList();//容量为0.
arrayList.add(2);//当且仅当添加第一个元素时数组才扩容至第一次容量为10,数组默认容量是10 ,当超过10 个元素时,底层会自动扩容,
* >扩容方式:int newCapacity = oldCapacity + (oldCapacity >> 1)就是旧容量的1.5倍
package day05Collection.ListTest;
import java.util.ArrayList;
/**
* @author yyc
*/
public class ArrayListDemo {
public static void main(String[] args) {
//jdk1.6是创建了一个ArrayList 对象时,直接创建了一个容量为10的数组。
//jdk1.8是创建了一个ArrayList对象时,创建了一个空数组。是为了优化内存。first element is added 才会扩容。
ArrayList arrayList = new ArrayList();//容量为0.
arrayList.add(2);//当且仅当添加第一个元素时数组才扩容至第一次容量为10,数组默认容量是10 ,当超过10 个元素时,底层会自动扩容,
//扩容方式:int newCapacity = oldCapacity + (oldCapacity >> 1)
//就是旧容量的1.5倍
}
}
1.2 Set接口:存储数据无序,不可存放重复值
Set:存放无序的、不可重复的数据
以HashSet为例说明:
1.无序性:不等于随机性.存储的数据在底层数组中并非按照数组索引的顺序添加,而是按照数组的哈希值
2.不可重复性:保证添加的元素按照equals()方法判断时,不能返回true ,即,相同元素只能添加一个
1、set 接口中没有额外定义新的方法,使用的都是Collection中声明的方法。
2、要求:向Set中添加的数据,其所在类一定要重写hashCode() 和 equals()方法。
要求:重写的hashCode() 和 equals()尽可能保持一致性:相等的对象必须具有相同的散列码
重写方法的小技巧:对象中用作equals()方法比较的Filed,都应该用来计算hashCode值。
二、添加元素的过程:以HashSet为例:
我们像HashSet中添加元素a, 首先调用元素a所在类的hashCode()方法,计算元素a的哈希值。此哈希值接着通过某种算法计算出在HashSet底层数组中存放位置(即为索引位置),判断数组再此位置上是否已经有元素:
如果此位置上没有其他元素,则元素添加成功—> 情况1
如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值,
如果hash值不同,则元素a添加成功。----> 情况2
如果hash值相同,进而需要调用元素a所在类的equals()方法: equals()返回true,元素添加失败。equals()返回false,元素添加成功。---->情况3
对于添加成功的情况2 和情况3 而言:元素a 与已经存在指定索引位置上数据以链表方式存储。
jdk 7 :元素a放到数组中,指向原来的元素
jdk8:原来的元素在数组中, 指向元素a.
总结:七上八下。
HashSet底层:数组+ 链表
package Set;
import org.junit.Test;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* @author yyc
*/
public class SetTest {
@Test
public void test1(){
Set set = new HashSet();
set.add(456);
set.add(123);
set.add(789);
set.add(789);//不可重复性,添加无效
set.add("AA");
set.add("CC");
set.add(new String("abc"));
set.add(new User("张三",12));
set.add(128);
set.add(new User("张三",12));
//遍历set中的元素
//方式一:迭代器
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
结果:
"D:\Program Files\Java\jdk1.8.0_211\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\Program Files\Java\idea2020.2.3\IntelliJ IDEA 2020.2.3\lib\idea_rt.jar=64757:D:\Program Files\Java\idea2020.2.3\IntelliJ IDEA 2020.2.3\bin" -Dfile.encoding=GBK -classpath "D:\Program Files\Java\idea2020.2.3\IntelliJ IDEA 2020.2.3\lib\idea_rt.jar;D:\Program Files\Java\idea2020.2.3\IntelliJ IDEA 2020.2.3\plugins\junit\lib\junit5-rt.jar;D:\Program Files\Java\idea2020.2.3\IntelliJ IDEA 2020.2.3\plugins\junit\lib\junit-rt.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_211\jre\lib\rt.jar;E:\neweclipseworkspace\shangguigu_workspace\classes\production\Collection;E:\neweclipseworkspace\shangguigu_workspace\lib\junit-4.12.jar;E:\neweclipseworkspace\shangguigu_workspace\lib\hamcrest-core-1.3.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 Set.SetTest,test1
AA
CC
128
abc
User{name='张三', age=12}
789
456
User{name='张三', age=12}
123
Process finished with exit code 0
1.2.1 Set接口的实现类
1.2.2 HashSet:作为Set接口的主要实现类,线程不安全的;可以存储Null值
1.2.3 LinkedHashSet类:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序去遍历。
LinkedHashSet的使用:
LinkedHashSet 作为HashSet的子类,在添加数据的同时,每个数据还具有前驱和后继指针,记录此数据前一个数据和后一个数据。
优点:对于频繁的遍历操作,LinkedHashSet效率高于HashSet
1.2.4 TreeSet 类:底层存放 的数据必须是同一个类型,可以按照添加的对象指定属性进行排序。
Collections工具