Java自定义排序用法
在Java中,我们可以使用自定义排序来对对象或数组进行排序。这可以通过实现 Comparator 接口或使用 Comparable 接口来实现。下面是两种方法的示例:
1.使用 Comparator 接口(常用)
当我们需要以不同的方式比较两个对象时,可以使用 Comparator
接口来实现自定义排序。这个接口有一个方法 compare(T o1, T o2)
,它接收两个泛型参数 T,并返回一个 int 类型的值。这个返回值指示了两个对象的大小关系,具体含义如下:
- 如果返回值为负数,则表示
o1
小于o2
——不交换 - 如果返回值为零,则表示
o1
等于o2
——不交换 - 如果返回值为正数,则表示
o1
大于o2
——交换
当使用排序算法(如 Arrays.sort()
或 Collections.sort()
)时,它们会根据 Comparator
的比较结果来决定是否交换两个元素的位置。如果返回值为负数或零,表示元素顺序已经符合要求,不需要交换;如果返回值为正数,表示元素顺序需要交换,算法会进行交换操作。
例如,在以下代码中:
Arrays.sort(array, new Comparator<Integer>() {@Overridepublic int compare(Integer num1, Integer num2) {return num1 - num2; // 升序排序}
});
如果 compare()
方法返回负数,则表示 num1
小于 num2
,这时不会交换它们的位置。如果返回正数,则表示 num1
大于 num2
,算法会交换它们的位置。
需要注意的是,如果直接返回 num1 - num2
,可能会导致整数溢出问题。为了避免这个问题,可以使用 Integer.compare(num1, num2)
方法,它会考虑到溢出情况,返回正确的比较结果。
Integer.compare(num1, num2)
方法是一个静态方法,用于比较两个整数的大小。它返回一个 int 值。
在排序算法中,当使用 Integer.compare(num1, num2)
方法作为比较器时,根据返回值的不同,交换的情况如下:
- 如果返回值为负数,则表示
num1
小于num2
,此时不进行交换。 - 如果返回值为零,则表示
num1
等于num2
,也不进行交换。 - 如果返回值为正数,则表示
num1
大于num2
,此时会进行交换。
需要注意的是,Integer.compare(num1, num2)
方法会考虑到整数溢出的情况,因此可以安全地使用该方法进行比较。
Arrays.sort(array, new Comparator<Integer>() {@Overridepublic int compare(Integer num1, Integer num2) {return Integer.compare(num1, num2); // 升序排序}
});
下面是三个不同的例子,用来说明如何使用 Comparator 接口进行自定义排序:
(1) 根据字符串长度排序
在这个例子中,我们将按照字符串长度对字符串数组进行排序。短字符串排在前面,长字符串排在后面。
import java.util.Arrays; // 导入Arrays类,提供了数组相关的工具方法
import java.util.Comparator; // 导入Comparator接口,该接口定义了比较两个对象的方法。public class Main {public static void main(String[] args) {String[] strings = {"aaa", "bb", "c", "dddd"}; // 定义一个字符串数组// 使用Arrays.sort方法对字符串数组进行排序,第二个参数是一个Comparator接口实现类的实例,// 匿名内部类方式实现了Comparator接口,定义比较方法compare,比较规则为比较两个字符串长度大小。Arrays.sort(strings, new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {return s1.length() - s2.length();}});System.out.println(Arrays.toString(strings)); // 打印排序后的字符串数组}
}==========================================================================
import java.util.Arrays;
import java.util.Comparator;public class Main {public static void main(String[] args) {String[] strings = {"aaa", "bb", "c", "dddd"};// 使用Lambda表达式替换匿名内部类实现Comparator接口Arrays.sort(strings, (s1, s2) -> s1.length() - s2.length());System.out.println(Arrays.toString(strings));}
}
在这个例子中,我们使用了匿名内部类来实现 Comparator
接口,并在其中重写了 compare()
方法。
该方法根据字符串的长度进行排序。最后,我们使用 Arrays.sort()
方法对字符串数组进行排序,并输出排序后的结果。
(2) 根据字符串长度和字典序排序
在这个例子中,我们将按照字符串长度和字典序对字符串数组进行排序。短字符串排在前面,长字符串排在后面,如果长度相等,则按照字典序排序。
import java.util.Arrays; // 导入Arrays类,提供了数组相关的工具方法
import java.util.Comparator; // 导入Comparator接口,该接口定义了比较两个对象的方法。public class Main {public static void main(String[] args) {String[] strings = {"aaa", "cc", "bb", "a"}; // 定义一个字符串数组// 使用Arrays.sort方法对字符串数组进行排序,第二个参数是一个Comparator接口实现类的实例,// 匿名内部类方式实现了Comparator接口,定义比较方法compare,比较规则为先比较字符串长度,长度相等时再比较字典序。Arrays.sort(strings, new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {int lenComp = s1.length() - s2.length(); // 比较字符串长度if (lenComp != 0) { // 如果长度不等,则返回长度差值return lenComp;} else { // 如果长度相等,则返回字典序比较结果return s1.compareTo(s2);}}});System.out.println(Arrays.toString(strings)); // 打印排序后的字符串数组}
}
============================================================================
import java.util.Arrays;public class Demo02 {public static void main(String[] args) {String[] strings = { "aaa", "cc", "bb", "a" };// 使用Lambda表达式对字符串数组进行排序Arrays.sort(strings, (s1, s2) -> {int lenComp = s1.length() - s2.length();if (lenComp != 0) {return lenComp;} else {return s1.compareTo(s2);}});System.out.println(Arrays.toString(strings));}
}
在这个例子中,我们同样使用了匿名内部类来实现 Comparator
接口。首先,我们按照字符串的长度进行比较,如果长度相等,则再按照字典序进行比较。最后,我们使用 Arrays.sort()
方法对字符串数组进行排序,并输出排序后的结果。
Tips:
compareTo
是Java中String类的一个方法,用于比较两个字符串的大小关系。
s1.compareTo(s2) 的作用是比较字符串s1和s2的字典序(按照字符的Unicode码值进行比较)。
例如,如果s1是"aaa",s2是"aaab",那么s1.compareTo(s2)将返回一个负数,表示s1在s2之前。
需要注意的是,compareTo方法要求两个字符串必须是非空的,否则可能会抛出空指针异常。因此,在实际使用时,需要确保s1和s2都不为null。
(3)根据对象属性排序
在这个例子中,我们将按照人物的年龄对人物数组进行排序。年龄小的人排在前面,年龄大的人排在后面。
import java.util.Arrays;
import java.util.Comparator;class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}
}public class Main {public static void main(String[] args) {Person[] people = {new Person("卡卡罗特", 25),new Person("贝吉塔", 20),new Person("龟仙人", 30)};Arrays.sort(people, new Comparator<Person>() {@Overridepublic int compare(Person p1, Person p2) {return p1.getAge() - p2.getAge();}});for (Person person : people) {System.out.println(person.getName() + " - " + person.getAge());}}
}贝吉塔- 20
卡卡罗特 - 25
龟仙人 - 30=============================================================================
public class Demo03 {public static void main(String[] args) {Person[] people = {new Person("Alice", 25),new Person("Bob", 20),new Person("Charlie", 30)};// 使用Lambda表达式替换匿名内部类实现Comparator接口Arrays.sort(people, (p1, p2) -> p1.getAge() - p2.getAge());for (Person person : people) {System.out.println(person.getName() + " - " + person.getAge());}}
}
在这个例子中,我们定义了一个 Person
类,并创建了一个 Person
对象数组。然后,我们使用匿名内部类来实现 Comparator
接口,并在其中重写了 compare()
方法。该方法根据人物的年龄进行比较。最后,我们使用 Arrays.sort()
方法对人物数组进行排序,并输出排序后的结果。
以上就是三个例子,它们展示了如何在 Java 中使用 Comparator 接口进行自定义排序。
2.使用 Comparable 接口
import java.util.Arrays;class Person implements Comparable<Person> {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic int compareTo(Person other) {// 按照年龄进行比较return this.age - other.age;}
}public class Demo04 {public static void main(String[] args) {Person[] people = {new Person("Alice", 25),new Person("Bob", 20),new Person("Charlie", 30)};Arrays.sort(people);for (Person person : people) {System.out.println(person.getName() + " - " + person.getAge());}}
}
使用Comparable接口主要适用于单一的比较规则,而Comparator接口对于需要多种或动态比较规则的情况更为常用。