Comparable 外部比较器 在java.lang包内 自然排序
以学生类为例,包含属性,构造方法,hashcode,equals方法等
public class Student {
public String name;
public int id;
public Student(String name, int id) {
super();
this.name = name;
this.id = id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "姓名=" + name + ", 学号=" + id;
}
}
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
import org.junit.Test;
public class TestStudent{
@Test
public void testComparable() {
Set<Student> s1 = new TreeSet<>();
s1.add(new Student("bb", 3));
s1.add(new Student("bb", 3));
s1.add(new Student("cc", 2));
s1.add(new Student("aa", 1));
System.out.println(s1);
}
}
会有java.lang.ClassCastException: org.witer.Student cannot be cast to java.lang.Comparable异常;意思是学生类型转换为Comparable类型失败
让学生类实现Comparable接口,重写compareTo方法,代码如下
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
import org.junit.Test;
public class Student implements Comparable<Student> {
public String name;
public int id;
public Student(String name, int id) {
super();
this.name = name;
this.id = id;
}
// 计算hash值是否相等
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
// 若hash值相等,用equals判断是否相等
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "姓名=" + name + ", 学号=" + id;
}
// 改写compareTo方法
@Override
public int compareTo(Student o) {
// 定义一个变量bj 将传入的参数和自己比较
int bj = this.id > o.id ? 1 : (this.id == o.id ? 0 : -1);
// 若id值相同,则用姓名的自然排序
if (bj == 0) {
bj = this.name.compareTo(o.name);
}
return bj;
}
}
Console 输出:[姓名=aa, 学号=1, 姓名=cc, 学号=2, 姓名=bb, 学号=3]
Comparator 内部比较器 在java.util包内 定制排序
以人类为例,参照学生类,也可以实现Comparator接口,重写compare方法,但是这样浪费了资源(一个类)
所以可以在外部写一个比较器,调用比较器解决问题
public class Person {
private String name;
private int age;
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 Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "姓名=" + name + ", 年龄=" + age;
}
}
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
import org.junit.Test;
public class TestStudent{
@Test
public void testComparator(){
//定义一个比较器
Comparator<Person> com=new Comparator<Person>() {
@Override
//重写compare方法
public int compare(Person o1, Person o2) {
//定义一个变量接收比较值
int b=o1.getAge()>o2.getAge()?1:(o1.getAge()==o2.getAge()?0:-1);
//如果年龄相等,按姓名的自然排序
if(b==0){
b=o1.getName().compareTo(o2.getName());
}
return b;
}
};
//创建集合并调用比较器
Set<Person>p1=new TreeSet<>(com);
p1.add(new Person("cc", 15));
p1.add(new Person("aa", 28));
p1.add(new Person("aa", 12));
p1.add(new Person("bb", 15));
System.out.println(p1);
}
}
Console显示 [姓名=aa, 年龄=12, 姓名=bb, 年龄=15, 姓名=cc, 年龄=15, 姓名=aa, 年龄=28]
什么时候使用定制排序?
答:1,当自然排序和定制排序都存在时,优先使用定制排序
2,当集合不支持自身比较器或者不满足程序员需求时