欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 新车 > java-单列集合list与set。

java-单列集合list与set。

2025/5/28 22:06:10 来源:https://blog.csdn.net/qq_69149404/article/details/148217968  浏览:    关键词:java-单列集合list与set。

集合定位:存储数据的容器

与数组的区别:

  • 数组只能存储同种数据类型数据,集合可以存储不同类型的数据。

  • 数组的长度一旦创建长度不可变,集合的长度是可变的

  • 数组的操作单一,集合的操作比较丰富(增删改查)

可以分为单列集合与双列集合:

单例集合:每个元素(数据)只包含一个值。
collecion--->List集合:ArrayList类LinkedList类添加的元素是有序、可重复、有索引。Set集合:	HashSet: 无序、不重复、无索引;LinkedHashSet: 有序、不重复、无索引。TreeSet:按照大小默认升序排序、不重复、无索引。双列集合:每个元素包含两个值(键值对)。
Map      -->

1.Collection的常用方法

Collection是单列集合的祖宗,它规定的方法(功能)是全部单列集合都会继承的。

常用方法如下:

//1.public Object[] toArray(): 把集合转换为数组
Object[] array = c.toArray();
System.out.println(Arrays.toString(array)); //[java1,java2, java2, java3]//2.如果想把集合转换为指定类型的数组,可以使用下面的代码
String[] array1 = c.toArray(new String[c.size()]);
System.out.println(Arrays.toString(array1)); //[java1,java2, java2, java3]//3.还可以把一个集合中的元素,添加到另一个集合中
Collection<String> c1 = new ArrayList<>();
c1.add("java1");
c1.add("java2");
Collection<String> c2 = new ArrayList<>();
c2.add("java3");
c2.add("java4");
c1.addAll(c2); //把c2集合中的全部元素,添加到c1集合中去
System.out.println(c1); //[java1, java2, java3, java4]

2.Collection的遍历方法

2.1 迭代器遍历集合

原理如下:

  • 当调用iterator()方法获取迭代器时,当前指向第一个元素

  • hasNext()方法则判断这个位置是否有元素,如果有则返回true,进入循环

  • 调用next()方法获取元素,并将当月元素指向下一个位置,

  • 等下次循环时,则获取下一个元素,依此内推

  • 如果取元素越界,会出现**NoSuchElementException异常。**

Collection<String> c = new ArrayList<>();
c.add("赵敏");
c.add("小昭");
//第一步:先获取迭代器对象
//解释:Iterator就是迭代器对象,用于遍历集合的工具)
Iterator<String> it = c.iterator();//第二步:用于判断当前位置是否有元素可以获取
//解释:hasNext()方法返回true,说明有元素可以获取;反之没有
while(it.hasNext()){//第三步:获取当前位置的元素,然后自动指向下一个元素.String e = it.next();System.out.println(s);
}

2.2 增强for遍历集合

格式:for(元素的数据类型 变量名:数组或者集合)

增强for不光可以遍历集合,还可以遍历数组。

Collection<String> c = new ArrayList<>();
c.add("赵敏");
c.add("小昭");
//1.使用增强for遍历集合
for(String s: c){System.out.println(s); 
}//2.再尝试使用增强for遍历数组
String[] arr = {"迪丽热巴", "古力娜扎", "稀奇哈哈"};
for(String name: arr){System.out.println(name);
}

2.3 foreach遍历集合

forEach方法的参数是一个Consumer接口,而Consumer是一个函数式接口,所以可以传递Lambda表达式。

Collection<String> c = new ArrayList<>();
c.add("赵敏");
c.add("小昭");
//调用forEach方法
//由于参数是一个Consumer接口,所以可以传递匿名内部类
c.forEach(new Consumer<String>{@Overridepublic void accept(String s){System.out.println(s);}
});//也可以使用lambda表达式对匿名内部类进行简化
c.forEach(s->System.out.println(s)); //[赵敏, 小昭, 素素, 灭绝]

当往集合中存对象时,实际上存储的是对象的地址值:

3.List系列集合

ArrayList、LinekdList:有序,可重复,有索引。

3.1 List集合的常用方法

3.2 ArrayList底层的原理

ArrayList集合底层是基于数组结构实现的,也就是说当你往集合容器中存储元素时,底层本质上是往数组中存储元素。

数组扩容,并不是在原数组上扩容(原数组是不可以扩容的),底层是创建一个新数组,然后把原数组中的元素全部复制到新数组中去。

ArrayList集合适合的应用场景:

  • 适合根据索引查询数据,或者数据量不是很大时。

  • 不适合在数据量大的同时,又要频繁的进行增删操作。

3.3 LinkedList底层原理

LinkedList集合是基于双向链表实现了,所以相对于ArrayList新增了一些可以针对头尾进行操作的方法,如下图示所示:

3.4 LinkedList的应用场景

它可以用来设计队列和栈结构。

