上节文章遇到了一个问题:student类没有实现Comparable接口,不是compare()方法的实现类。
所以在执行Collection.Sort()时找不到compare()方法,导致程序报错。
一、知识点
(1)错误的代码示例
student类没有实现Comparable方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public void testsort4(){ List<student> studentlist = new ArrayList<student>(); studentlist.add(new student(1+"", "船长铭")); studentlist.add(new student(2+"", "uml铭")); studentlist.add(new student(3+"", "旋转铭")); System.out.println("---------------排序前------------------"); for (student student : studentlist) { System.out.println("学生:"+student.name); } // 为什么会报错? // 要用comparable接口实现方法 // student类型并不是compare方法的实现类,是无法对类进行sort()排序的。 Collections.sort(studentlist); } |
执行时报出找不到方法的错误。
(2)compare的必要性
编译器排序的时候,依据的是自然顺序,排序的依据已经是定死了的。
举个例子:一群学生排队,默认按照身高来排,从矮到高站成一堆。现在我们想按照学生的年龄去排序,该怎么实现呢?
在java中,两个对象想要进行排序,那么两者必须是可以比较的。我们用Comparable来表示这两个对象是可以比较的。
Comparable实现了默认比较规则,就像是之前的身高排序。如果我们想用到年龄排序,就要覆盖默认排序方法,实现临时的排序规则。
(3)comparable接口是什么?如何使用?
需要对一个对象进行排序时,就应该实现Comparable接口,并且实现其唯一的方法compareTo()。
当调用Arrays.sort()方法时会回调compareTo()方法,获取排序规则。
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
package test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Scanner;; public class testset { public List<course> coursestoselect = null; private Scanner console = null; public student stu = null; public testset() { coursestoselect = new ArrayList<course>(); console = new Scanner(System.in); } public void testadd() { // 用于往coursestoselect中添加备选课程 // 创建一个课程对象,并通过add方法添加到备选课程List中 course cr1 = new course("1", "数据结构"); coursestoselect.add(cr1); course temp = (course) coursestoselect.get(0); System.out.println("添加了课程:"+temp.id+":"+temp.name); course cr2 = new course("2", "java"); coursestoselect.add(1, cr2); course temp2 = (course) coursestoselect.get(1); System.out.println("添加了课程:"+temp2.id+":"+temp2.name); // 以下方法会抛出数组越界异常 // course cr3 = new course("3", "testfuck"); // coursestoselect.add(3,cr3); course[] course = {new course("3", "离散数学"),new course("4", "汇编语言")}; coursestoselect.addAll(Arrays.asList(course)); course temp3 = (test集合.course) coursestoselect.get(2); course temp4 = (test集合.course) coursestoselect.get(3); System.out.println("添加了两门课程:"+temp3.id+":"+temp3.name +";"+temp4.id+":"+temp4.name); course[] course1 = {new course("5", "高等数学"),new course("6", "大学英语")}; coursestoselect.addAll(Arrays.asList(course1)); course temp5 = (test集合.course) coursestoselect.get(4); course temp6 = (test集合.course) coursestoselect.get(5); System.out.println("添加了两门课程:"+temp5.id+":"+temp5.name +";"+temp6.id+":"+temp6.name); } // 通过for each遍历 public void testforeach() { // 定义一个Object类型的变量,coursestoselect是要遍历的集合 // 去遍历集合中的每一个元素,把它取出来,作为Object的一个变量 System.out.println("有如下课程待选(通过for each方法):"); for(Object obj:coursestoselect) { course cr = (course) obj; System.out.println("课程:"+cr.id+":"+cr.name); } } // 循环遍历 public void testforeach2() { for(course c:coursestoselect) { System.out.println("课程:"+c.id+":"+c.name); } } public void testforeachfortest(student stu) { // 打印输出学生所选的课程 System.out.println("一共选择了:"+student.courses.size()+"门课程。"); for(course cr:student.courses) { System.out.println("选择了课程:"+cr.id+":"+cr.name); } } public void show() { System.out.println(coursestoselect); } // 测试list的contains方法 public void testlistcontains() { // 取得备选课程序列的第0个元素 course co = coursestoselect.get(0); // 打印输出coursestoselect是否含有包含course对象 System.out.println("取得课程:"+co.name); System.out.println("备选课程中是否包含课程:"+co.name+","+ coursestoselect.contains(co)); // 创建一个新的课程对象,id和名称,与co对象完全一样 // 需要重写equals方法 // 提示输入课程名称 System.out.println("请输入课程名称:"); String name = console.next(); course co2 = new course(); co2.name = name; // course co2 = new course(co.id,co.name); System.out.println("新创建课程:"+co2.name); System.out.println("备选课程中是否包含课程:"+co2.name+","+ coursestoselect.contains(co2)); // indexof方法获取元素索引位置 if(coursestoselect.contains(co2)) { System.out.println("课程:"+co2.name+"的索引位置为:"+ coursestoselect.indexOf(co2)); } } // 这个方法失败了 // public void testcontainsall() { // course s4 = coursestoselect.get(4); // course s5 = coursestoselect.get(5); // System.out.println("取得课程:"+s4.name+" "+s5.name); // course[] a = {new course("5", "高等数学"),new course("6", "大学英语")}; // System.out.println("备选课程中是否包含课程:"+s4.name+","+s5.name+" "+ // coursestoselect.containsAll(a)); // } // 创建学生对象并且选课 public void create() { stu = new student("1", "菊花宝"); System.out.println("欢迎"+stu.id+"号学生: "+stu.name+" 同学选课!"); // 创建一个scanner对象用于接受从键盘输入的id Scanner console = new Scanner(System.in); for (int i = 0; i < 3; i++) { System.out.println("请输入课程的id:"); String courseid = console.next(); // 注意这里的格式变换,为什么要用String? // 因为之前的cr.id是course类型里的id是string类型,所以要用equals方法 for(course cr:coursestoselect) { if (cr.id.equals(courseid)) { student.courses.add(cr); student.courses.add(cr); // 这里明明怼进去了两次,本来应该是6个course类型数据才对啊? // 就是为了测试不可重复性 // set中元素无序不可按具体位置查找,也不能重复 // 但是list中就不同了,不但可以按具体位置查找,还可以重复哦 } } } } public void testsetcontains() { // 提示输入课程名称 System.out.println("请输入学生已选的课程名称:"); String name = console.next(); course co2 = new course(); co2.name = name; System.out.println("新创建课程:"+co2.name); System.out.println("备选课程中是否包含课程:"+co2.name+","+ student.courses.contains(co2)); } public static void main(String[] args) { testset t = new testset(); t.testadd(); t.testlistcontains(); t.testforeach(); // t.create(); // t.testsetcontains(); // t.testcontainsall(); // System.out.println("////////////////////////////"); // t.testforeach2(); // t.testforeachfortest(stu); // t.show(); } } |
下面解决一些问题:
1.如何生成3个不重复的1000以内的随机正整数作为学生ID?
可以这样生成:
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 |
public void testSort4(){ List<Student> studentList=new ArrayList<Student>(); List<Integer> randomList=new ArrayList<Integer>(); Random random=new Random(); int k; for(int i=0;i<3;i++){ do{ k=random.nextInt(1000); }while(randomList.contains(k)); randomList.add(k); } studentList.add(new Student(randomList.get(0)+"","luci")); studentList.add(new Student(randomList.get(1)+"","nibi")); studentList.add(new Student(randomList.get(2)+"","good")); System.out.println("*****排序前******"); for(Student stu:studentList){ System.out.println("学生"+stu.name ); } System.out.println("*****排序后*********"); Collections.sort(studentList); for(Student stu:studentList){ System.out.println("学生"+stu.name+" "+stu.id); } //用new StudentComparator()来接收return的值。 Collections.sort(studentList,new StudentComparator()); System.out.println("****根据姓名排序*******"); for(Student stu:studentList){ System.out.println("根据姓名:"+stu.id+" "+stu.name); } } |
完善代码:
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
package test集合; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; public class testcollection { /** * 将要完成 * 1.通过collections.sort()方法,对integer泛型的List进行排序 * 2.对string泛型的List进行排序 * 3.对其他类型泛型的List进行排序,以Student为例 */ /** * 创建一个integer泛型的List,插入十个100以内的不重复的随机整数 调用collections.sort()方法对齐进行排序 */ public void testsort1() { List<Integer> integerList = new ArrayList<Integer>(); // 插入随机数 Random ram = new Random(); Integer k; for (int i = 0; i < 10; i++) { do { k = ram.nextInt(100); } while (integerList.contains(k)); integerList.add(k); System.out.println("成功添加整数" + k); } System.out.println("-----------------排序前------------------"); for (Integer a: integerList) { System.out.println("元素为:" + a); } Collections.sort(integerList); System.out.println("-----------------排序后------------------"); for (Integer b : integerList) { System.out.println("元素为:" + b); } } /** * 2.对string类型的List进行排序 创建string泛型的List,添加三个乱序的string元素 调用sort方法,再次进行排序然后输出 */ public void testsort2() { List<String> stringlist = new ArrayList<String>(); stringlist.add("xinyixin"); stringlist.add("laopo"); stringlist.add("love"); System.out.println("-------------排序前---------------"); for (String string : stringlist) { System.out.println("元素:" + string); } Collections.sort(stringlist); System.out.println("-------------排序后---------------"); for (String string : stringlist) { System.out.println("元素:" + string); } } public void testsort3() { List<String> list3 = new ArrayList<String>();// 储存所有字符串 Set<String> setString = new HashSet<String>();// 用于选择不同的字符串 String newst = new String(); // 储存当前得到的字符串 Random rand = new Random(); // 产生10以内随机数。用于字符串控制长度 StringBuffer sb = new StringBuffer(); // 可以变动的字符型 StringBuffer buf = new StringBuffer("abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"); // 字符组合的基 int m = 0; // m控制字符串的数量 while (m < 10) { do { // 字符串长度在10以内。达到该长度前进行for循环 for (int i = 0; i < rand.nextInt(10); i++) { // 定义一个变量,取得buf字符组合基的长度 int num = buf.length(); // 往空的字符串 sb 的末端加入单个元素。该元素从buf组合基中随机取得 sb.append(buf.charAt(rand.nextInt(num))); } // do结束 // 将sb可变动类型转换成字符串型 newst = sb.toString(); // 若setString中已包含该对象,重新进行do操作 } while (setString.contains(newst)); // 往Set接口下的setString中添加该对象 setString.add(newst); // 往List接口下的list3中添加该字符串 list3.add(newst); System.out.println("成功添加:" + newst); // 可变更类型的 sb 字符串 清空,用于下一次操作 sb = new StringBuffer(); m++; } System.out.println("----------------------排序前---------------------"); for (String in : list3) { System.out.println("元素:" + in); } System.out.println("----------------------排序后---------------------"); Collections.sort(list3); for (String in : list3) { System.out.println("元素:" + in); } } public void testsort4() { List<student>studentlist = new ArrayList<student>(); List<Integer>list = new ArrayList<Integer>(); Random random = new Random(); int k; for (int i = 0; i < 3; i++) { // do/while 循环是 while 循环的变体。在检查条件是否为真之前,该循环首先会执行一次代码块,然后检查条件是否为真, // 如果条件为真的话,就会重复这个循环。适合用于在循环次数未知的情况下判断是否达到条件并打印最后一位数. do { k=random.nextInt(100); } while (list.contains(k)); list.add(k); } // 可以改进,生成3个不重复的1000以内的随机数作为学生id studentlist.add(new student(list.get(0)+"", "船长铭")); studentlist.add(new student(list.get(1)+"", "uml铭")); studentlist.add(new student(list.get(2)+"", "旋转铭")); studentlist.add(new student(10000+"", "石头铭")); System.out.println("---------------排序前------------------"); for (student st : studentlist) { System.out.println("学生id:"+st.id+" "+st.name); } // 威慑么会报错? // 要用comparaable接口实现方法 // 我们的student类型并不是compare方法的实现类,所以不进行处理compare是无法对类进行sort()排序的。 // student类并没有实现comparable接口,所以需要改造student类 // 这里其实是按字符串的开头字符顺序来排列的,先数字后字母,10000是1,a1是a,Azz3是A,以此类推 Collections.sort(studentlist); System.out.println("---------------排序后------------------"); for (student st : studentlist) { System.out.println("学生id:"+st.id+" "+st.name); } Collections.sort(studentlist,new studentcompare()); System.out.println("---------------姓名排序后------------------"); for (student st : studentlist) { System.out.println("学生id:"+st.id+" "+st.name); } } public static void main(String[] args) { testcollection ct = new testcollection(); // ct.testsort1(); // ct.testsort2(); ct.testsort4(); } } |
比较简单的实现。
2.(“1”, “小明”)和(1+””,”小明”)有区别吗?
从代码角度看,没什么太大区别,写法不同而已。编译器也会将1 + “”视为1与一个空字符串相连接,将其转换为String类型,实现和”1″一样的效果。
二、总结
如果一个对象需要自比较,就需要实现Comparable接口。String、Integer自己就实现了Comparable接口,可完成比较大小操作。
如果想在list容器中排序自定义类,需要让这个自定义类实现Comparable接口。
如果Collections类的sort方法在排序时不指定Comparator,那就以自然顺序排序。所谓自然顺序就是实现Comparable接口设定的排序方式,也可以自定义排序方法。