内部比较器(Comparable)和外部比较器(Comparator)、匿名内部类

内部比较器(Comparable)

//接口:Comparable
//实现方法: compareTo(Object o)


/**
 * 图书类、学生类、新闻类、商品类等是不同的类,可是却都需要有比较的功能,怎么办?
 * 共同的父类不可以,可以定义一个比较接口Comparable,
 * 其中定义一个实现比较的方法compareTo(Object obj)。让各个类实现该接口即可。
 * Java中就是这么来实现的,下面就来模拟实现一下Comparable接口吧。
 */
public interface Comparable {
    /**
     * 判断两个对象的大小:this obj
     * @param obj  另一个对象
     * @return
     * 0 =
     * 负数 <
     * 正数 >
     */
   public int compareTo(Object obj);
}

内部比较器的特点:

内部比较器用于自定义一个类时,定义在类内部来进行比较的;

本身Compareto方法的实现是在创造的类内部进行实现的

public class Person implements Comparable  {
    private String name;
    private int age;

    @Override
    public int compareTo(Object obj) {
        Person other = (Person) obj;
        //先比较年龄,年龄相同在比较姓名
        int result = this.age - other.age;
        if (result == 0) {
            //用的是String的compareTo
            return this.name.compareTo(other.name);
        }else
        {
            return result;
        }

    }

    public Person(){

    }

    public Person(String name, int age) {
        //this.name = name;
        //this.age = age;
        this.setName(name);
        this.setAge(age);
    }
    public String getName(){
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {

        this.name=name;
    }

    public void setAge(int age) {
        if (age<0||age > 140) {
            System.out.println("请重新输入年龄");

        }else
        {
            this.age = age;
        }
    }

    public void show() {
        System.out.println("name=" + name + ",age=" + age);
    }

//    public static void main(String[] args) {
//        Person person = new Person();
//        person.name = "张三";
//        person.age = 24;
//        person.show();
//    }
}

外部比较器

//接口: Comparator
//实现方法:compare( Object o1, Object  o2)

外部比较器的特点:

外部比较器适用于对于自定义一个类时,在这个类的外部定义;

本身Compare方法的实现是再创造一个比较类来实现compare方法

public class People   {
    String name ;//姓名
    int age;//年龄