//1.创建一个队列:先进先出、后进后出
LinkedList<String> queue = new LinkedList<>();//入对列queue.addLast("第1号人");
queue.addLast("第2号人");
queue.addLast("第3号人");
queue.addLast("第4号人");
System.out.println(queue);​//出队列System.out.println(queue.removeFirst());    //第4号人System.out.println(queue.removeFirst());    //第3号人System.out.println(queue.removeFirst());    //第2号人System.out.println(queue.removeFirst());    //第1号人
//1.创建一个栈对象
LinkedList<String> stack = new ArrayList<>();
//压栈(push) 等价于 addFirst()
stack.push("第1颗子弹");
stack.push("第2颗子弹");
stack.push("第3颗子弹");
stack.push("第4颗子弹");
System.out.println(stack); //[第4颗子弹, 第3颗子弹, 第2颗子弹,第1颗子弹]//弹栈(pop) 等价于 removeFirst()
System.out.println(statck.pop()); //第4颗子弹
System.out.println(statck.pop()); //第3颗子弹
System.out.println(statck.pop()); //第2颗子弹
System.out.println(statck.pop()); //第1颗子弹//弹栈完了,集合中就没有元素了
System.out.println(list); //[]

4. Set集合

4.1 Set集合的特点

4.2 HashSet底层原理

哈希值就是一个int类型的数值,Java中每个对象都有一个哈希值。

java中的所有对象,都可以调用Object类提供的hashCode方法,返回该对象自己的哈希值。

  • 同一个对象多长调用hashCode()方法返回的哈希值是相同的

  • 不同的对象,它们的哈希值一般不相同,但也有可能相同(哈希碰撞)

数据结构:哈希表(哈希函数+数组+链表+红黑树)

  1. 创建HashSet初始一个长度为16的数组table,加载因子默认为0.75

  2. 添加元素,首先用元素的hash值和数组长度取余后得到存储位置,如果位置有数据则调用equals比较两个值是否相等,相等则不存储,不相等直接挂在老元素后面,如果链表长度超过8且数组长度大于64时,将链表转成红黑树,如果红黑树节点少于8的时候红黑树退化成链表。

4.3HashSet去重原理

HashSet存储元素的原理,依赖于两个方法:一个是hashCode方法用来确定在底层数组中存储的位置,另一个是用equals方法判断新添加的元素是否和集合中已有的元素相同。

要想保证在HashSet集合中没有重复元素,我们需要重写元素类的hashCode和equals方法。

4.4 TreeSet集合

reeSet集合的特点是可以对元素进行排序,但是必须指定元素的排序规则。

如何排序?

  • 值为int或Integer等,按照从小到大的顺序排序。

  • 字符串,默认按照第一个字符的对应ASCII的值,相同的则比较第二个,直到比出大小。

  • 对象类型:可以让对象实现Comparable接口,重写compareTo方法;使用TreeSet的有参构造器 参数Compartor

