ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 集合排序 [TOC] ## 导学 在之前的集合课程中都没有涉及到集合的排序问题,本节课中,我们将来学习集合排序的问题。 那么,集合如何进行排序呢?首先我们要回忆一下数组是如何进行排序的: ~~~ int[] arr = new int{1,8,91,3,7,6,2,9}; Arrays.sort(arr);//数组排序 ~~~ 其实集合排序也会使用到`sort(List<T> list)`方法。只是这个`sort(List<T> list)`方法,存在于`Collections`类中。 >[danger]注意`Collections`类和`Collection`接口 因为在集合中,`List`集合才是有序的。所以,集合排序通常是针对`List`集合而言。 小结: - 使用`Collections`类中` sort(List<T> list)`方法对List集合进行排序 - ` sort(List<T> list)`方法根据元素的自然顺序对指定列表按升序进行排序,比如字符串或者字符数据按照Ascall码值进行排序 ## 对基本数据类型和字符串类型进行排序 ### 对整型排序 ~~~ import java.util.ArrayList; import java.util.Collections; import java.util.List; public class IntSort { public static void main(String[] args) { // 对存储在List中的整型数据进行排序 List<Integer> list=new ArrayList<Integer>(); list.add(5); list.add(9); list.add(3); list.add(1); System.out.println("排序前:"); for(int n:list){ System.out.print(n+" "); } System.out.println(); //对List中的数据进行排序 Collections.sort(list); System.out.println("排序后:"); for(int n:list){ System.out.print(n+" "); } } } ~~~ 小结: 1. 泛型中的数据类型不能使用基本数据类型要使用包装类,因为`List`不同与数组,参数是`Object`类型,都是对象,所以泛型的时候要用包装类。不能使用`int`,应该使用`List<Integer>list = new ArrayList<Integer>()`; 2. 集合中使用了泛型统一,则输出时候可以用for-each循环 3. 使用Collections.sort(list);方法对集合中的内容进行升序排序; ### 对字符串排序 ~~~ import java.util.ArrayList; import java.util.Collections; import java.util.List; public class StringSort { public static void main(String[] args) { // 对存放在List中的字符串进行排序 List<String> list=new ArrayList<String>(); list.add("orange"); list.add("blue"); list.add("yellow"); list.add("gray"); System.out.println("排序前:"); for(String s:list){ System.out.print(s+" "); } System.out.println(); Collections.sort(list); System.out.println("排序后:"); for(String s:list){ System.out.print(s+" "); } } } ~~~ 小结:字符串是按照其首字母对应的ASCII码值进行排序的。 ## Comparator接口 `Comparator`接口 * 强行对某个对象进行整体排序的比较函数。 * 可以将`Comparator`接口作为参数,传递给sort方法(如`Collections.sort`或`Arrays.sort`) * 在`Comparator`接口存在`int compare(T o1, T o2)`方法,比较用来排序的两个参数 - 对于其返回值,如果o1<o2,返回整数、如果o1=o2,返回0、如果o1>o2,返回正整数 * `Comparator`接口中还存在`boolean equals(Object obj)`方法,指示某个其他对象是否“等于”此Comparator,此方法可以被Object类中的equals方法覆盖,不必重写。 ### 案例:宠物猫排序 ~~~ public class Cat { private String name; //名字 private int month; //年龄 private String species;//品种 //构造方法 public Cat(String name, int month, String species) { super(); this.name = name; this.month = month; this.species = species; } //getter与setter方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } @Override public String toString() { return "[名字:" + name + ", 年龄:" + month + ", 品种:" + species + "]"; } } ~~~ ~~~ import java.util.Comparator; public class AgeComparator implements Comparator<Cat>{ @Override public int compare(Cat o1, Cat o2) { // 按年龄降序排序 int age1=o1.getMonth(); int age2=o2.getMonth(); return age2-age1; } } ~~~ ~~~ import java.util.Comparator; public class NameComparator implements Comparator<Cat> { @Override public int compare(Cat o1, Cat o2) { // 按名字升序排序 String name1=o1.getName(); String name2=o2.getName(); int n=name1.compareTo(name2); return n; } } ~~~ ~~~ import java.util.ArrayList; import java.util.Collections; import java.util.List; public class CatTest { public static void main(String[] args) { // 按名字升序排序 Cat huahua=new Cat("huahua",5,"英国短毛猫"); Cat fanfan=new Cat("fanfan",2,"中华田园猫"); Cat maomao=new Cat("maomao",3,"中华田园猫"); List<Cat> catList=new ArrayList<Cat>(); catList.add(huahua); catList.add(fanfan); catList.add(maomao); //排序前 System.out.println("排序前:"); for(Cat cat:catList){ System.out.println(cat); } //按名字进行升序排序 Collections.sort(catList, new NameComparator()); System.out.println("按名字升序排序后:"); for(Cat cat:catList){ System.out.println(cat); } //按年龄进行降序排序 Collections.sort(catList, new AgeComparator()); System.out.println("按年龄降序排序后:"); for(Cat cat:catList){ System.out.println(cat); } } } ~~~ ## Comparable接口 **Comparable接口** * 此接口强行对实现它的每个类别的对象进行整体排序; * 这种排序被称为类的自然比较方法; * int compareTo(T o)方法——比较的其实是当前对象和参数对象,该对象(实现Comparable接口的对象)小于,等于或大于指定对象(compareTo方法中的参数对象)则分别返回负整数,零或正整数。 ### 案例:商品排序 ~~~ public class Goods implements Comparable<Goods> { private String id;//商品编号 private String name;//商品名称 private double price;//商品价格 //构造方法 public Goods(String id,String name,double price){ this.id=id; this.name=name; this.price=price; } //getter和setter方法 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public String toString(){ return "商品编号:"+id+",商品名称:"+name+",商品价格:"+price; } @Override public int compareTo(Goods o) { // 取出商品价格 double price1=this.getPrice(); double price2=o.getPrice(); int n=new Double(price2-price1).intValue(); return n; } } ~~~ ~~~ import java.util.ArrayList; import java.util.Collections; import java.util.List; public class GoodsTest { public static void main(String[] args) { Goods g1 = new Goods("s00001", "手机", 2000); Goods g2 = new Goods("s00002", "冰箱", 5000); Goods g3 = new Goods("s00003", "电视机", 3000); List<Goods> goodsList = new ArrayList<Goods>(); goodsList.add(g1); goodsList.add(g2); goodsList.add(g3); // 排序前 System.out.println("排序前:"); for (Goods goods : goodsList) { System.out.println(goods); } Collections.sort(goodsList); // 排序后 System.out.println("排序后:"); for (Goods goods : goodsList) { System.out.println(goods); } } } ~~~ ## 排序接口区别 **区别:** 1. 实现了`java.lang.Comparable`的对象直接就可以成为一个可以比较的对象,不过得在类中进行方法定义; 2. `java.util.Comparator`在对象外比较,不修改实体类; 3. 实现了`Comparable`的意思是我可以把自己和另一个对象进行比较;而实现了`Comparator`的意思是我可以比较其他两个对象;也就是说`Comparable`是一个可比较的对象可以将自己与另一个对象进行比较;而`Comparator`是比较两个不同的对象。 4. 使用`Comparable`需要修改原先的实体类,是属于一种自然排序。而`Comparator`则不用修改原先类。即使修改了`Comparable`实体类,`Comparable`也仅有一种比较规则。而`Comparator`可以实现多个,来提供多个比较规则。 **使用场景:** 一般情况下如果对某个类进行排序,比如`Cat`类,如果使用`Comparable`接口的方式,那么`Cat`类需要实现`Comparable`接口。如果`Cat`类通过`Comparable`接口的方式实现排序,比如通过name排序了。那么我们还希望通过age进行排序,这时不希望修改`Cat`类,那此时就需要使用`Comparator`接口了 因此,`Comparable`接口可以作为实现类的默认排序算法,`Comparator`接口则用于一个类的扩展排序 ## 练习 一、选择 1. 在下面代码中的(1)(2)处可以填写(多选) ![](https://img.kancloud.cn/d0/30/d030e8be25e1fc2ece81a7f874a54f83_443x62.png) ~~~ A. int int B. Integer  Integer C. String  String D. string  string ~~~ 2. 下列说法中不正确的是: ~~~ A. Comparator接口用于对自定义类进行整体排序 B. Comparator接口可以将Comparator传递给sort方法 C. int compare(T o1,T o2)比较用来排序的两个对象 D. boolean equals(Object obj)指示对象obj是否是“等于”当前对象。此方法不可以被Object类中的equals方法覆盖 ~~~ 3. 关于Comparable接口的说法,以下哪个是错误的? ~~~ A. Comparable位于java.lang包 B. 调用sort方法时,需要指定Comparable接口的实现类 C. Comparable接口的抽象方法是 int compareTo(T t) D. Comparable接口还可以用于数组的排序 ~~~ 二、编程 1. 对英文单词进行排序,效果图如下: ![](https://img.kancloud.cn/a3/dc/a3dcc4afe3d778c07fadca1cf563023a_536x114.png) **任务** 1、给list添加元素 2、输出排序前list中的内容 3、对list中的元素进行排序 4、输出排序后list中的内容 ~~~ import java.util.ArrayList; import java.util.Collections; import java.util.List; public class StringSort { public static void main(String[] args) { //给list添加元素 //输出排序前list中的内容 //对list中的元素进行排序 //输出排序后list中的内容 } } ~~~ 2. 定义一个学生信息类,包括学号,姓名,年龄三个成员变量,然后按名字进行升序排序。(使用Comparator接口) **运行效果图:** ![](https://img.kancloud.cn/4b/69/4b69d1638b8edf42546da6731267c13c_361x210.png) **任务:** ![](https://img.kancloud.cn/c1/98/c1983b561e075a2a2032ee52d5c0fe06_332x246.png) 3. 定义一个员工信息类,包括编号,姓名,工资三个成员变量,要求工资定义为float类型,然后按工资进行降序排序。(使用Comparable接口) **运行效果图:** ![](https://img.kancloud.cn/92/ec/92ec441e49c96dd274adc4baf65cfd79_465x221.png) **任务:** ![](https://img.kancloud.cn/e5/ea/e5eac1d64b08a0788a72794cf00ae99a_670x176.png)