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>() {
@Override
public 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>() {
@Override
public 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>() {
@Override
public 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>() {
@Override
public 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>() {
@Override
public 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;
}
@Override
public 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接口对于需要多种或动态比较规则的情况更为常用。