对对象数组与存放对象数据的集合进行排序 —— Comparable接口的用法

Arrays类的sort方法可以对整型数组进行升序排列:

int[] i = { 1, 5, 2, 4, 3 };
Arrays.sort(i);
System.out.println(Arrays.toString(i));

控制台则输出:[1, 2, 3, 4, 5]

Collections类的sort方法可以对整型数据集合实现相同的功能:

List<Integer> l = new ArrayList<>();
l.add(1);
l.add(5);
l.add(2);
l.add(4);
l.add(3);
Collections.sort(l);
System.out.println(l);

输出为:[1, 2, 3, 4, 5]


其实,sort方法不仅仅可以对整型数据进行排序,也可以对对象数组与存放对象数据的集合进行排序,而且可以指定排序方式(升序或降序),但要求满足以下前提:对象所属的类必须实现了Comparable接口。

下面是Comparable接口的源代码:

public interface Comparable<T> {
    public int compareTo(T o);
}

在实现接口时,泛型<T>中的T需声明为欲排序对象的类型。

若一个数组或集合中存放的对象所对应的类实现了Comparable接口并重写了compareTo方法,那么在调用Arrays.sort或Collections.sort的时候就能够对数组或集合进行排序。具体实现的方式我们在这里不去讨论,因为那是Arrays类和Collections类中的内容(这两个类分别为对数组和集合进行相关操作的工具类,比如排序功能的实现),在这里我们着重探讨一下Comparable接口中的comparaTo抽象方法。

在调用s.compareTo(o)的时候,compareTo方法会比较两个对象的内容,并返回比较的结果。当s小于o时,返回一个负数;当s大于o时,返回一个正数;否则(s等于o)时,返回0。

因此,在实现类重写compareTo方法时,需要比较当前类中的属性(比如,年龄 age)与参数对象o对应属性(o.age)的大小,并根据需求(升序排列、降序排列)返回相应的值(正数或负数)。

这段话苦涩难懂,不过不用担心,接下来的例子会让你很轻松的理解它想表达的意思。


现有一简单的学生类 Student,类中包含学生的一些信息:姓名 name、年龄 age,包含构造方法对学生信息进行初始化,重写toString方法用来在控制台打印信息。代码如下:

public class Student {

	private String name;
	private int age;

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

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

}

创建一测试类,实例化5个学生,并存入Student类型的数组。代码如下:

public class Test {

	public static void main(String[] args) {

		Student s1 = new Student("张三", 20);
		Student s2 = new Student("李四", 18);
		Student s3 = new Student("王五", 22);
		Student s4 = new Student("赵六", 19);
		Student s5 = new Student("孙七", 21);

		Student[] s = { s1, s2, s3, s4, s5 };

	}

}

现有需求:将数组中的学生按照年龄进行升序排列。

此时,便需要用到Arrays.sort方法。但前文已经说过,对对象数组进行排序需要对象所属类实现Comparable接口并重写compareTo方法。因此我们需要对Student类进行如下修改:

实现Comparable接口:

public class Student implements Comparable<Student> {     // 泛型T改为欲排序的对象所属的类(Student)

重写compareTo方法:

@Override
public int compareTo(Student o) {
	if (age < o.age) {
		return -1;     // 这里的-1可以改成任意负数,若想按降序排列则改为返回一个正数
	} else if (age > o.age) {
		return 1;     // 若想按降序排列则改为返回一个负数
	} else {
		return 0;
	}
}

其实这个方法有改善的空间,Integer类有一个名为compare的静态方法,源代码如下:

public static int compare(int x, int y) {
    return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

方法体中的三元表达式的作用为:当 x < y 时,返回 -1;当 x > y 时,返回 1;否则返回 0。这正是我们所需要的。顺便一提,Double类也有这个方法,它能适用于double类型的数据,适用面更广。

修改后的compateTo方法:

@Override
public int compareTo(Student o) {
	return Integer.compare(age, o.age);
}

怎么样,是不是简化了很多?若想按降序排列只要改变compare方法两个参数的位置就可以了(age 和 o.age)。

现在我们可以在Test类中调用sort方法,并用foreach循环将排序后的数组打印出来了:

Arrays.sort(s);
for (Student ss : s)
	System.out.println(ss);     // 这里能够直接输出Student的对象是因为Student类中重写了toString方法

打印结果为:

Student [name=李四, age=18]
Student [name=赵六, age=19]
Student [name=张三, age=20]
Student [name=孙七, age=21]
Student [name=王五, age=22]

至此,我们已经实现了对对象数组的排序操作。


若想对存放对象数据的集合进行排序需要执行的操作是类似的,只要将对象存到集合就可以了。

不过这里需要注意的是,TreeSet集合本身便具有排序的功能,因此,如果一个TreeSet中存放的对象数据所对应的类没有实现Comparable接口,那么在对这个TreeSet进行操作的时候会抛出一个ClassCastException(类型转换异常),它会提示你存放的数据无法转换成Comparable类型。


在本文中,我们进行排序操作时均选择了整型的数据,比如整型数组和整型数据集合,对对象数组的排序也选择了以整型的年龄作为判断的依据。其实,sort方法的排序依据不仅仅局限于整型,只要制定好排序的规则,便可以按照需求做出相应的排序操作,比如按照姓名的首字母进行排序等,这些更复杂的需求需要我们对sort方法进行深入的研究,也需要在重写compareTo方法时给出更复杂的算法。如果你有兴趣,可以去尝试一下,相信你一定会成功!


在本文的最后我会放上Student类和Test类的全部代码,供参考用。

如果您看到了这里,我表示由衷的感谢,这是我的第一篇博文,希望您以后能多多支持!


Student:

public class Student implements Comparable<Student> {

	private String name;
	private int age;

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

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

	@Override
	public int compareTo(Student o) {
		return Integer.compare(age, o.age);
	}

}

Test:

import java.util.Arrays;

public class Test {

	public static void main(String[] args) {

		Student s1 = new Student("张三", 20);
		Student s2 = new Student("李四", 18);
		Student s3 = new Student("王五", 22);
		Student s4 = new Student("赵六", 19);
		Student s5 = new Student("孙七", 21);

		Student[] s = { s1, s2, s3, s4, s5 };

		Arrays.sort(s);
		for (Student ss : s)
			System.out.println(ss);

	}

}

感谢阅读!

转载于:https://my.oschina.net/1263612846/blog/686650

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值