排序自定义对象的数组

排序自定义对象的数组

假设我们有这样一个student的类

Student s1 = new Student(4,“张三”,25);
Student s2 = new Student(3,“李四”,18);
Student s3 = new Student(2,“王五”,50);
Student s4 = new Student(1,“赵六”,38);

第一列对应为ID,第二列对应为名字,第三列对应为年龄。
至于如何创建这个类不在我们的讨论范围。
现在我们想针对Student中的年龄进行按从小到大的排序应该如何做到呢?
通过JDK的API手册中Arrays.sort我们可以发现这样这两个重载的方法。

	static void sort(Object[] a) 
                  根据元素的自然顺序对指定对象数组按升序进行排序。 
     static <T> void  sort(T[] a, Comparator<? super T> c) 
                  根据指定比较器产生的顺序对指定对象数组进行排序。 

很明显这两个数组都是对自定义对象的数组进行排序的。
通过进一步查询API

自然排序

sort
public static void sort(Object[] a)
根据元素的自然顺序对指定对象数组按升序进行排序。数组中的所有元素都必须实现 Comparable 接口。此外,数组中的所有元素都必须是可相互比较的(也就是说,对于数组中的任何 e1 和 e2 元素而言,e1.compareTo(e2) 不得抛出 ClassCastException)。
保证此排序是稳定的:不会因调用 sort 方法而对相等的元素进行重新排序。

该排序算法是一个经过修改的合并排序算法(其中,如果低子列表中的最高元素小于高子列表中的最低元素,则忽略合并)。此算法提供可保证的 n*log(n) 性能。

参数:
a - 要排序的数组
抛出:
ClassCastException - 如果数组包含不可相互比较的 的元素(例如,字符串和整数)。

上面提到了 Comparable接口。查询手册里面就只有一种方法
int compareTo(T o) 比较此对象与指定对象的顺序。

也就是说,我们需要对自定义对象数组的类实现(implements)这个接口。接口类型为Comparable<T>。

啊~~~
通过API手册我们对自然排序得到了以下的结论:

  1. 对自定义对象调用接口Comparable

  2. 然后再对象数组中重写int compareTo(T o)方法

  3. 然后就放心的交给Arrays.sort排序吧。

以下是完整代码:

import java.util.Arrays;

public class PolyDemo04 {
	public static void main(String[] args) {
		Student s1 = new Student("张三",25);
		Student s2 = new Student("李四",18);
		Student s3 = new Student("王五",50);
		Student s4 = new Student("赵六",38);		
		Student[] stu = {s1,s2,s3,s4};
		
		System.out.println(Arrays.toString(stu));
		System.out.println("=======================================");
		// 针对对象数组进行排序
		Arrays.sort(stu);	
		System.out.println(Arrays.toString(stu));
	}
}
class Student implements Comparable<Student> {
//以下的代码为构建Student,可以略过直接到最后一行
	private int ID;
	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 int getID() {
		return ID;
	}
	public void setID(int iD) {
		ID = iD;
	}
	public Student() {
		super();
	}
	public Student(int ID,String name, int age) {
		super();
		this.ID = ID;
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
	//到此为止
	@Override
	public int compareTo(Student o) {
		return  o.getAge() - this.age;
	}
	
	
}

其实上面一大半的代码都是构建get/set方法 真正的代码只有

public int compareTo(Student o) {
		return  o.getAge() - this.age;
	}

来看看运行的效果吧
排序前
[Student [name=张三, age=25], Student [name=李四, age=18], Student [name=王五, age=50], Student [name=赵六, age=38]]
排序后
[Student [name=王五, age=50], Student [name=赵六, age=38], Student [name=张三, age=25], Student [name=李四, age=18]]

啊~我们看到都按照年龄排序了。

关于排序方法的探究

让我们在深入一点看看我们的sort到底用了那种方法来排序。代码很简单只需要在compareTo里面加入三行测试代码

