effective java(12) 之考虑实现Comparable接口

effective java 之考虑实现Comparable接口


1、什么是Comparable接口?

Comparable接口一般用于表示某个实例具有内在的排序关系。简单来说就是用于对象排序。

2、为什么需要实现Comparable接口?
我们可以对数值和字符串进行排序,是因为系统内部已经为我们定义了数值和字符串的排序关系。
而我们定义的对象,本身是不包含排序关系的,因此,我们无法直接对对象进行排序。
如果我们需要对对象进行排序的话,就必须定义对象的内在排序关系,即实现Comparable接口。

3、如何实现Comparable接口

我们举个具体的例子,我们定义一个person对象,要求person按照年龄来进行排序。
	import java.util.ArrayList;
	import java.util.Collections;
	import java.util.List;
	public class Person implements Comparable<Person> {
		private String name;
		private int age;

		public Person(String name, int age) {
			this.name = name;
			this.age = age;
		}
		@Override
		public int compareTo(Person o) {
			if (this.age > o.age)
				return 1;
			else if (this.age < o.age)
				return -1;
			else
				return 0;
		}
		@Override
		public String toString() {
			return "Person [name=" + name + ", age=" + age + "]";
		}
		public static void printList(List<Person> list) {
			for (Person p : list) {
				System.out.println(p);
			}
			System.out.println();
		}
		public static void main(String[] args) {
			List<Person> list = new ArrayList<>();
			list.add(new Person("John", 38));
			list.add(new Person("Marry", 21));
			list.add(new Person("Tom", 20));
			System.out.println("Before sort:");
			printList(list);
			Collections.sort(list);
			System.out.println("After sort:");
			printList(list);
		}
	}

Before sort:
Person [name=John, age=38]
Person [name=Marry, age=21]
Person [name=Tom, age=20]
After sort:
Person [name=Tom, age=20]
Person [name=Marry, age=21]
Person [name=John, age=38]
//升序排序
@Override
public int compareTo(Person o) {
if (this.age > o.age)
return 1;
else if (this.age < o.age)
return -1;
else
return 0;
}
//降序排序
@Override
public int compareTo(Person o) {
if (this.age < o.age)
return 1;
else if (this.age > o.age)
return -1;
else
return 0;
}


4、多重排序
假设age相同时,对name进行排序。
	public class Person implements Comparable<Person> {
		private String name;
		private int age;

		public Person(String name, int age) {
			this.name = name;
			this.age = age;
		}
		//多重排序
		@Override
		public int compareTo(Person o) {
			if (age > o.age)
				return 1;
			if (age < o.age)
				return -1;
			//若年龄相等,则直接通过名字来进行排序。
			return name.compareTo(o.name);
		}
		@Override
		public String toString() {
			return "Person [name=" + name + ", age=" + age + "]";
		}
		public static void printList(List<Person> list) {
			for (Person p : list) {
				System.out.println(p);
			}
			System.out.println();
		}
		public static void main(String[] args) {
			List<Person> list = new ArrayList<>();
			list.add(new Person("John", 38));
			list.add(new Person("Tom", 20));
			list.add(new Person("Marry", 20));
			System.out.println("Before sort:");
			printList(list);
			Collections.sort(list);
			System.out.println("After sort:");
			printList(list);
		}
	}

Before sort:
Person [name=John, age=38]
Person [name=Tom, age=20]
Person [name=Marry, age=20]
After sort:
Person [name=Marry, age=20]
Person [name=Tom, age=20]
Person [name=John, age=38]


实际上,也就是当年龄相等时,可以直接调用name的compare方法来进行排序。
因为字符串在系统中已经设置好了内部排序。
这里默认为升序,那如果需要设置降序呢?

return -name.compareTo(o.name);
修改为其相反数即可。

5、如果为Person类添加一个id属性,并要求先按id升序,若id相同,则按年龄降序,若id和age都相同,则按name升序。
	import java.util.ArrayList;
	import java.util.Collections;
	import java.util.List;

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

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


		// 先排序谁,就把谁放到最前面
		@Override
		public int compareTo(Person o) {
			if (id > o.id)
				return 1;
			if (id < o.id)
				return -1;
			// id相等的情况下,对age进行排序
			if (age > o.age)
				return -1;
			if (age < o.age)
				return 1;
			// 若id和age相等,则直接通过名字来进行排序。
			return name.compareTo(o.name);
		}


		@Override
		public String toString() {
			return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
		}


		public static void printList(List<Person> list) {
			for (Person p : list) {
				System.out.println(p);
			}
			System.out.println();
		}


		public static void main(String[] args) {
			List<Person> list = new ArrayList<>();
			list.add(new Person(3, "John", 38));
			list.add(new Person(1, "Tom", 20));
			list.add(new Person(1, "Marry", 20));
			System.out.println("Before sort:");
			printList(list);
			Collections.sort(list);
			System.out.println("After sort:");
			printList(list);
		}
	}

Before sort:
Person [id=3, name=John, age=38]
Person [id=1, name=Tom, age=20]
Person [id=1, name=Marry, age=20]
After sort:
Person [id=1, name=Marry, age=20]
Person [id=1, name=Tom, age=20]
Person [id=3, name=John, age=38]

6、实现Comparable接口所需满足的需求

满足对称性:
必须确保所有的x和y都满足sgn(x.compareTo(y)) == -sgn(y.compareTo(x));
满足传递性:
若(x.compareTo(y) >0 && y.compareTo(z)>0),则x.compareTo(z)>0。
若x.compareTo(y)==0,则sgn(x.compareTo(z)) == sgn(y.compareTo(z));


7、与Comparator的区别

Comparator位于包java.util下,而Comparable位于包java.lang下,Comparable接口将比较代码嵌入自身类中,而后者在一个独立的类中实现比较。 
如果类的设计师没有考虑到Compare的问题而没有实现Comparable接口,可以通过  Comparator来实现比较算法进行排序,并且为了使用不同的排序标准做准备,比如:升序、降序。

我们看一个Comparator的例子:

	import java.util.TreeSet; 
	import java.util.Comparator; 
	class NumComparator implements Comparator<NameTag> { 
		public int compare (NameTag left,NameTag right) { 
			return(left.getNumber() - right.getNumber()); 
		} 
	} 
	public class CollectionNine { 
		public static void main(String arg[]) { 
			new CollectionNine(); 
		} 
		CollectionNine() { 
			NumComparator comparator = new NumComparator(); 
			TreeSet<NameTag> set = new TreeSet<NameTag>(comparator); 
			set.add(new NameTag("Agamemnon",300)); 
			set.add(new NameTag("Cato",400)); 
			set.add(new NameTag("Plato",100)); 
			set.add(new NameTag("Zeno",200)); 
			set.add(new NameTag("Archimedes",500)); 
			for(NameTag tag : set) 
				System.out.println(tag); 
		} 
	}




每天努力一点,每天都在进步。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

powerfuler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值