    public People01(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override//重写toString 方法
    public String toString() {
        return "People01{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
import java.util.Comparator;

public class ComparePeople implements Comparator<People> {
    @Override
    public int compare(People01 o1, People01 o2) {
        return o1.name.codePointAt(0)-o2.name.codePointAt(0);
    }
}

 

 

内部比较器与外部比较器可以在:TreeSet中用于比较俩个节点的大小,用于定义比较方法。

      因为TreeSet底层是由红黑树组成的,当添加节点时,需要进行比较,这时就必须用内部比较器或者外部比较器进行比较。

 

下面创建一个Student类以及创建一个TreeSet集合进行测试

首先创建一个Student类

package set;

import java.util.Objects;

public class Student implements Comparable<Student> { //这里利用泛型将内部比较器两个比较的对象由Object变为Student

    private  int sno;
    private String name;
    private int age;
    private double score;

    public Student() {
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (sno != student.sno) return false;
        if (age != student.age) return false;
        if (Double.compare(student.score, score) != 0) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = sno;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + age;
        temp = Double.doubleToLongBits(score);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }

    public Student(int sno, String name, int age, double score) {
        this.sno = sno;
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public int getSno() {
        return sno;
    }

    public void setSno(int sno) {
        this.sno = sno;
    }

    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;
    }

    @Override
    public String toString() {
        return "Student{sno=" + this.sno + ",name=" + this.name + ",age=" + this.age + ",score=" + this.score + "}";
    }
//实现内部比较器进行内部比较器中compareTO方法的实现
    @Override
    public int compareTo(Student o) {
        return this.sno - o.sno;
    }
}

只有在定义了内部比较器(在没有定义外部比较器的情况下)以后创建含有Student类的TreeSet集合才不会报错 

package set;

import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

/**
 * 创建一个学生对象
 * 使用Set存储对各学生信息
 * 问题1:为什么课程名称可以保证课程唯一性,而创建的学生类不能够保证唯一性(我觉得是因为创建的学生每个的地址不同)
 *
 *
 *
 * 问题2:为什么课程名称(String)方法TreeSet中可以保证唯一性 有序性,但是学生类放入TrerSet中直接抛出异常ClassCastException
 *
 * 思考:是否因为String是系统类  而Student是用户自定义类
 *
 * String做了某些操作,而Student没有做
 *
 * 解答问题1:任意对象放入HashSet LinkedHashSet等底层结构有哈希表的集合中,
 * 都必须重写两个方法:hashCode()  equals()
 * String类已经重写了两个方法,而Student类没有重写这两个方法
 *
 * 解答问题2:任意对象放入TreeSet等底层结构是红黑树的集合中,都需要实现Comparable接口 并实现其方法
 *
 * 问题3Comparable至多指定一种规则,如果希望按照更多的排序规则放入TreeSet中,怎么办?
 * 解决问题3:可以通过外部比较器来实现(匿名类)
 *
 */
public class TestSet2Student3 {

    public static void main(String[] args) {
//        Set<Student> set = new HashSet<Student>();
//        Set<Student> set = new LinkedHashSet<Student>();
        Set<Student> set = new TreeSet<Student>();
        //添加信息
        Student stu1 = new Student(1, "张三", 22, 68.1);
        Student stu2 = new Student(2, "王五", 26, 98.1);
        Student stu3 = new Student(3, "张忘", 25, 69.1);
        Student stu4 = new Student(4, "李四", 21, 78.1);
        Student stu5 = new Student(1, "张三", 22, 68.1);
        set.add(stu1);
        set.add(stu2);
        set.add(stu3);
        set.add(stu4);
        set.add(stu5);
        System.out.println(set.size());
        for (Student stu : set) {
            System.out.println(stu.toString());
        }
        System.out.println();

除了运用内部比较器以外,在Student以外可以定义外部比较器来进行比较

1.可以定义一个按照学生姓名的自然顺序进行排序的外部比较器

package set;

import java.util.Comparator;

public class StuNameComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getName().compareTo(o2.getName());
    }

}

 在主程序中进行测试

首先创建一个姓名外部比较器StuNameComparator的对象;

 Comparator comparator2 = new StuNameComparator();

在创建Treeset对象时调用这个外部比较器的对象

 Set set3 = new TreeSet(comparator2);//优先使用外部比较器

 最后代码段如下:

 System.out.println("----------------姓名排列-------------------");
        System.out.println();
        Comparator comparator2 = new StuNameComparator();
        Set set3 = new TreeSet(comparator2);//优先使用外部比较器
        set3.add(stu1);
        set3.add(stu2);
        set3.add(stu3);
        set3.add(stu4);
        set3.add(stu5);
        Iterator<Student> it3 = set3.iterator();
        while (it3.hasNext()) {
            Student stu = it3.next();
            System.out.println(stu);
        }

2.同理我们可以创建按照学生分数进行递减的外部比较器

package set;

import java.util.Comparator;

/**
 * 按照分数降序排列
 */
public class StuScoreDescComparator implements Comparator<Student> {

    @Override
    public int compare(Student o1, Student o2) {
        if (o1.getScore() > o2.getScore()) {
            return -1;
        } else if (o1.getScore() < o2.getScore()) {
            return 1;
        }else   {
            return (o1.getSno()-o2.getSno());
        }
    }
}

 在主程序中进行测试

System.out.println("----------------成绩降序排列-------------------");
        System.out.println();
        Comparator comparator1 = new StuScoreDescComparator();
        Set set2 = new TreeSet(comparator1);//优先使用外部比较器
        set2.add(stu1);
        set2.add(stu2);
        set2.add(stu3);
        set2.add(stu4);
        set2.add(stu5);
        Iterator<Student> it = set2.iterator();
        while (it.hasNext()) {
            Student stu = it.next();
            System.out.println(stu);
        }
        System.out.println();

 有时为了进行比较,用的次数不多时

3.可以不用定义外部比较器,只需要创建一个匿名内部类

匿名内部类其实时内部类的一种特殊情况

定义一个进行按照年龄大小排序的内部类

 //局部内部类
        class StuAgeComparator 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 1;
                }else{
                    return o1.getSno() - o2.getSno();
                }
            }
        }

而匿名内部类时从内部类的基础上进一步改善的

 //匿名内部类
        Comparator com3=new Comparator<Student>() {


            @Override
            public int compare(Student o1, Student o2) {

                    if (o1.getAge() > o2.getAge()) {
                        return -1;
                    } else if (o1.getAge() < o2.getAge()) {
                        return 1;
                    }else{
                        return o1.getSno() - o2.getSno();
                    }


            }
        };
        Set set4 = new TreeSet(comparator3);//优先使用外部比较器


        set4.add(stu1);
        set4.add(stu2);
        set4.add(stu3);
        set4.add(stu4);
        set4.add(stu5);
        Iterator<Student> it4 = set4.iterator();
        while (it4.hasNext()) {
            Student stu = it4.next();
            System.out.println(stu);

        }
        Double d1;

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值