集合
集合的概述和总结
集合是java中提供的一种容器,可以用来存储多个数据。
集合和数组既然都是容器,它们有啥区别呢?
数组的长度是固定的。集合的长度是可变的。
数组中可以存储基本数据类型值,也可以存储对象,而集合中只能存储对象
集合主要分为两大系列:Collection和Map,Collection 表示一组对象,Map表示一组映射关系或键值对。
一·集合框架的概述
<p>
1.集合,数组都是对多个数据进行存储操作的结构,简称java容器。
说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,.avi,数据库中的数据等)。
2.1数组在存储多个数据方面的特点:
> 一旦初始化以后,其长度就确定了。
>数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。
比如:String[] arr;int[] arr1;Object[] arr2;
2.2数组在存储多个数据方面的缺点:
>一旦初始化以后,其长度就不可修改。
>数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常的不方便,同时效率不高。
>获取数组中实际元素的个数的需求,数组没有现成的属性或者方法可用。
>数组存储数据的特点:有序,可重复。对于无序、不可重复的需求,不能满足。
<p>
二.集合框架
|---Collection接口:单列集合,用来存储一个一个的对象。
|---List接口:存储有序的、可重复的数据。也可以称为--->"动态数组"。
|---ArrayList、LinkedList、Vector。
|---Set接口:存储无序的、不可重复的数据。
|---HashSet、LinkedHashSet、TreeSet。
<p>
|---Map接口:双列集合,用来存储一对(key-value)一对的数据。
|---HashMap、LinkedHashMap、TreeMap、HashTable、Properties
Collection中抽象方法的使用(15个)
Collection 层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接实现:它提供更具体的子接口(如 Set 和 List、Queue)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。
结论:
Collection接口的实现类的对象中添加数据o时,要求o所在类要重写equals()。
ArrayList的equals和hashcode都进行了重写,并且hashcode的默认值为1。
Collection<E>是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合。方法如下:
boolean add(E e):将元素e,添加到集合col中。null也能存储成功,并且元素可以重复。 E是泛型,这里由于之前学的泛型忘了,还没复习到泛型;所以泛型统一用Object类型表示。
int size():获取该集合中的元素个数。返回此集合中的元素数。如果此集合包含超过Integer。MAX_VALUE元素返回Integer.MAX_VALUE。
boolean addAll(Collection<? extends E> c):将指定集合中的所有元素添加到此集合(可选操作)。如果在操作进行时修改了指定的集合, 则此操作的行为是未定义的。(这意味着如果指定的集合为此集合,且此集合非空,则此调用的行为是未定义的。)
boolean isEmpty():判断当前集合是否为空,如果此集合不包含任何元素,则为 true。如果是放的null,结果返回false。因为null也是一个元素。
public void clear():从此集合中移除所有元素(可选操作)。该方法返回后,集合将为空。
//Collection接口中的所有抽象方法的使用(15个),抽象方法是没有方法体的。
Collection col = new ArrayList();
//1.boolean add(E e):将元素e,添加到集合col中。null也能存储成功,并且元素可以重复。
// E是泛型,这里由于之前学的泛型忘了,还没复习到泛型;所以泛型统一用Object类型表示。
boolean aa = col.add("aa");
System.out.println(aa);//true
boolean add = col.add(null);
boolean ad = col.add(null);
System.out.println(add);//true
col.add("bb");
col.add("aa");
col.add(123);//自动装箱:基本数据转化为包装类在使用。因为集合中不能存储基本数据类型的数据。
col.add(new Date());
System.out.println(col);//[aa, bb, aa, 123, Fri Feb 17 15:56:47 CST 2023]
//2.int size():获取该集合中的元素个数。返回此集合中的元素数。如果此集合包含超过Integer。MAX_VALUE元素返回Integer.MAX_VALUE
System.out.println(col.size());//7
//3.boolean addAll(Collection<? extends E> c):将指定集合中的所有元素添加到此集合(可选操作)。如果在操作进行时修改了指定的集合,
// 则此操作的行为是未定义的。(这意味着如果指定的集合为此集合,且此集合非空,则此调用的行为是未定义的。)
//新建一个集合
Collection col1 = new ArrayList();
System.out.println(col1);//[]
col.addAll(col1);
System.out.println(col.size());//7
col1.add(null);
col1.add(34);
col1.add(35);
//将col1集合中的所有元素添加到col集合中
col.addAll(col1);
System.out.println(col.size());//10
//4.boolean isEmpty():判断当前集合是否为空,如果此集合不包含任何元素,则为 true。如果是放的null,结果返回false。
// 因为null也是一个元素。
System.out.println(col1.isEmpty());//判断当前集合中的元素个数是否为0个
//5.public void clear():从此集合中移除所有元素(可选操作)。该方法返回后,集合将为空。
System.out.println(col1.size());//3
System.out.println(col1.isEmpty());//false
col1.clear();
System.out.println(col1.size());//0
System.out.println(col1.isEmpty());//true
boolean contains(Object o):判断当前集合中是否包含o
boolean containsAll(Object o):判断形参o中的所有元素是否都存在于当前集合中。
/**
* Collection接口中声明的方法的测试
*结论: Collection接口的实现类的对象中添加数据o时,要求o所在类要重写equals()。
*/
@Test
public void test2() {
Collection col = new ArrayList();
col.add(123);
col.add("欣爱康");
col.add("fhakl");
col.add(76532);
//6.boolean contains(Object o):判断当前集合中是否包含o
//我们在判断时会调用o对象所在类的equals()。
// boolean contains = col.contains(123);
// System.out.println(contains);//true
//7.boolean containsAll(Object o):判断形参o中的所有元素是否都存在于当前集合中。
Collection col1 = Arrays.asList(123, 4567);
System.out.println(col.containsAll(col1));//false
Collection col2 = Arrays.asList(123, 76532);
System.out.println(col.containsAll(col2));//true
}
boolean remove(Object o):从当前集合中移除o元素。如果集合中有多个该元素只移除索引最小的那一个元素。
boolean removeAll(Collection<?> c):从当前集合中移除与c集合共有的所有元素。
@Test
public void test3() {
Collection col = new ArrayList();
col.add(123);
col.add("欣爱康");
col.add(123);
col.add(123);
col.add("欣爱康");
col.add("fhakl");
col.add(76532);
//8.boolean remove(Object o):从当前集合中移除o元素。如果集合中有多个该元素只移除索引最小的那一个元素。
// System.out.println(col.size());
// System.out.println(col);
// col.remove("欣爱康");
// System.out.println(col.size());
// System.out.println(col);
//9.boolean removeAll(Collection<?> c):从当前集合中移除与c集合共有的所有元素。
Collection col1 = new ArrayList();
col1.add("欣爱康");
col1.add("fhakl");
col1.add(76);
System.out.println(col.size());//7
System.out.println(col);//[123, 欣爱康, 123, 123, 欣爱康, fhakl, 76532]
System.out.println(col1.size());//3
System.out.println(col1);//[欣爱康, fhakl, 76]
col.removeAll(col1);
System.out.println(col.size());//4
System.out.println(col);//[123, 123, 123, 76532]
System.out.println(col1.size());//3
System.out.println(col1);//[欣爱康, fhakl, 76]
}
boolean retainAll(Collection<?> c):交集,获取当前集合与c集合的交集部分,并返回给当前集合。
@Test
public void test4() {
Collection col = new ArrayList();
col.add(123);
col.add("欣爱康");
col.add("欣爱康");
col.add("欣爱康");
col.add(123);
//10.boolean retainAll(Collection<?> c):交集,获取当前集合与c集合的交集部分,并返回给当前集合。
Collection col1 = new ArrayList();
col1.add("欣爱康");
col1.add("欣爱康");
col1.add("fhakl");
col1.add(76);
System.out.println(col.size());//5
System.out.println(col);//[123, 欣爱康, 欣爱康, 欣爱康, 123]
System.out.println(col1.size());//4
System.out.println(col1);//[欣爱康, 欣爱康, fhakl, 76]
col.retainAll(col1);
System.out.println(col.size());//3
System.out.println(col);//[欣爱康, 欣爱康, 欣爱康]
System.out.println(col1.size());//4
System.out.println(col1);//[欣爱康, 欣爱康, fhakl, 76]
}
boolean equals(Object o):当前集合与o集合比较,如果每个索引位置的对象内容都相等才返回true,否则返回false。
@Test
public void test5() {
Collection col = new ArrayList();
col.add(123);
col.add("欣爱康");
//11.boolean equals(Object o):当前集合与o集合比较,如果每个索引位置的对象内容都相等才返回true,否则返回false。
Collection col1 = new ArrayList();
col1.add("欣爱康");
col1.add(123);
System.out.println(col.equals(col1));//false 因为ArrayList是有序可重复的。
Collection col2 = new ArrayList();
col2.add(123);
col2.add("欣爱康");
System.out.println(col.equals(col2));//true
}
hashCode():返回此集合的哈希码值。
如果equals方法被重写,hashCode方法一定要重写。两个对象比较时调用equals(Object o)返回true,那么两个对象的hashCode一定相等。两个对象的hashCode相等,两个对象不一定相等。
@Test
public void test6() {
Collection col = new ArrayList();
System.out.println(new Object().hashCode());
Collection col1 = new ArrayList();
System.out.println(new ArrayList().hashCode());
//12.hashCode():返回此集合的哈希码值。如果equals方法被重写,hashCode方法一定要重写。
// 两个对象比较时调用equals(Object o)返回true,那么两个对象的hashCode一定相等。
// 两个对象的hashCode相等,两个对象不一定相等。
System.out.println(col.hashCode());
System.out.println(col1.hashCode());
}
Object[] toArray():将当前集合转为数组。
public static <T> List<T> asList(T... a):参数为可变形参,将当前数组转为集合。
@Test
public void test7() {
//13.Object[] toArray():将当前集合转为数组。
Collection col = new ArrayList();
col.add(123);
col.add("欣爱康");
Object[] objects = col.toArray();
System.out.println(col);//[123, 欣爱康]
System.out.println(objects);//[Ljava.lang.Object;@c81cdd1
System.out.println(new ArrayList());//[]
System.out.println(new ArrayList().toArray());//[Ljava.lang.Object;@1fc2b765
//14.public static <T> List<T> asList(T... a):参数为可变形参,将当前数组转为集合。
List<Object> objects1 = Arrays.asList(objects);
System.out.println(objects1);//[123, 欣爱康]
}
Iterator迭代器:作用是遍历集合,跟for循环类似。本身并不是容器。
总结:集合元素的遍历操作,使用Iterator接口。
①通过迭代器遍历集合中的元素,每个元素只能被遍历一次,在一个方法中如果重复遍历,则可能会报java.util.NoSuchElementException的异常。
②如果集合中的元素是集合,那么通过迭代器遍历时输出的是内部的集合;
如果集合中的元素是数组,那么通过迭代器遍历该集合时输出的是这个数组的地址值。
③集合对象每次调用iterator()方法都得到一个新的迭代器对象,默认游标都在集合的第一个元素之前。
④内部定义了remove(),可以在遍历的时候,删除集合中的元素。此方法不同于集合直接调用remove().
⑤如果还未调用next()或在上一次调用next方法之后已经调用了remove方法,再调用remove都会报java.lang.IllegalStateException。
hasNext():通过指针判断该集合中是否还有下一个元素,指针的初始位置在该集合第一个元素所在位置的前面。
next():①指针下移②将下移以后集合位置上的元素返回。
/**
* 总结:集合元素的遍历操作,使用Iterator接口。
* ①通过迭代器遍历集合中的元素,每个元素只能被遍历一次,在一个方法中如果重复遍历,则可能会报java.util.NoSuchElementException的异常。
* ②如果集合中的元素是集合,那么通过迭代器遍历时输出的是内部的集合;
* 如果集合中的元素是数组,那么通过迭代器遍历该集合时输出的是这个数组的地址值。
* ③集合对象每次调用iterator()方法都得到一个新的迭代器对象,默认游标都在集合的第一个元素之前。
*/
@Test
public void test8() {
//Iterator<E> iterator():返回此集合中元素的迭代器。对于元素的返回顺序没有保证(除非此集合是提供保证的某个类的实例)。
//<E> –此集合中元素的类型
String[] strings1 = new String[]{"太难1", "阿辉1", "法本记录卡1"};
ArrayList list = new ArrayList();
list.add("太难2");
list.add("阿辉2");
list.add("法本记录卡2");
String[] strings2 = new String[]{"法拉克", "fabj", "法录卡"};
ArrayList list1 = new ArrayList();
list1.add("法拉克2");
list1.add("fabj2");
list1.add("法录卡2");
Collection col = new ArrayList();
col.add(strings1);
col.add(strings2);
col.add(list);
col.add(list1);
col.add(123);
col.add("欣爱康");
//迭代器:专门用来遍历集合。本身并不是容器
Iterator iterator = col.iterator();
//方式一:(不推荐)
// System.out.println(iterator.next());//[Ljava.lang.String;@c81cdd1
// System.out.println(iterator.next());//[Ljava.lang.String;@c81cdd1
// System.out.println(iterator.next());//[太难2, 阿辉2, 法本记录卡2]
// System.out.println(iterator.next());//[法拉克2, fabj2, 法录卡2]
//方式二:(不推荐)
// for (int i = 0; i < col.size(); i++) {
// System.out.println(iterator.next());
// }
//方式三:(推荐)
//hasNext():通过指针判断该集合中是否还有下一个元素,指针的初始位置在该集合第一个元素所在位置的前面。
while (iterator.hasNext()) {
//next():①指针下移②将下移以后集合位置上的元素返回。
//123
//欣爱康
System.out.println(iterator.next());
}
//java.util.NoSuchElementException:由各种访问器方法引发,以指示所请求的元素不存在。
// System.out.println(iterator.next());
}
@Test
public void test9() {
//Iterator<E> iterator():返回此集合中元素的迭代器。对于元素的返回顺序没有保证(除非此集合是提供保证的某个类的实例)。
//<E> –此集合中元素的类型
String[] strings1 = new String[]{"太难1", "阿辉1", "法本记录卡1"};
ArrayList list = new ArrayList();
list.add("太难2");
list.add("阿辉2");
list.add("法本记录卡2");
Collection col = new ArrayList();
col.add(strings1);
col.add(list);
col.add(123);
col.add("欣爱康");
//迭代器:专门用来遍历集合。本身并不是容器
Iterator iterator = col.iterator();
//错误的遍历:方式一
//java.util.NoSuchElementException
// while (iterator.next() != null) {
// System.out.println(iterator.next());
// }
//错误的遍历:方式二
while (col.iterator().hasNext()) {
System.out.println(col.iterator().next());
}
}
java.util.Iterator接口
在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,JDK专门提供了一个接口java.util.Iterator。Iterator接口也是Java集合中的一员,但它与Collection、Map接口有所不同,Collection接口与Map接口主要用于存储元素,而Iterator主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器。
想要遍历Collection集合,那么就要获取该集合迭代器完成迭代操作,下面介绍一下获取迭代器的方法:
public Iterator iterator(): 获取集合对应的迭代器,用来遍历集合中的元素的。
下面介绍一下迭代的概念:
迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
Iterator接口的常用方法如下:
public E next():返回迭代的下一个元素。
public boolean hasNext():如果仍有元素可以迭代,则返回 true。
迭代器的实现原理
当遍历集合时,首先通过调用集合的iterator()方法获得迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素,如果存在,则调用next()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。
Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素,Iterator对象迭代元素的过程:
![](https://img-blog.csdnimg.cn/img_convert/93d57bad6e704eb8bd0a4fcfdf0f70c4.png)
在调用Iterator的next方法之前,迭代器的索引位于第一个元素之前,指向第一个元素,当第一次调用迭代器的next方法时,返回第一个元素,然后迭代器的索引会向后移动一位,指向第二个元素,当再次调用next方法时,返回第二个元素,然后迭代器的索引会再向后移动一位,指向第三个元素,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。
使用Iterator迭代器删除元素
/**
* 通过迭代器中删除元素
*/
@Test
public void test10() {
//
ArrayList list = new ArrayList();
list.add("太难2");
list.add("阿辉2");
list.add("法本记录卡2");
Collection col = new ArrayList();
col.add(list);
col.add(123);
col.add("欣爱康");
// boolean remove = col.remove(123);//这是调用col对象里面的remove方法
// System.out.println(col);
Iterator iterator = col.iterator();
//报异常:java.lang.IllegalStateException
// iterator.remove();//这是调用的Iterator迭代器里面的remove方法
//System.out.println(col);
//删除集合中的指定元素
while (iterator.hasNext()) {
//①移动指针②将指针移动后所指的集合中的元素返回
Object next = iterator.next();
if ("欣爱康".equals(next)) {
//调用迭代器的remove方法
iterator.remove();
}
}
System.out.println(iterator.hasNext());//false
iterator = col.iterator();//将迭代器指针重置到初始位置
// //重新遍历集合
while (iterator.hasNext()) {
System.out.print(iterator.next());//[太难2, 阿辉2, 法本记录卡2]123
}
// 通过指针判断该集合中是否还有下一个元素,如果有返回true
while (iterator.hasNext()) {
//调用迭代器的remove方法
iterator.remove();//java.lang.IllegalStateException
}
注意:不要在使用Iterator迭代器进行迭代时,调用Collection的remove(xx)方法,否则会报异常java.util.ConcurrentModificationException,或出现不确定行为。
增强for
增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。
格式:
for(遍历出来的元素的数据类型 变量名 : Collection集合or数组){
//写操作代码
}
增强for循环内部仍然是调用迭代器进行遍历
遍历数组
通常只进行遍历元素,不要在遍历的过程中对数组元素进行修改。
public class NBForDemo1 {
public static void main(String[] args) {
int[] arr = {3,5,6,87};
//使用增强for遍历数组
for(int a : arr){//a代表数组中的每个元素
System.out.println(a);
}
}
}
遍历集合
通常只进行遍历元素,不要在遍历的过程中对集合中的元素进行增加、删除、替换操作。
public class NBFor {
public static void main(String[] args) {
Collection<String> coll = new ArrayList<String>();
coll.add("小河神");
coll.add("老河神");
coll.add("神婆");
//使用增强for遍历
for(String s :coll){//接收变量s代表被遍历到的集合元素
System.out.println(s);
}
}
}
java.lang.Iterable接口
java.lang.Iterable接口,实现这个接口允许对象成为 "foreach" 语句的目标。
Java 5时Collection接口继承了java.lang.Iterable接口,因此Collection系列的集合就可以直接使用foreach循环遍历。
java.lang.Iterable接口的抽象方法:
public Iterator iterator(): 获取对应的迭代器,用来遍历数组或集合中的元素的。
自定义某容器类型,实现java.lang.Iterable接口,发现就可以使用foreach进行迭代。
public class TestMyArrayList {
public static void main(String[] args) {
MyArrayList<String> my = new MyArrayList<>();
for(String obj : my) {
System.out.println(obj);
}
}
}
class MyArrayList<T> implements Iterable<T>{
@Override
public Iterator<T> iterator() {
return null;
}
}