------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
10、声明类Student,包含3个成员变量:name、age、score,创建5个对象装入TreeSet, 按照成绩排序输出结果(考虑成绩相同的问题)。
看到这个题目,自然而然很简单的 想到就是创建类并包含三个成员变量,加入TreeSet很简单,就开始写代码,下面是代码和运行结果。
import java.util.Iterator;
import java.util.TreeSet;
public class Test10 {
/**
* 10、声明类Student,包含3个成员变量:name、age、score,创建5个对象装入TreeSet,
* 按照成绩排序输出结果(考虑成绩相同的问题)。
*
* 思路:TreeSet要指定自然顺序并且不能重复,自定义的Student没有自然顺序所以要
* 实现Comparable接口对student进行,自然方法排序的增加,
* 如果不实现此接口将student对象加入数组就会报 com.itheima.
* Student cannot be cast to java.lang.Comparable异常
*/
public static void main(String[] args) {
//声明创建TreeSet集合泛型为Student
TreeSet<Student> set = new TreeSet<Student>();
//声明创建五个student并加入set集合
Student stu1 = new Student("小明", 23, 98.5);
Student stu2 = new Student("小红", 24, 45.6);
Student stu3 = new Student("小强", 25, 84.2);
Student stu4 = new Student("小刚", 26, 84.2);
Student stu5 = new Student("小松", 23, 98);
set.add(stu1);
set.add(stu2);
set.add(stu3);
set.add(stu4);
set.add(stu5);
System.out.println("set大小:" + set.size());
//调用所定义的对set集合的输出函数
Myout(set);
}
public static void Myout(TreeSet<Student> set) {
//迭代set集合
Iterator<Student> it = set.iterator();
//取出迭代器中的元素
while (it.hasNext()) {
Student stu = (Student) it.next();
System.out.println(stu.toString());
}
}
}
/*
* 定义Student类,并继承Comparable并实现compareto()方法
* 在此我直接将泛型加入,省去compareto()中的强转
*
*/
class Student {
private String name;
private int age;
private double score;
public Student() {
}
//增加带参数构造器方便添加数据
public Student(String name, int age, double score) {
super();
this.name = name;
this.age = age;
this.score = score;
}
//增加get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
//覆盖toString()方法方便调试和显示
@Override
public String toString() {
return "Student [age=" + age + ", name=" + name + ", score=" + score
+ "]";
}
}点击运行,结果出乎意料:上图考虑TreeSet,TreeSet是基于TreeMap实现的,TreeSet是有序的,要求其中存的元素要是实现Comparable接口,或者是在使用TreeSet时使用(TreeSet(Comparator<? superE> comparator)构造一个新的空 TreeSet,它根据指定比较器进行排序。)该构造器对TreeSet传入一个比较器。这就需要程序员手动实现Comparactor接口了。下面先说Comparable接口:
public interfaceComparable<T>
此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。
实现此接口的对象列表(和数组)可以通过 Collections.sort(和Arrays.sort)进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
这段话的意思就是,自己编写的类要实现排序的功能就必须重写CompareTo方法定义自定义对象的自然比较方法,然会就能对其排序。
要重写compareTo方法:
compareTo
int compareTo(T o)
- 比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
实现类必须确保对于所有的x和y都存在sgn(x.compareTo(y)) == -sgn(y.compareTo(x))的关系。(这意味着如果y.compareTo(x)抛出一个异常,则x.compareTo(y)也要抛出一个异常。)
实现类还必须确保关系是可传递的:(x.compareTo(y)>0 && y.compareTo(z)>0)意味着x.compareTo(z)>0。
最后,实现者必须确保x.compareTo(y)==0意味着对于所有的z,都存在sgn(x.compareTo(z)) == sgn(y.compareTo(z))。 强烈推荐(x.compareTo(y)==0) == (x.equals(y))这种做法,但并不是 严格要求这样做。一般来说,任何实现Comparable接口和违背此条件的类都应该清楚地指出这一事实。推荐如此阐述:“注意:此类具有与 equals 不一致的自然排序。”
在前面的描述中,符号sgn(expression)指定 signum 数学函数,该函数根据expression 的值是负数、零还是正数,分别返回-1、0或1中的一个值。
- 参数:
o- 要比较的对象。 返回:- 负整数、零或正整数,根据此对象是小于、等于还是大于指定对象。 抛出:
ClassCastException- 如果指定对象的类型不允许它与此对象进行比较。
package com.itheima;
import java.util.Iterator;
import java.util.TreeSet;
public class Test10 {
/**
* 10、声明类Student,包含3个成员变量:name、age、score,创建5个对象装入TreeSet,
* 按照成绩排序输出结果(考虑成绩相同的问题)。
*
* 思路:TreeSet要指定自然顺序并且不能重复,自定义的Student没有自然顺序所以要
* 实现Comparable接口对student进行,自然方法排序的增加,
* 如果不实现此接口将student对象加入数组就会报 com.itheima.
* Student cannot be cast to java.lang.Comparable异常
*/
public static void main(String[] args) {
//声明创建TreeSet集合泛型为Student
TreeSet<Student> set = new TreeSet<Student>();
//声明创建五个student并加入set集合
Student stu1 = new Student("小明", 23, 98.5);
Student stu2 = new Student("小红", 24, 45.6);
Student stu3 = new Student("小强", 25, 84.2);
Student stu4 = new Student("小刚", 26, 84.2);
Student stu5 = new Student("小松", 23, 98);
set.add(stu1);
set.add(stu2);
set.add(stu3);
set.add(stu4);
set.add(stu5);
System.out.println("set大小:" + set.size());
//调用所定义的对set集合的输出函数
Myout(set);
}
public static void Myout(TreeSet<Student> set) {
//迭代set集合
Iterator<Student> it = set.iterator();
//取出迭代器中的元素
while (it.hasNext()) {
Student stu = (Student) it.next();
System.out.println(stu.toString());
}
}
}
/*
* 定义Student类,并继承Comparable并实现compareto()方法
* 在此我直接将泛型加入,省去compareto()中的强转
*
*/
class Student implements Comparable<Student>{
private String name;
private int age;
private double score;
public Student() {
}
//增加带参数构造器方便添加数据
public Student(String name, int age, double score) {
super();
this.name = name;
this.age = age;
this.score = score;
}
//增加get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
//覆盖compareTo()方法,定义出自己所需的情况
@Override
public int compareTo(Student o) {
Student stu = o;
//下面几个if else 语句实现了先通过分数进行排序和年龄进行排序
//如果两者都相同则通过姓名进行排序。
//返回的-1、1和0也可以是其它的证书或者负数
if (this.score < stu.score)
return (int) -1;
else if (this.score > stu.score)
return 1;
else if (this.age > stu.age)
return 1;
else if (this.age < stu.age)
return -1;
else if (this.score == stu.score && this.age == stu.age)
//分数年龄相同则返回姓名的字典顺序差。
return this.name.compareTo(stu.name);
return 0;
}
//覆盖toString()方法方便调试和显示
@Override
public String toString() {
return "Student [age=" + age + ", name=" + name + ", score=" + score
+ "]";
}
}上面已经描述了,要对TreeSet中的元素进行排序,需要对象具备自然顺序,要么就是使用TreeSet时候指定构造器,下面就展示通过实现Comparator 接口实现的方式
package com.itheima;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class Test10 {
/**
* 10、声明类Student,包含3个成员变量:name、age、score,创建5个对象装入TreeSet,
* 按照成绩排序输出结果(考虑成绩相同的问题)。
*
* 思路:TreeSet要指定自然顺序并且不能重复,自定义的Student没有自然顺序所以要
* 实现Comparable接口对student进行,自然方法排序的增加,
* 如果不实现此接口将student对象加入数组就会报 com.itheima.
* Student cannot be cast to java.lang.Comparable异常
*/
public static void main(String[] args) {
//声明创建TreeSet集合泛型为Student
TreeSet<Student> set = new TreeSet<Student>(new myStudentComparactor());
//声明创建五个student并加入set集合
Student stu1 = new Student("小明", 23, 98.5);
Student stu2 = new Student("小红", 24, 45.6);
Student stu3 = new Student("小强", 25, 84.2);
Student stu4 = new Student("小刚", 26, 84.2);
Student stu5 = new Student("小松", 23, 98);
set.add(stu1);
set.add(stu2);
set.add(stu3);
set.add(stu4);
set.add(stu5);
System.out.println("set大小:" + set.size());
//调用所定义的对set集合的输出函数
Myout(set);
}
public static void Myout(TreeSet<Student> set) {
//迭代set集合
Iterator<Student> it = set.iterator();
//取出迭代器中的元素
while (it.hasNext()) {
Student stu = (Student) it.next();
System.out.println(stu.toString());
}
}
}
class Student {
private String name;
private int age;
private double score;
public Student() {
}
//增加带参数构造器方便添加数据
public Student(String name, int age, double score) {
super();
this.name = name;
this.age = age;
this.score = score;
}
//增加get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
//覆盖toString()方法方便调试和显示
@Override
public String toString() {
return "Student [age=" + age + ", name=" + name + ", score=" + score
+ "]";
}
}
//自定义排序器
class myStudentComparactor implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
if (o1.getScore() > o2.getScore())
return (int) -1;
else if (o1.getScore() < o2.getScore())
return 1;
else if (o1.getAge() > o2.getAge())
return 1;
else if (o1.getAge() < o2.getAge())
return -1;
else if (o1.getScore() == o2.getScore() && o1.getAge() == o2.getAge())
return o1.getName().compareTo(o2.getName());
return 0;
}
}另外:在comparable接口的介绍中:也可以使用Arrays.sort()进行排序,上面已经展示了TreeSet的构造器,下面是简略的说明一下,如果对象加入的是Arrays中,也可以通过Arrays.sort()指定构造器进行元素的排序,下面是方法
static
<T> void
sort(T[] a, Comparator<? super T> c)
根据指定比较器产生的顺序对指定对象数组进行排序。
static
<T> void
sort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c)
根据指定比较器产生的顺序对指定对象数组的指定范围进行排序。
通过这样的传入比较器的方式我们也能实现对自定义对象的排序,下面是代码:
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class SortStudent {
public static void main(String[] args) {
Student students[] = new Student[7];
students [0]=new Student("Tom",24, 89);
students [1]=new Student("Robin",32, 99);
students [2]=new Student("Jerry",24, 99);
students [3]=new Student("Lili",23, 87);
students [4]=new Student("Jack",22, 87);
students [5]=new Student("LiLei",25, 95);
students [6]=new Student("Robin",32 ,99);
Myout(students);
}
//定义输出函数在此进行排序
public static void Myout(Student[] students) {
Arrays.sort(students, new MysortType());
for (Student student : students) {
System.out.println(student.toString());
}
}
}
//自定义排序类定义排序方法
class MysortType implements Comparator<Student>{
@Override
public int compare(Student o1,Student o2) {
if (o1.getScore() > o2.getScore())
return (int) -1;
else if (o1.getScore() < o2.getScore())
return 1;
else if (o1.getAge() > o2.getAge())
return 1;
else if (o1.getAge() < o2.getAge())
return -1;
else if (o1.getScore() == o2.getScore() && o1.getAge() == o2.getAge())
return o1.getName().compareTo(o2.getName());
return 0;
}
}
class Student {
private String name;
private int age;
private int score;
public Student() {
}
//增加带参数构造器方便添加数据
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
//增加get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
//覆盖toString()方法方便调试和显示
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", score=" + score
+ "]";
}
}
总结:相同点:Comparable接口和comparactor接口都是对自定义类添加自然顺序的方法。
不同点:Comparable接口实现方式是自定义类实现Comparable接口,并重写compareTo方法,自定义排序方式,使得自定义类有了自然顺序的排序方式但是这种方 式改变了自定义类的结构,使得代码不再完美。
Comparator接口实现方式是例如本文的Student类之外定义新的类,实现Comparator接口,并实现comapre方法,自定义排序方式,形成排序器,然后将排序 器传给TreeSet,从而实现对Student的排序。这种方式相对于第一种而言,更具有灵活性。而且没有对Student类本身造成任何的影响。这种方式更加方便。
而且看一下下面是Comparable多有的实现类