	@Override
	public int compareTo(Student o) {
		System.out.println("this===" + this);
		System.out.println("   o===" + o);
		System.out.println("============================");
		return  o.getAge() - this.age;
	}

this***Student [name=李四, age=18]
o***Student [name=张三, age=25]


this***Student [name=王五, age=50]
o***Student [name=李四, age=18]


this***Student [name=王五, age=50]
o***Student [name=李四, age=18]


this***Student [name=王五, age=50]
o***Student [name=张三, age=25]


this***Student [name=赵六, age=38]
o***Student [name=张三, age=25]


this***Student [name=赵六, age=38]
o***Student [name=王五, age=50]


上面的排序是一个二分法的插入排序。具体探究过程再次篇幅有限就不介绍了。

定制排序

上面这个排序很好,但是对于行业潜规则Java bean来说显然在student类里面去重写一个借口显得惨无人道。之后维护代码的时候想要换一种排序还要回来找这个Student类。
那么有没有一种排序可以单独在一个类中就完成我们的分类呢?
在上面提到了还有一种排序
以下信息可以直接跳
sort
public static void sort(T[] a,Comparator<? super T> c)
根据指定比较器产生的顺序对指定对象数组进行排序。数组中的所有元素都必须是通过指定比较器可相互比较的(也就是说,对于数组中的任何 e1 和 e2 元素而言,c.compare(e1, e2) 不得抛出 ClassCastException)。
保证此排序是稳定的:不会因调用 sort 方法而对相等的元素进行重新排序。

该排序算法是一个经过修改的合并排序算法(其中,如果低子列表中的最高元素小于高子列表中的最低元素,则忽略合并)。此算法提供可保证的 n*log(n) 性能。

参数:
a - 要排序的数组
c - 确定数组顺序的比较器。null 值指示应该使用元素的自然顺序。
抛出:
ClassCastException - 如果数组包含使用指定的比较器不可相互比较的 的元素。

再来看看
Comparator<? super T> c
看看方法:int compare(T o1, T o2)
                                     比较用来排序的两个参数。
显然这里意思让我们重写他了
箱子让我们看看步骤

  1. 创建一个类去实现这个接口啦
  2. 与上面雷同

开始码代码吧

import java.util.Comparator;

class ComparatorImpl implements Comparator<Student>{

	@Override
	public int compare(Student o1, Student o2) {
		// TODO Auto-generated method stub
		return result = o1.getAge() - o2.getAge()}
}

其他的类和之前都一样喽。
但是我们在排序前要new一个ComparatorImpl类调用他的方法先

Comparator<Student> ci = new ComparatorImpl();
		
		Arrays.sort(stu,ci);

但是仅仅就这样就完了吗?
很多童鞋想到
Student s1 = new Student(4,“张三”,25);
Student s2 = new Student(3,“李四”,25);
Student s3 = new Student(2,“王五”,25);
Student s4 = new Student(1,“赵六”,38);
要是年龄一样怎么办呢?是不是要按照ID的顺序来排呢?
那么我们再来看看重写的compare

	@Override
	public int compare(Student o1, Student o2) {
		// TODO Auto-generated method stub
		return result = o1.getAge() - o2.getAge()}
}

我们看到return的就是一个int还是两个年龄相减后的!!那么要是两个年龄相等我们是不是只用把ID减一下就好了呢?

	@Override
	public int compare(Student o1, Student o2) {
		// TODO Auto-generated method stub
		int result = o1.getAge() - o2.getAge();
		
		if (result == 0) {
			result = o1.getId() - o2.getId();
		}
		
		return result;
	}

大功告成
看一下输出的代码
[Student [id=2, name=王五, age=25],
Student [id=3, name=李四, age=25],
Student [id=4, name=张三, age=25],
Student [id=1, name=赵六, age=38]]
好像成功了呢!

总结

还要总结!! 多照着码几遍吧。

发布了11 篇原创文章 · 获赞 0 · 访问量 179

猜你喜欢

转载自blog.csdn.net/Bryce_Loski/article/details/103498157