(十六)集合框架(Collection和Map)和比较器(Comparable和comparator)
一、集合框架
1.1 为什么要使用集合框架?
当我们需要保持一组一样(类型相同)的元素的时候,我们应该使用一个容器来保存,数组就是这样一个容器。
那么,数组的缺点是什么呢?
数组一旦定义,长度将不能再变化。
然而在我们的开发实践中,经常需要保存一些变长的数据集合,于是,我们需要一些能够动态增长长度的容器来保存我们的数据。
而我们需要对数据的保存的逻辑可能各种各样,于是就有了各种各样的数据结构。我们将数据结构在Java中实现,于是就有了我们的集合框架。
1.2 集合框架的内容
注意: Collction是接口,而Collections是具体类,里面封装着大量操作方法。(紫色部分是接口,黄色部分是具体类)
1.3 注意
- foreach遍历只能用于colletion接口下的(即list和set)和数组,map是不能用foreach遍历的。
- 如果是无序的集合比如set接口下的类,因为无序,所以就不能根据索引号来获取值,比如有序List.get(0)来获取存在List里的第一个值。
- 如果我们往集合里(List或set等)添加的是自定义对象,比如我们往TreeSet里添加一个学生类的引用,这个学生类有name、age两个属性,如果我们想对name进行排序 比如姓王的排在前面,那么我们需要设置比较器Comparable或compartor,否则会报错,因为如果没有设置比较器,那么会对引用进行比较。
1.4 ArrayList类
- 对于ArrayList遍历的几种方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | //利用size()和get()方法对arraylist进行遍历 List<String> li= new ArrayList<String>(); li.add( "abc" ); li.add( "efg" ); li.add( "hij" ); li.add( "klm" ); for ( int i= 0 ;i<li.size();i++) { System.out.println(li.get(i)); } //用foreach遍历 for (String str:li) { System.out.println(str); } //用迭代器遍历Iterator Iterator<String> i=li.iterator(); while (i.hasNext()) { //执行一次next()就会指向下一个元素,所以这里输出的是efg的下一个元素 if ((i.next()).equals( "efg" )) { System.out.println(i.next()); continue ; } else { System.out.println( "不满足条件" ); continue ; } } |
- 注意: 如果要对arraylist进行元素删除操作即(Iterator.remove()),那么只能用迭代器来进行,其他方法不行。
1.5 HashSet
- set集合是唯一无序的,也就是说里面的对象不能相同,存储位置也是无序的,其实说是无序只是相对于添加顺序来说,在内存中的存储位置是按照hash算法来存放的,只是这个算法很难算得出存放的位置。不能使用Comparator比较器。
1 2 3 4 5 6 7 8 9 10 11 | public static void main(String[] args) { Set<String> se= new HashSet<String>(); se.add( "111" ); se.add( "aaa" ); se.add( "1sr" ); //Iterator迭代 Iterator<String> i=se.iterator(); while (i.hasNext()) { System.out.println(i.next()); }} |
1.6 TreeSet
- TreeSet可以给Set集合中的元素进行指定方式的排序(即可以使用comparator和comparable)。
1 2 3 4 5 6 7 8 9 | public static void main(String[] args) { Set<String> se= new TreeSet<String>(); se.add( "222" ); se.add( "bbb" ); se.add( "aaa" ); se.add( "111" ); System.out.println(se); } |
- 如果往TreeSet添加的是基本数据类型或者String等,那么TreeSet会自动给这些值进行排序。如果添加的是自定义类,那么必须对TreeSet设置排序规则.即我们需要在这个自定义类里继承比较器接口Comparable和Compartor,然后覆盖里面的方法;
Student.java
1 2 3 4 5 | public class Student { private String name; private int age; //setget方法、构造方法省略 } |
TreeSetApp.java
1 2 3 4 5 | public static void main(String[] args) { Set<Student> se= new TreeSet<Student>(); Student s= new Student( "张三" , 15 ); se.add(s); System.out.println(se);} |
- 注意: ArrayList和HashSet和TreeSet中,只有TreeSet和ArrayList的可以实现compartor比较器,TreeSet可以通过构造方法指定compartor比较器,而ArrayList可以通过Colletions.sort(List list, Compartor c)来指定使用compartor比较器。
1.7 HashMap
- 它是基于哈希表的 Map 接口的实现,以key-value的形式存在。在HashMap中,key-value总是会当做一个整体来处理,系统会根据hash算法来来计算key-value的存储位置,我们总是可以通过key快速地存、取value。
1 2 3 4 5 6 7 8 | public static void main(String[] args) { Map<String,String> m= new HashMap<String,String>(); m.put( "CN" , "中国" ); m.put( "JP" , "日本" ); for (String str:m.keySet()){ System.out.println(str+ "=" +m.get(str)); } } |
解析: 对HashMap进行遍历,不能直接用for(String str:m) 来遍历 因为Map接口没有迭代器Iterator ,只能调用hashmap的里的keySet()方法,这个方法返回一个Set集合,而Colletion接口下的类有迭代器,可以使用foreach()。
二、比较器
- 比较器: comparable 和comparator
student.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class Student implements Comparable<Student>{ private String name; private int age; //省略getset以及构造方法 public int compareTo(Student o) { if ( this .age>o.getAge()){ return 1 ; } else if ( this .age<o.getAge()){ return - 1 ; } else { return 0 ; } }} |
ListApp.java
1 2 3 4 5 6 7 8 9 10 11 12 | public static void main(String[] args) { List<Student> li= new ArrayList<Student>(); Student s1= new Student( "张三" , 15 ); Student s2= new Student( "李四" , 50 ); Student s3= new Student( "王五" , 25 ); li.add(s1); li.add(s2); li.add(s3); for (Student s:li){ System.out.println(s.getAge()); } } |
结果:
解析:由结果可知,comparable的比较方法是第一个s1被添加进li中,当s2被添加到li后,把s1的age跟s2的age比,可知s1<s2,所以返回-1,排列结果为:15,50 。 当s3被添加到li后,把s1的age跟s3的age比,可知s1<s3,所以返回-1,排列结果为: 15,50,25.
student.java
1 2 3 4 5 | public class Student { private String name; private int age; //省略getset以及包含全属性的构造方法 } |
ListApp.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public static void main(String[] args) { List<Student> li= new ArrayList<Student>(); Student s1= new Student( "张三" , 15 ); Student s2= new Student( "李四" , 50 ); Student s3= new Student( "王五" , 25 ); li.add(s1); li.add(s2); li.add(s3); Collections.sort(li, new MyComparator()); for (Student s:li){ System.out.println(s.getAge()); } } |
MyComparator.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class MyComparator implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { if (o1.getAge()>o2.getAge()) { return 1 ; } else if (o1.getAge()==o2.getAge()) { return 0 ; } else return - 1 ; } } |
实现升序方法。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~