详解Comparable接口与Comparator接口的使用及区别

一、简介

1、Comparable 接口简介

  • Comparable<T>接口:位于java.lang包下,需要重写public int compareTo(T o);
  • Comparable 是排序接口。若一个类实现了Comparable接口,就意味着“该类支持排序”。
  • “实现Comparable接口的类的对象”可以用作“有序映射(如TreeMap)”中的键或“有序集合(TreeSet)”中的元素,而不需要指定比较器。
  • 它强行将实现它的每一个类的对象进行整体排序-----称为该类的自然排序,实现此接口的对象列表和数组可以用Collections.sort(),和Arrays.sort()进行自动排序;
  • 接口中通过compareTo(T o)来比较x和y的大小。若返回负数,意味着x比y小;返回零,意味着x等于y;返回正数,意味着x大于y。

 2、Comparator 接口简介

  •  Comparator<T>接口:位于java.util包下,需要重写int compare(T o1, T o2);
  • Comparator 是比较器接口。我们若需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口);

  • 它是针对一些本身没有比较能力的对象(数组)为它们实现比较的功能,所以它叫做比较器,是一个外部的东西,通过它定义比较的方式,再传到Collection.sort()和Arrays.sort()中对目标排序,而且通过自身的方法compare()定义比较的内容和结果的升降序;

  • int compare(T o1, T o2) 和上面的x.compareTo(y)类似,定义排序规则后返回正数,零和负数分别代表大于,等于和小于。

二、 代码实现(具体案例)

 1.创建一个汽车的实体类Car 继承Comparable接口(排序接口),并重写compareTo方法

//让实体类Car继承Comparable接口
public class Car implements Comparable<Car> {
	
	private String brand;
	private int price;
	

	public Car() {
		super();
	}

	public Car(String brand, int price) {
		super();
		this.brand = brand;
		this.price = price;
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public int getPrice() {
		return price;
	}

	public void setPrice(int price) {
		this.price = price;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((brand == null) ? 0 : brand.hashCode());
		result = prime * result + price;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Car other = (Car) obj;
		if (brand == null) {
			if (other.brand != null)
				return false;
		} else if (!brand.equals(other.brand))
			return false;
		if (price != other.price)
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "Car [brand=" + brand + ", price=" + price + "]";
	}
    
    //重写compareTo()方法
	@Override
	public int compareTo(Car o) {
		return this.price-o.price;
	}
	
}

 2.创建测试类Test01

public class Test01{
	public static void main(String[] args) {
		//创建一个TreeMap集合,用来存放Car实体类对象
		TreeMap<Car, String> treeMap=new TreeMap<Car, String>();

		//向TreeMap集合中添加四个具体汽车类对象
		treeMap.put(new Car("宏碁汽车", 43), "动力十足!");
		treeMap.put(new Car("奔驰s", 38), "奔驰牌2");
		treeMap.put(new Car("奔驰s", 35), "奔驰牌1");
		treeMap.put(new Car("五菱", 50), "五菱宏光,动力十足!");
		
        //通过map.entry方法拿到一个个封装好的对象集合
		Set<Map.Entry<Car, String>> set=treeMap.entrySet();
		//通过增强for循环,遍历每个对象
		for (Entry<Car, String> entry : set) {
			System.out.println(entry);
		}
	}

运行结果为:

         通过上述运行结果,可以看出我们通过继承Comparable接口,重写compareTo()方法,在方法中我们return的是this.price-o.price;即排序规则是按照价格price从低到高排序,输出结果符合。现在我们修改return为o.price-this.price;观察输出结果,是否按照price由高到低输出。

 

 

 3.使用comparator接口(比较器接口),重写compare(T o1, T o2)方法。

TreeMap<Car, String> treeMap = new TreeMap<Car, String>(new Comparator<Car>() {
            //通过匿名内部类实现Comparator接口,重写compare方法,定义比较器的排序规则
			@Override
			public int compare(Car o1, Car o2) {
				if (o1.getBrand().length() == o2.getBrand().length()) {
					return o1.getPrice() - o2.getPrice();
				}
				return o1.getBrand().length() - o2.getBrand().length();
			}
		});
        

4.创建测试类Test02(此时需要将Car实体类中继承的Comparable接口先删除掉) 

public class Test02{
	public static void main(String[] args) {
		//创建一个TreeMap集合,用来存放Car实体类对象
		TreeMap<Car, String> treeMap = new TreeMap<Car, String>(new Comparator<Car>() {
            //通过匿名内部类实现Comparator接口,重写compare方法,定义比较器的排序规则
			@Override
			public int compare(Car o1, Car o2) {
				if (o1.getBrand().length() == o2.getBrand().length()) {
					return o1.getPrice() - o2.getPrice();
				}
				return o1.getBrand().length() - o2.getBrand().length();
			}
		});

		//向TreeMap集合中添加四个具体汽车类对象
		treeMap.put(new Car("宏碁汽车", 43), "动力十足!");
		treeMap.put(new Car("奔驰s", 38), "奔驰牌2");
		treeMap.put(new Car("奔驰s", 35), "奔驰牌1");
		treeMap.put(new Car("五菱", 50), "五菱宏光,动力十足!");
		
        //通过map.entry方法拿到一个个封装好的对象集合
		Set<Map.Entry<Car, String>> set=treeMap.entrySet();
		//通过增强for循环,遍历每个对象
		for (Entry<Car, String> entry : set) {
			System.out.println(entry);
		}
	}

