1. 基本类型排序
1.1 升序
基本类型可直接调用()进行排序,默认升序排列:
public class Test {
public static void sort() {
int[] nums = new int[]{4, 3, 2, 6, 4, 23, 18};
System.out.println("排序前:" + Arrays.toString(nums));
Arrays.sort(nums);
System.out.println("排序后:" + Arrays.toString(nums));
}
public static void main(String[] args) {
sort();
}
}
执行结果:
排序前:[4, 3, 2, 6, 4, 23, 18]
排序后:[2, 3, 4, 4, 6, 18, 23]
1.2 降序
如果需要进行降序排列,则需要自定义比较器Comparator,但Comparator仅支持包装类和自定义类,不支持基本数据类型,如果对基本类型进行降序排列,可以对数组进行升序排列后反转:
public class Test {
public static void sort() {
int[] nums = new int[]{4, 3, 2, 6, 4, 23, 18};
System.out.println("排序前:" + Arrays.toString(nums));
Arrays.sort(nums);
reverse(nums);
System.out.println("排序后:" + Arrays.toString(nums));
}
public static void reverse(int[] nums) {
for (int left = 0, right = nums.length - 1; left < right; left++, right--) {
// swap the values at the left and right indices
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
}
public static void main(String[] args) {
sort();
}
}
执行结果:
排序前:[4, 3, 2, 6, 4, 23, 18]
排序后:[23, 18, 6, 4, 4, 3, 2]
Java包装类,如Integer,需要通过自定义Comparator类来自定义排序顺序:
public class Test {
public static void sort() {
Integer[] nums = new Integer[]{4, 3, 2, 6, 4, 23, 18};
System.out.println("排序前:" + Arrays.toString(nums));
// 1. 自定义比较器Compartor
Arrays.sort(nums, new IntegerComparator());
System.out.println("排序后:" + Arrays.toString(nums));
// 2. 匿名类
Arrays.sort(nums, new Comparator<Integer>() {
@Override
public int compare(Integer n1, Integer n2) {
return n2 - n1;
}
});
System.out.println("排序后:" + Arrays.toString(nums));
// 3. lambda表达式
Arrays.sort(nums, (n1, n2) -> n2 - n1);
System.out.println("排序后:" + Arrays.toString(nums));
}
public static void main(String[] args) {
sort();
}
}
class IntegerComparator implements Comparator<Integer> {
@Override
public int compare(Integer n1, Integer n2) {
return n2 - n1;
}
}
执行结果:
排序前:[4, 3, 2, 6, 4, 23, 18]
排序后:[23, 18, 6, 4, 4, 3, 2]
排序后:[23, 18, 6, 4, 4, 3, 2]
排序后:[23, 18, 6, 4, 4, 3, 2]
Comparator的详细介绍见后面章节。
2. 自定义类型排序
2.1 Java比较器 - Comparable
Comparable 是排序接口,若一个类实现了 Comparable 接口,就意味着该类“支持排序”或者“具有比较能力”。如,当前有一个描述小狗的类Dog,具有名字和年龄两个属性,要求可以根据小狗的年龄大小进行排序:
public class Dog implements Comparable<Dog> {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{name: " + this.name + ", age: " + this.age + "}";
}
// 重写compareTo方法
@Override
public int compareTo(Dog dog) {
if (this.age > dog.age) {
return 1;
} else if (this.age < dog.age) {
return -1;
}
return 0;
}
}
compareTo方法用来比较两个实例的大小,比较器根据该方法返回值进行排序:
- 返回正数,表示当前实例比传入的实例大
- 返回复数,表示当前实例比传入的实例小
- 返回0,表示两者相等
因此上述代码中的compareTo()可以简写为:
public int compareTo(Dog dog) {
return this.age - dog.age;
}
构造一个Dog数组,进行排序:
public class Test {
public static void sort() {
Dog dog1 = new Dog("AAA", 3);
Dog dog2 = new Dog("BBB", 2);
Dog dog3 = new Dog("CCC", 4);
Dog dog4 = new Dog("DDD", 1);
Dog[] dogs = new Dog[]{dog1, dog2, dog3, dog4};
System.out.println("排序前:" + Arrays.toString(dogs));
Arrays.sort(dogs);
System.out.println("排序后:" + Arrays.toString(dogs));
}
public static void main(String[] args) {
sort();
}
}
执行结果:
排序前:[Dog{name: AAA, age: 3}, Dog{name: BBB, age: 2}, Dog{name: CCC, age: 4}, Dog{name: DDD, age: 1}]
排序后:[Dog{name: DDD, age: 1}, Dog{name: BBB, age: 2}, Dog{name: AAA, age: 3}, Dog{name: CCC, age: 4}]
若要实现按照年龄降序排列,compareTo可定义为:
public int compareTo(Dog dog) {
return dog.age - this.age;
}
2.2 Java比较器 - Comparator
Comparator是定义在类之外的比较器,该类本身并不支持排序,而只是定义一种排序规则。当不希望改变原有类,或者原有类提供的比较器不支持当前需求时,可以考虑外部定义Comparator实现类。
现在仍然有一个小狗的类,但是没有实现Comparable接口:
public class Dog {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{name: " + this.name + ", age: " + this.age + "}";
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
接下来实现Comparator类,实现其compare方法:
public class Test {
public static void sort() {
Dog dog1 = new Dog("AAA", 3);
Dog dog2 = new Dog("BBB", 2);
Dog dog3 = new Dog("CCC", 4);
Dog dog4 = new Dog("DDD", 1);
Dog[] dogs = new Dog[]{dog1, dog2, dog3, dog4};
System.out.println("排序前:" + Arrays.toString(dogs));
Arrays.sort(dogs, new DogComparator());
System.out.println("排序后:" + Arrays.toString(dogs));
}
public static void main(String[] args) {
sort();
}
}
class DogComparator implements Comparator<Dog> {
@Override
public int compare(Dog d1, Dog d2) {
return d1.getAge() - d2.getAge();
}
}
执行结果:
排序前:[Dog{name: AAA, age: 3}, Dog{name: BBB, age: 2}, Dog{name: CCC, age: 4}, Dog{name: DDD, age: 1}]
排序后:[Dog{name: DDD, age: 1}, Dog{name: BBB, age: 2}, Dog{name: AAA, age: 3}, Dog{name: CCC, age: 4}]
compare方法与compareTo方法类似,都是根据返回值进行排序。
为了方便,也可以采用匿名类或者lambda的方式:
Arrays.sort(dogs, new Comparator<Dog>() {
@Override
public int compare(Dog d1, Dog d2) {
return d1.getAge() - d2.getAge();
}
});
// 或者
Arrays.sort(dogs, (d1, d2) -> d1.getAge() - d2.getAge());
2.3 Comparator 和 Comparable 区别
- 内部比较器 Comparable 是排序接口,只包含一个函数 compareTo();若一个类实现了 Comparable 接口,就意味着 “该类支持排序”,它可以直接通过 () 或 () 进行排序。
- 外部比较器 Comparator 是比较器接口,单独实现一个比较器,不需要对原来的类进行结构上的变化,属于无侵入式的;一个类实现了 Comparator 接口,那么它就是一个 “比较器”。其它的类,可以根据该比较器去排序。