//第一步:先让Student类,实现Comparable接口
//注意:Student类的对象是作为TreeSet集合的元素的
public class Student implements Comparable<Student>{private String name;private int age;private double height;//无参数构造方法public Student(){}//全参数构造方法public Student(String name, int age, double height){this.name=name;this.age=age;this.height=height;}//...get、set、toString()方法自己补上..//第二步:重写compareTo方法//按照年龄进行比较,只需要在方法中让this.age和o.age相减就可以。/*原理:在往TreeSet集合中添加元素时,add方法底层会调用compareTo方法,根据该方法的结果是正数、负数、还是零,决定元素放在后面、前面还是不存。*/@Overridepublic int compareTo(Student o) {//this:表示将要添加进去的Student对象//o: 表示集合中已有的Student对象return this.age-o.age;}
}
//创建TreeSet集合时,传递比较器对象排序
/*
原理:当调用add方法时,底层会先用比较器,根据Comparator的compare方是正数、负数、还是零,决定谁在后,谁在前,谁不存。
*/
//下面代码中是按照学生的年龄升序排序
Set<Student> students = new TreeSet<>(new Comparator<Student>{@Overridepublic int compare(Student o1, Student o2){//需求:按照学生的身高排序return Double.compare(o1,o2); }
});//创建4个Student对象
Student s1 = new Student("至尊宝",20, 169.6);
Student s2 = new Student("紫霞",23, 169.8);
Student s3 = new Student("蜘蛛精",23, 169.6);
Student s4 = new Student("牛魔王",48, 169.6);//添加Studnet对象到集合
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
System.out.println(students); 

4.5 总结Collection集合

4.6 并发修改异常

在使用迭代器遍历集合时,可能存在并发修改异常。

下面是出现问题的代码,问题出在list.remove():

List<String> list = new ArrayList<>();
list.add("王麻子");
list.add("小李子");
list.add("李爱花");
list.add("张全蛋");
list.add("晓李");
list.add("李玉刚");
System.out.println(list); // [王麻子, 小李子, 李爱花, 张全蛋, 晓李, 李玉刚]//需求:找出集合中带"李"字的姓名,并从集合中删除
Iterator<String> it = list.iterator();
while(it.hasNext()){String name = it.next();if(name.contains("李")){list.remove(name);}
}
System.out.println(list);

为什么会出现这个异常呢?那是因为迭代器遍历机制,规定迭代器遍历集合的同时,不允许集合自己去增删元素,否则就会出现这个异常

怎么解决这个问题呢?不使用集合的删除方法,而是使用迭代器的删除方法,代码如下:

List<String> list = new ArrayList<>();
list.add("王麻子");
list.add("小李子");
list.add("李爱花");
list.add("张全蛋");
list.add("晓李");
list.add("李玉刚");
System.out.println(list); // [王麻子, 小李子, 李爱花, 张全蛋, 晓李, 李玉刚]//需求:找出集合中带"李"字的姓名,并从集合中删除
Iterator<String> it = list.iterator();
while(it.hasNext()){String name = it.next();if(name.contains("李")){//list.remove(name);it.remove(); //当前迭代器指向谁,就删除谁}
}
System.out.println(list);

l如果能用for循环遍历时:可以倒着遍历并删除;或者从前往后遍历,但删除元素后做i --操作。

5. Collection的其他操作

5.1 可变参数

  • 可变参数是一种特殊的形式参数,定义在方法、构造器的形参列表处,它可以让方法接收多个同类型的实际参数。**

  • 可变参数在方法内部,本质上是一个数组

具体代码实现如下:

public class ParamTest{public static void main(String[] args){//不传递参数,下面的nums长度则为0, 打印元素是[]test();	//传递3个参数,下面的nums长度为3,打印元素是[10, 20, 30]test(10,20,30); //传递一个数组,下面数组长度为4,打印元素是[10,20,30,40] int[] arr = new int[]{10,20,30,40}test(arr); }public static void test(int...nums){//可变参数在方法内部,本质上是一个数组System.out.println(nums.length);System.out.println(Arrays.toString(nums));System.out.println("----------------");}
}

最后还有一些错误写法,需要让大家写代码时注意一下,不要这么写哦!!!

  • 一个形参列表中,只能有一个可变参数;否则会报错**

  • 一个形参列表中如果多个参数,可变参数需要写在最后;否则会报错

5.2 Collections工具类

这里的Collections是用来操作Collection的工具类。它提供了一些好用的静态方法,如下:

演示方法如下:

public class CollectionsTest{public static void main(String[] args){//1.public static <T> boolean addAll(Collection<? super T> c, T...e)List<String> names = new ArrayList<>();Collections.addAll(names, "张三","王五","李四", "张麻子");System.out.println(names);//2.public static void shuffle(List<?> list):对集合打乱顺序Collections.shuffle(names);System.out.println(names);//3.public static <T> void short(List<T list): 对List集合排序List<Integer> list = new ArrayList<>();list.add(3);list.add(5);list.add(2);Collections.sort(list);System.out.println(list);}
}

上面我们往集合中存储的元素要么是Stirng类型,要么是Integer类型,他们本来就有一种自然顺序所以可以直接排序。但是如果我们往List集合中存储Student对象,这个时候想要对List集合进行排序自定义比较规则的。指定排序规则有两种方式,如下:

排序方式1:让元素实现Comparable接口,重写compareTo方法;然后再使用Collections.sort(list集合)对List集合排序

public class Student implements Comparable<Student>{private String name;private int age;private double height;//排序时:底层会自动调用此方法,this和o表示需要比较的两个对象@Overridepublic int compareTo(Student o){//需求:按照年龄升序排序//如果返回正数:说明左边对象的年龄>右边对象的年龄//如果返回负数:说明左边对象的年龄<右边对象的年龄,//如果返回0:说明左边对象的年龄和右边对象的年龄相同return this.age - o.age;}//...getter、setter、constructor..
}//3.public static <T> void short(List<T list): 对List集合排序
List<Student> students = new ArrayList<>();
students.add(new Student("蜘蛛精",23,169.7));
students.add(new Student("紫霞",22,169.8));
students.add(new Student("紫霞",22,169.8));
students.add(new Student("至尊宝",26,169.5));/*
原理:sort方法底层会遍历students集合中的每一个元素,采用排序算法,将任意两个元素两两比较;每次比较时,会用一个Student对象调用compareTo方法和另一个Student对象进行比较;根据compareTo方法返回的结果是正数、负数,零来决定谁大,谁小,谁相等,重新排序元素的位置注意:这些都是sort方法底层自动完成的,想要完全理解,必须要懂排序算法才行;
*/
Collections.sort(students);	
System.out.println(students);

 **排序方式2:使用调用sort方法是,传递比较器**

/*
原理:sort方法底层会遍历students集合中的每一个元素,采用排序算法,将任意两个元素两两比较;每次比较,会将比较的两个元素传递给Comparator比较器对象的compare方法的两个参数o1和o2,根据compare方法的返回结果是正数,负数,或者0来决定谁大,谁小,谁相等,重新排序元素的位置注意:这些都是sort方法底层自动完成的,不需要我们完全理解,想要理解它必须要懂排序算法才行.
*/
Collections.sort(students, new Comparator<Student>(){@Overridepublic int compare(Student o1, Student o2){return o1.getAge()-o2.getAge();}
});	
System.out.println(students);

后续还会更新map集合,上述所涉及图片均出自b站黑马程序员java进阶课程ppt。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词