内部比较器(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;
}
}