 运行结果为:

        由匿名内部类中实现的Comparator接口中重写的Compare(Car o1,Car o2)方法中定义的排序规则看出当品牌名长度相同时,比较价格price,从低到高显示;当品牌名长度不等时,比较品牌名长度,从长度小的到长度大的显示。从运行结果来看符合排序规则。

        此时,可能有的小伙伴会有一个疑惑当同时实现了Comparable接口和Comparator接口时,遵从谁定义的排序规则呢?那就随小编一起操作,将Car实体类中继承的Comparable接口重新继承,然后再次运行Test02,观察结果。

        此时 我们会发现运行结果,使用的是Comparator接口实现类中定义的排序规则,而不是继承了Comparable接口中定义的按照价格price从高到低排序规则。

Tips:当我们同时实现了Comparable接口和Comparator接口时,谁离的近就用谁定义的排序规则(就近原则)

 三、区别

  1.  Comparable接口位于java.lang包下;Comparator位于java.util包下
  2. Comparable接口只提供了一个compareTo()方法;
  3. Comparator接口不仅提供了compara()方法,还提供了其他默认方法,如reversed()、thenComparing(),使我们可以按照更多的方式进行排序
  4. 如果要用Comparable接口,则必须实现这个接口,并重写comparaTo()方法;
  5. Comparator接口可以在类外部使用,通过将该接口的一个匿名类对象当做参数传递给Collections.sort()方法或者Arrays.sort()方法实现排序。
  6. Comparator体现了一种策略模式,即可以不用要把比较方法嵌入到类中,而是可以单独在类外部使用,这样我们就可有不用改变类本身的代码而实现对类对象进行排序。

四、总结

  •  学习Comparable接口和Comparator接口本质的不同在于使用的时机;
  • 如果你想给这个类通过一种顺序排序,那就实现Comparable接口;
  • 如果你不想实现Comparable接口,想用这个像算法一样的方式去实现,那就直接在测试类写一个Comparator接口的实现类的对象就好了,在其中实现你想要的排序方式即可!

小编的话:编程不仅仅要学,还要灵活的去用。

                要明白条条大路通成功!要开发自己的思维,激发自我的编程之魂~

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ComparatorComparable都是Java中用于比较对象的接口,但它们的使用场景略有不同。 Comparable接口Java中内置的接口,用于对类的对象进行比较。如果一个类实现了Comparable接口,那么它的对象就可以通过Collections.sort()或Arrays.sort()方法进行排序。Comparable接口只有一个compareTo()方法,用于定义对象之间的自然排序规则。例如,如果我们有一个Student类,我们可以在其中实现Comparable接口,以便按照学生的年龄进行排序: ```java public class Student implements Comparable<Student> { private String name; private int age; // 构造函数、getter和setter方法 @Override public int compareTo(Student other) { return Integer.compare(this.age, other.age); } } ``` Comparator接口也是Java中的接口,用于对类的对象进行比较。与Comparable不同的是,Comparator接口可以在创建对象时动态地指定排序规则。Comparator接口有两个方法:compare()和equals()。compare()方法用于定义对象之间的排序规则,而equals()方法用于比较两个对象是否相等。例如,如果我们有一个Person类,我们可以在其中实现Comparator接口,以便按照身高进行排序: ```java public class Person { private String name; private int age; private int height; // 构造函数、getter和setter方法 public static Comparator<Person> heightComparator = new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return Integer.compare(p1.getHeight(), p2.getHeight()); } }; } ``` 在上面的例子中,我们创建了一个名为heightComparatorComparator对象,它可以按照Person对象的身高进行排序。在需要按照身高排序的时候,我们可以使用Collections.sort()或Arrays.sort()方法,并将heightComparator作为参数传递进去。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值