【JAVA】Collections.sort()实现动态数组自定义排序

时间:2024-03-24 16:53:17

Collections.sort()


@SuppressWarnings("unchecked")
    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
    }
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }

Collections.sort()的源码如上所示,可以看到Collections.sort()实现了两种重载

  • 第一种<T extends Comparable<? super T>>:这种方法需要我们实现Comparable接口中的compareTo()方法
  • 第二种对泛型无要求,但是需要我们实现Comparator比较器接口



Comparable排序接口

  • 如果一个类实现了Comparable接口,则该类支持排序
  • 如果一个List或者一个数组中的对象是实现了Comparable接口的类,则可以通过Collections.sort()或者Arrays.sort()来对该数组进行排序

可以通过一个例子来说明。首先我们创建一个类Fruit实现Comparable接口,并且重载compareTo方法

class Fruit implements Comparable<Fruit>{
	private String name;
	private int price;
	
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getPrice() {
		return price;
	}

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


	@Override
	public int compareTo(Fruit f) {
		return this.price-f.price;
	}
	
	@Override
	public String toString() {
		return "the fruit is "+this.name+"\nand the price is "+this.price;
	}	
}
  • 这个类中还重载了toString方法,这样我们可以通过System.out.println(实体对象)直接输出这个对象的信息
  • 本来compareTo()是用于比较字符串的,这里重载之后用于比较int型数字

然后测试一下:

	public static void main(String[] args) {
		List<Fruit> list=new ArrayList<>();
		
		Fruit apple=new Fruit();
		apple.setName("apple");
		apple.setPrice(12);
		
		Fruit banana=new Fruit();
		banana.setName("banana");
		banana.setPrice(7);
		
		list.add(apple);
		list.add(banana);
				
		Collections.sort(list);
		
		System.out.println(list);
	}

运行结果为:
【JAVA】Collections.sort()实现动态数组自定义排序
可以看到,成功通过Collections.sort()对动态数组list中的中的两个对象apple和banana按照价格进行了升序排序

PS:
如果我们需要实现升序排序,重载compareTo()方法时使用【成员变量-方法变量】的方式:

	@Override
	public int compareTo(Fruit f) {
		return this.price-f.price;
	}

如果需要实现降序排序,重载时使用【方法变量-成员变量】的方式:

	@Override
	public int compareTo(Fruit f) {
		return this.price-f.price;
	}



Comparator比较器接口

对刚刚那个例子,这次我们使用Comparator比较器接口来实现Collections.sort()来进行排序:

class Fruit{
	private String price;
	private String name;

	public String getPrice() {
		return price;
	}

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

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "the fruit name is "+name+"\nand the price is "+price;
	}
}

首先可以看到第二种方法中,我们创建的类没有重载compareTo方法。测试方法如下:

	public static void main(String[] args) {
		List<Fruit> list=new ArrayList<>();
		
		Fruit apple=new Fruit();
		apple.setName("apple");
		apple.setPrice("12");
		
		Fruit banana=new Fruit();
		banana.setName("banana");
		banana.setPrice("7");
		
		list.add(apple);
		list.add(banana);
		
		Collections.sort(list,new Comparator<Fruit>() {
			@Override
			public int compare(Fruit f1,Fruit f2) {
				return f1.getPrice().compareTo(f2.getPrice());
			}
		});
				
		System.out.println(list);
	}

运行结果如下:
【JAVA】Collections.sort()实现动态数组自定义排序



拓展一:Comparator比较器接口的另外一种写法

如果一个类对象有多种可以比较的参数,则可以使用自定义比较器来实现对不同参数的排序。
这里同样以刚刚的例子进行说明,令Fuit这个类的成员变量为id、name、price,然后针对Fruit对象的id和price来写自定义比较器来排序。
Fruit类代码如下:

class Fruit{
	private int id;
	private String name;
	private int price;
	
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getPrice() {
		return price;
	}

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


	@Override
	public String toString() {
		return "id: "+id+"  fruit name: "+name+"  price: "+price;
	}
}
  • 使用自定义比较器接口的话,类就不用实现Comparable接口
  • Fruit的成员变量有id、name、price,每个成员变量都有自己的set和get方法
  • Fruit类重写了toString()方法

对id和price的自定义比较器如下:

	static class PriceComparator implements Comparator<Object>{
		public int compare(Object o1,Object o2) {
			Fruit f1=(Fruit)o1;
			Fruit f2=(Fruit)o2;
			return f1.getPrice()-f2.getPrice();
		}
	}
	
	static class IdComparator implements Comparator<Object>{
		public int compare(Object o1,Object o2) {
			Fruit f1=(Fruit)o1;
			Fruit f2=(Fruit)o2;
			return f1.getId()-f2.getId();
		}
	}
	
	public static void printList(List<Fruit> list) {
		Iterator it=list.iterator();
		while(it.hasNext()) {
			System.out.println(it.next()+"\n");
		}
	}
  • 自定义比较器需要实现Comparator接口,同时实现了该接口中的方法compare()
  • 这里还写了个方法printList,用于打印Fruit数组中的对象

测试方法如下:

public static void main(String[] args) {
		List<Fruit> list=new ArrayList<>();
		
		Fruit apple=new Fruit();
		apple.setId(1);
		apple.setName("apple");
		apple.setPrice(12);
		
		Fruit banana=new Fruit();
		banana.setId(2);
		banana.setName("banana");
		banana.setPrice(7);
		
		list.add(apple);
		list.add(banana);
		
		Collections.sort(list,new PriceComparator());
		System.out.println("按照书的价格来排序"+"\n");
		printList(list);
		
		Collections.sort(list,new IdComparator());
		System.out.println("按照书的ID来排序"+"\n");
		printList(list);
	}

运行结果如下:
【JAVA】Collections.sort()实现动态数组自定义排序



拓展二:使用ES6的语法来写Comparator比较器接口

通过ES6的语法来写的话,代码看起来会简洁很多。例如我们有一个list,list是Fruit对象,现在使用Collections.sort()来对list中的Fruit对象按照id来排序。
首先我们的Fruit的代码为:

class Fruit{
	private int id;
	private String name;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	public String toString() {
		return "id: "+String.valueOf(id)+"\nname: "+name+"\n";
	}
}

然后测试类为:

public class TestComparator{
	public static void main(String[] args) {
		List<Fruit> list=new ArrayList<Fruit>();
		Fruit apple=new Fruit();
		apple.setId(0);
		apple.setName("apple");
		Fruit banana=new Fruit();
		banana.setId(3);
		banana.setName("banana");
		list.add(apple);
		list.add(banana);
		
		Collections.sort(list,(a,b)->(a.getId()-b.getId()));
		
		System.out.println(list);
	}
}

可以发现,Collections.sort()的代码被缩减成了一行:

Collections.sort(list,(a,b)->(a.getId()-b.getId()));

相关文章