文章目录
- 一、对比简介
- 二、Comparable接口的实例操作
- 三、Comparator接口实例操作
- 四、当用到自定义排序器的时候
- 五、Comparable和Comparator区别比较
- 六、拓展:集合TreeSet(自然排序与定制排序)
一、对比简介
实现Compareable接口与Comparator接口的类,都是为了对象实例数组排序的方便,因为可以直接调用
java.util.Arrays.sort(对象数组名称),可以自定义排序规则。排序实现的原理都是基于红黑二叉树原理实现的。
- Comparable是排序接口。若一个类实现了Comparable接口,就意味着该类支持排序。实现了Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。
- Comparator是比较接口,我们如果需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口),那么我们就可以建立一个“该类的比较器”来进行排序,这个“比较器”只需要实现Comparator接口即可。也就是说,我们可以通过实现Comparator来新建一个比较器,然后通过这个比较器对类进行排序。
不同之处:
1 排序规则实现的方法不同
- Comparable接口的方法:compareTo(Object o)
- Comparator接口的方法:compare(T o1, To2)
2 类设计前后不同
- Comparable接口用于在类的设计中使用;设计初期,就实现这个借口,指定排序方式。
- Comparator接口用于类设计已经完成,还想排序(Arrays)。
二、Comparable接口的实例操作
N多的类中都有该compareTo方法,根本原因是因为它们都实现了接口comparable接口,并且实现了接口中的compareTo方法。
实现Compareable的jdk源码类
Student类创建时实现Comparable接口,覆写compareTo()方法,
成绩按从高到低排序,成绩相等按年龄从小到大排序。
package ch11.lei.ji;
/*实现Comparator接口的类可以方便的排序,
* 覆写compareTo接口
* java.util.Arrays.sort(对象类数组),*/
class Student implements Comparable<Student> { // 指定类型为Student
private String name ;
private int age ;
private float score ;
public Student(String name,int age,float score){
this.name = name ;
this.age = age ;
this.score = score ;
}
public String toString(){
return name + "\t\t" + this.age + "\t\t" + this.score ;
}
public int compareTo(Student stu){ // 覆写compareTo()方法,实现排序规则的应用
if(this.score>stu.score){
return -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{
return 0 ;
}
}
}
};
public class Comparable01{
public static void main(String args[]){
Student stu[] = {new Student("张三",20,90.0f),
new Student("李四",22,90.0f),new Student("王五",20,99.0f),
new Student("赵六",20,70.0f),new Student("孙七",22,100.0f)} ;
java.util.Arrays.sort(stu) ; // 进行排序操作
for(int i=0;i<stu.length;i++){ // 循环输出数组中的内容
System.out.println(stu[i]) ;
}
}
};
三、Comparator接口实例操作
Student01类原先没有比较器,类完成后构建一个比较器StudentComparator类
按年龄从大到小排序。
package ch11.lei.ji;
import java.util.* ;
class Student01{ // 指定类型为Student
private String name ;
private int age ;
public Student01(String name,int age){
this.name = name ;
this.age = age ;
}
public boolean equals(Object obj){ // 覆写equals方法
if(this==obj){
return true ;
}
if(!(obj instanceof Student)){
return false ;
}
Student01 stu = (Student01) obj ;
if(stu.name.equals(this.name)&&stu.age==this.age){
return true ;
}else{
return false ;
}
}
public void setName(String name){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
public String toString(){
return name + "\t\t" + this.age ;
}
};
class StudentComparator implements Comparator<Student01>{ // 实现比较器
// 因为Object类中本身已经有了equals()方法
public int compare(Student01 s1,Student01 s2){
if(s1.equals(s2)){
return 0 ;
}else if(s1.getAge()<s2.getAge()){ // 按年龄比较
return 1 ;
}else{
return -1 ;
}
}
};
public class Comparator01{
public static void main(String args[]){
Student01 stu[] = {new Student01("张三",20),
new Student01("李四",22),new Student01("王五",20),
new Student01("赵六",20),new Student01("孙七",22)} ;
java.util.Arrays.sort(stu,new StudentComparator()) ; // 进行排序操作
for(int i=0;i<stu.length;i++){ // 循环输出数组中的内容
System.out.println(stu[i]) ;
}
}
};
注意: 1、若一个类要实现Comparator接口:它一定要实现compare(T o1, T o2) 函数,但可以不实现 equals(Object obj) 函数。
2、int compare(T o1, T o2) 是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”。
四、当用到自定义排序器的时候
如:Collections.sort中需要传入一个自定义的排序器,使用匿名内部类的方式,传入comparator,重写方法,使用A.compareToB的方式进行排序
static void sortByValue(Map map) {
List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
for (Map.Entry<String, Integer> mapping : list) {
System.out.println("键:" + mapping.getKey() + " 值:" + mapping.getValue());
}
注意: 这里的o1.getValue().compareTo(o2.getValue())
是字符串本身就实现了的比较方法
String类实现的接口public final class String extends Object implements Serializable, Comparable<String>, CharSequence
五、Comparable和Comparator区别比较
Comparable是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”。而Comparator是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。
Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。
两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。 用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。
六、拓展:集合TreeSet(自然排序与定制排序)
一、TreeSet的自然排序:
步骤:
1.让元素自身具备比较性,
2.实现Compareable接口,覆盖其CompareTo方法
例:
Class Student implements Comparable//第一:实现Compareable接口
{
private String name;
private int age;
//复写构造函数初始化姓名跟年龄
Student(String name,int age)
{
this.name = name;
this.age = age;
}
public int compareTo(Object obj) //第二:复写CompareTo方法
{
//return 0;
if(!(objinstanceof Student)) //第三:判断对象是否是特定类的一个实例
throw new RuntimeException("不是学生对象");
Student s = (Student)obj;
System.out.println(this.name+"....compareto....."+s.name);
//第四:当前对象的年龄与插入对象的年龄进行比较,当前年龄大于插入对象的年龄时,返回1,
此时将插入二叉树的右边,当等于时,返回0,进行次要条件的比较,再次调用;当小于时,返回-1;
if(this.age>s.age) //判断当前对象年龄是否大于传入的对象年龄
return 1;
if(this.age==s.age) //如果当前年龄等于传入对象的年龄,则比较姓名是否相同
{
return this.name.compareTo(s.name);
}
return -1;
/**/
}
public String getName() //获取姓名
{
return name;
}
public int getAge() //获取年龄
{
return age;
}
}
Class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts = newTreeSet(); //创建一个TreeSet的集合
ts.add(new Student("lisi02",22)); //往集合添加元素
ts.add(new Student("lisi007",20));
ts.add(new Student("lisi09",19));
ts.add(new Student("lisi08",19));
Iterator it = ts.iterator(); //初始化迭代器,遍历集合中的所有元素
while(it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}
二、TreeSet的定制排序
1、由来:当元素自身不具备比较性时,或者具备的比较性不是所需要的。
这时就要让集合自身具备比较性,在初始化时,就有了比较方式。
2、步骤:
1)实现comparator接口
2)复写compare方法
3)在创建TreeSet集合对象时,提供一个一个Comparator对象,
例:
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
Class Student1{
private Integer age;
public Student1(Integer age) {
super();
this.age = age;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return age + "";
}
}
class MyComparator implements Comparator{ //第一步:实现Comparator接口
@Override
public int compare(Object o1, Object o2) { //第二步:实现一个campare方法
//判断对象是否是特定类的一个实例
if(o1 instanceof Student1 & o2instanceof Student1){
Student1 s1 =(Student1)o1;
Student1 s2 =(Student1)o2;
if(s1.getAge() > s2.getAge()){
return -1;
}else if(s1.getAge() < s2.getAge()){
return 1;
}
}
return 0;
}
}
public Class Demo15 {
public static void main(String[] args) {
Set<Student1> s= new TreeSet(new MyComparator());//第三步:创建TreeSet集合对象时,提供一个一个Comparator对象,
/**
* 要实现定制排序,需要在创建TreeSet集合对象时,提供一个一个Comparator对象,
* 该对象里负责集合元素的排序逻辑;
*/
s.add(new Student1(140));
s.add(new Student1(15));
s.add(new Student1(11));
s.add(new Student1(63));
s.add(new Student1(96));
System.out.println(s);
}
}