集合的概述 Java提供了特殊的类,这个类像是数组,但是它却和数组不一样,因为它储存的内容可以使任意的对象,并且它的储存长度是可以进行改变的。这个类位于java.unit包中,所以在进行调用的时候记得导入相应的包。
集合按照它的储存方式可以分为两大模式,首先是单列集合 Collection,然后就是双列集合Map.
现在来分析一下这两种集合的特点: 单列集合(Collection集合): 单列集合的根接口,用于储存一系列符合某种规则的元素: 下面的接口关系使用X-main进行表示
双列集合(Map集合): 双列集合的根接口,用于储存具有键(Key)、值(Value)映射关系的元素 (有一点像哈希表的味道)
Collection接口(根接口)
List接口: List接口继承Collection接口,List集合中允许出现重复的元素,所有元素是以一种线性方式进行储存的,在程序中可以通过索引来访问集合中指定的元素.
其中有一些函数: (上网找到相应的图片)ArrayList接口是List接口实现的一个类,ArrayList集合看作长度可变的数组,所以它不适合做大量的增删操作,但是在查找元素的时候将变得比较高效
代码如下:
/**
* @Author 陈辉明
* @Date 2021-11-01 11:40
* @Version 1.0
*/
import java.util.ArrayList;
public class arrayList {
public static void main(String[] args) {
//使用ArrayList的代码
//实现的目标,打印出ArrayList里面的元素个数,打印出按照索引给出的元素
ArrayList a1 = new ArrayList();
a1.add("list1");
a1.add("list2");
a1.add("list3");
a1.add("list4");
System.out.println("集合的长度是: " + a1.size());
System.out.println("集合的第二个元素是: " + a1.get(1));
}
}
**
这里需要注意的是,索引的开始值是0,最后的一个索引是size - 1
**
/**
* @Author 陈辉明
* @Date 2021-11-01 12:11
* @Version 1.0
*/
import java.util.LinkedList;
public class linkedList {
public static void main(String [] args) {
//创建linkedList集合
LinkedList link = new LinkedList();
//1.添加元素
link.add("stu1");
link.add("stu2");
//输出集合当中的元素
System.out.println(link);
link.offer("在尾部加入元素");
link.push("在头部加入元素");
System.out.println(link);
//获取元素
System.out.println("——————————————————————————————————————————————");
Object object = link.peek(); //获取集合的第一个元素
System.out.println(object);
System.out.println("——————————————————————————————————————————————");
//删除元素
link.removeFirst(); //删除集合的第一个元素
link.pollLast(); //删除集合的最后一个元素
System.out.println(link);
}
}
上面对Collection的两种子类进行了介绍,那么我们对数据进行了存储,但是我们如何对数据进行遍历操作呢,下面我们来介绍一下如何对存储在里面的数据如何进行遍历吧.
1.Iterator遍历集合
ilterator主要用于遍历Collection集合当中的元素,因此iterator对象也叫做迭代器
实现代码如下面:
/**
* @Author 陈辉明
* @Date 2021-11-01 17:47
* @Version 1.0
*/
import java.util.ArrayList;
import java.util.Iterator;
public class iterator {
public static void main(String[] agrs) {
//创建ArrayList集合
ArrayList list = new ArrayList();
//向改集合当中添加字符串
list.add("data_1");
list.add("data_2");
list.add("data_3");
list.add("data_4");
//获取iterator对象
Iterator iterator = list.iterator();
//判断集合当中是否存在下一个元素
while(iterator.hasNext()) {
Object obj = iterator.next(); //取出ArrayList集合之中的元素,类似于C语言当中的链表中的指针指向下一个元素
System.out.println(obj);
}
}
}
在这种遍历的方式下调用集合的对象remove()方法去删除元素的时候会出现异常,下面通过一个异常的代码来演示一下这些结果
/**
* @Author 陈辉明
* @Date 2021-11-02 10:49
* @Version 1.0
*/
import java.util.ArrayList;
import java.util.Iterator;
public class ilterator_remove {
public static void main(String [] args) {
ArrayList list = new ArrayList();
list.add("线段12");
list.add("线段13");
list.add("线段14");
list.add("线段15");
Iterator i = list.iterator();
while(i.hasNext()) {
Object obj = i.next();
if ("线段12".equals(obj)) {
list.remove(obj);
}
}
System.out.println(list);
}
}
运行结果如下:
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
at ilterator_remove.main(ilterator_remove.java:19)
Process finished with exit code 1
出现异常的原因是集合中删除了元素会导致遍历的预期的遍历次数发生变化,导致遍历的结果不准确
下面有两种方法在使用循环的过程当中进行对集合元素的删除:
方法一:
在一种思路上面来说,我们只是想删除一个元素,所以,我们只需要使用迭代器对那个元素进行处理,然后再对这个元素删除完再进行跳出这个迭代
if ("list_23".equals(obj)) {
list.remove(obj);
break;
}
方法二
如何需要在遍历的期间对集合的元素进行删除,那一使用迭代器本身的删除方法
if ("list_23".equals(obj)) {
it.remove();
}
2.foreach遍历集合
使用foreach遍历集合的优点就是更加简洁地使用for循环进行循环遍历数组或者集合中的元素。foreach循环语句非常简洁,没有循环条件,也没有迭代语句,所有这些工作都交给JVM去执行了。foreach循环的次数是由容器中的元素的个数决定的,每一次循环,foreach中都通过变量将当前的元素记住,从而将集合中的元素分别打印出来.需要注意的是,
/**
* @Author 陈辉明
* @Date 2021-11-02 17:29
* @Version 1.0
*/
import java.util.ArrayList;
/*
使用foreach遍历集合的优点就是更加简洁地使用for循环进行循环遍历数组或者集合中的元素
*/
public class foreach {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("小");
list.add("古");
list.add("追");
list.add("光");
//使用foreach循环进行对集合的遍历
for (Object obj: list) {
System.out.println(obj); //打印出集合当中的元素
}
}
}
使用foreach循环遍历集合和数组时,只能访问集合中的元素,不能对其中的元素进行修改.
/**
* @Author 陈辉明
* @Date 2021-11-02 17:43
* @Version 1.0
*/
public class foreach_error {
static String[] strs = {"aaa", "bbb", "ccc"};
public static void main(String[] args) {
//1.foreach遍历数组
for (Object obj: strs) {
obj = "syyds";
}
System.out.println("在遍历之中修改之后的数组为:" + strs[0] + strs[1] + strs[2]);
}
}
运行结果如下:
在遍历之中修改之后的数组为:aaabbbccc
Process finished with exit code 0
3.JDK8的forEach遍历集合
接下来演示一下如何进行使用forEach遍历集合对象,这个代码如下:
/**
* @Author 陈辉明
* @Date 2021-11-02 19:14
* @Version 1.0
*/
import java.util.ArrayList;
public class foreach_1 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("data_1");
list.add("data_2");
list.add("data_3");
list.add("data_4");
System.out.println(list);
//使用IDK增加的forEach(Consumer action)方法遍历的集合
list.forEach(obj -> System.out.println("迭代集合元素:" + obj));
}
}
/*
set接口比Collection更加地严格,在set接口当中的元素是无序的,并且会以某种规则让加进来的元素不出现重复
set方法具有两个实现的类,分别是HashSet()和TreeSet().
其中HashSet()是根据对象的哈希值来确定元素在集合中的存储的位置,因此具有良好的存取和查找性能.
其中TreeSet()是以二叉树的方法来存储元素,它可以实现对集合中的元素进行排序。
*/
二.Set接口
Set接口中的元素无序,并且都会以魔种规则保证存入的元素不出现重复,Set接口主要有两个实现类,分别是HashSet和TreeSet,其中HashSet是根据对象的哈希值来确定元素在集合中的存储的位置,一次具有良好的存取和查找性能.TreeSet则是以二叉树的方式来存储元素,它可以实现对集合中的元素进行排序.
1.SetHash集合,并且元素存储时不可以重复的,并且元素都是无序的,当向HashSet集合中添加一个元素时候,首先会调用该元素的hashCode()方法来确定元素的存储位置,然后再调用元素对象的equals()方法来确定该位置没有重复元素。Set集合与List集合存取元素的方式都一样,下面来演示一下HashSet()的代码:
import java.util.HashSet;
/**
* @Author 陈辉明
* @Date 2021-11-03 15:38
* @Version 1.0
*/
/*
接下来进行介绍一下HashSet集合的使用代码
*/
public class hashSet_1 {
public static void main(String[] args) {
HashSet set = new HashSet();
set.add("study");
set.add("study");
set.add("do");
//遍历输出Set集合中的元素
set.forEach(o -> System.out.println(o));
}
}
下面使用Xmind软件编写一个添加元素的操作流程:
当向集合里面存如元素的时候,为了保证HashSet正常工作,要求再存入对象时,需要重写Object类中的hashCode()和equal()方法。但是使用编程者自定义的类型对象的时候存储进HashSet时,可能会发生存储重复的现象.
验证的代码如下:
/** * @Author 陈辉明 * @Date 2021-11-03 15:55 * @Version 1.0 */
import javax.swing.plaf.basic.BasicScrollPaneUI; import java.util.*; class Student_hasSet_2 {
String id;
String name;
public Student_hasSet_2(String id, String name) {
this.id = id;
this.name = name;
}
public String toString() {
return id + ":" + name;
} }
public class hashSet_2 {
public static void main(String[] args) {
HashSet hs = new HashSet();
Student_hasSet_2 st1 = new Student_hasSet_2("1", "study");
Student_hasSet_2 st2 = new Student_hasSet_2("1", "study");
Student_hasSet_2 st3 = new Student_hasSet_2("3", "job");
hs.add(st1);
hs.add(st2);
hs.add(st3);
System.out.println(hs);
} }
运行结果如下:
[1:study, 1:study, 3:job]
Process finished with exit code 0
上面的运行结果可以看出,由于study被存储了两次.
之所以出现了两次study存储的情况,是因为在定义Student_hasSet_2的时候没有进行重写hashCode()方法和equal()方法,现在写出一个进行重写的代码实验一下.
代码如下:
/**
* @Author 陈辉明
* @Date 2021-11-03 16:05
* @Version 1.0
*/
import java.util.HashSet;
class Students_haset3 {
private String id;
private String name;
public Students_haset3(String id, String name) {
this.id = id;
this.name = name;
}
//重写toString()方法,让toString用这种方法进行返回数据
public String toString() {
return id + ":" + name;
}
//重写hashCode()方法
public int hashCode() {
return id.hashCode();
}
//重写equaks()方法
public boolean equals(Object obj) {
if (this == obj) { //判断是否是同一个对象
return true; //如果是,返回true
}
if (!(obj instanceof Students_haset3)) { //判断对象是为Student类型
return false; //如果对象不是Student类型,返回false
}
Students_haset3 stu = (Students_haset3) obj; //将对象强制转化为Student类型
boolean b = this.id.equals(stu.id); //判断id的值是否相同
return b; //返回判断的结果
}
}
public class hashSet_3 {
public static void main(String[] args) {
HashSet hs = new HashSet();
//记住创建的那个对象是Students_haset3的,因为它蕴含了重写检查对象ID的函数.
Students_haset3 st1 = new Students_haset3("1", "study");
Students_haset3 st2 = new Students_haset3("1", "study");
Students_haset3 st3 = new Students_haset3("3", "job");
hs.add(st1);
hs.add(st2);
hs.add(st3);
System.out.println(hs);
}
}
运行结果:
[1:study, 3:job]
Process finished with exit code 0