引入的背景
我们知道基本数据类型的数据(除boolean类型外)需要比较大小的话,直接使用比较运算符即可,但是引用数据类型是不能直接使用比较运算符来比较大小的。那么,如何解决这个问题呢?
在Java中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题。
Java实现对象排序的方式有两种:
- 自然排序:java.lang.Comparable
- 定制排序:java.util.Comparator
自然排序:java.lang.Comparable
Comparable接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序。
实现 Comparable 的类必须实现 compareTo(Object obj)
方法,两个对象即通过 compareTo(Object obj) 方法的返回值来比较大小。
如果当前对象this大于形参对象obj,则返回正整数。
如果当前对象this小于形参对象obj,则返回负整数。
如果当前对象this等于形参对象obj,则返回零。
package java.lang;
public interface Comparable{
int compareTo(Object obj);
}
Comparable 的典型实现:(默认都是从小到大排列的
)
- String:按照字符串中字符的Unicode值进行比较
- Character:按照字符的Unicode值来进行比较
- 数值类型对应的包装类以及BigInteger、BigDecimal:按照它们对应的数值大小进行比较
- Boolean:true 对应的包装类实例大于 false 对应的包装类实例
- Date、Time等:后面的日期时间比前面的日期时间大
测试String
代码示例:
@Test
public void test1(){
//测试String已经写好的
String [] a = new String[]{"Jack", "Tom", "Lucy"};
//排序之前
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+"\t");
}
System.out.println();
//使用Arrays进行排序
Arrays.sort(a);
//排序之后进行展示
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+"\t");
}
}
运行效果:
测试自己实现comparable接口
Product类
package cn.edu.chd.exer1;
import java.util.Objects;
public class Product implements Comparable{
private String name;
private double prices;
//无参构造
public Product() {
}
//全参构造
public Product(String name, double prices) {
this.name = name;
this.prices = prices;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrices() {
return prices;
}
public void setPrices(double prices) {
this.prices = prices;
}
@Override
public String toString() {
return "Product{" +
"name='" + name + '\'' +
", prices=" + prices +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product product = (Product) o;
return Double.compare(product.prices, prices) == 0 && name.equals(product.name);
}
@Override
public int hashCode() {
return Objects.hash(name, prices);
}
@Override
public int compareTo(Object o) {
//如果是同一个对象,return 0
if (this == o){
return 0;
}
//两个对象比较的标准是:价格从小到大,价格一样的话,按照名字从小到大
if (o instanceof Product){
Product p = (Product)o;
int v = Double.compare(this.prices, p.prices);
// return v;
if (v != 0){
return v;
}
//价格如果相同,名字按照从小到大
return this.name.compareTo(p.name);
}
//手动抛异常
throw new RuntimeException("类型不匹配");
}
}
测试
//对不同对象的大小进行排序
@Test
public void test2(){
//商品数组
Product[] products = new Product[5];
//全参构造器,在new对象时就对属性进行赋值
products[0] = new Product("Huawei", 5999);
products[1] = new Product("XiaoMi", 4999);
products[2] = new Product("iPhone", 9999);
products[3] = new Product("vivo", 3999);
products[4] = new Product("Honer", 5999);
System.out.println("排序之前");
//排序之前的遍历
for (int i = 0; i < products.length; i++) {
System.out.println(products[i]);
}
System.out.println("----------------------------------------------");
//使用arrays进行排序
Arrays.sort(products);
System.out.println("排序之后");
//排序后的遍历
for (int i = 0; i < products.length; i++) {
System.out.println(products[i]);
}
}
运行效果
定制排序:java.util.Comparator
思考
- 当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码(例如:一些第三方的类,你只有.class文件,没有源文件)
- 如果一个类,实现了Comparable接口,也指定了两个对象的比较大小的规则,但是此时此刻我不想按照它预定义的方法比较大小,但是我又不能随意修改,因为会影响其他地方的使用,怎么办?(例如:我想要String按照字母从大到小的顺序排序,而不是默认的从小到大)
JDK在设计类库之初,也考虑到这种情况,所以又增加了一个java.util.Comparator接口。强行对多个对象进行整体排序的比较。
- 重写compare(Object o1,Object o2)方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。
- 可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。
Product类
package cn.edu.chd.exer2;
import java.util.Objects;
public class Product implements Comparable{
private String name;
private double prices;
//无参构造
public Product() {
}
//全参构造
public Product(String name, double prices) {
this.name = name;
this.prices = prices;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrices() {
return prices;
}
public void setPrices(double prices) {
this.prices = prices;
}
@Override
public String toString() {
return "Product{" +
"name='" + name + '\'' +
", prices=" + prices +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product product = (Product) o;
return Double.compare(product.prices, prices) == 0 && name.equals(product.name);
}
@Override
public int hashCode() {
return Objects.hash(name, prices);
}
@Override
public int compareTo(Object o) {
//如果是同一个对象,return 0
if (this == o){
return 0;
}
//两个对象比较的标准是:价格从小到大,价格一样的话,按照名字从小到大
if (o instanceof Product){
Product p = (Product)o;
int v = Double.compare(this.prices, p.prices);
// return v;
if (v != 0){
return v;
}
//价格如果相同,名字按照从小到大
return this.name.compareTo(p.name);
}
//手动抛异常
throw new RuntimeException("类型不匹配");
}
}
按照商品的价格从低到高排序的comparator
@Test
public void test1(){
//new一个comparator接口的匿名实现类
Comparator comparator = new Comparator() {
//按照商品的价格从低到高排序
@Override
public int compare(Object o1, Object o2) {
if (o1 == o2){
return 0;
}
if (o1 instanceof Product && o2 instanceof Product){
//强转
Product p1 = (Product) o1;
Product p2 = (Product) o2;
return Double.compare(p1.getPrices(), p2.getPrices());
}
throw new RuntimeException("类型不匹配");
}
};
//商品数组
Product[] products = new Product[5];
//全参构造器,在new对象时就对属性进行赋值
products[0] = new Product("Huawei", 5999);
products[1] = new Product("XiaoMi", 4999);
products[2] = new Product("iPhone", 9999);
products[3] = new Product("vivo", 3999);
products[4] = new Product("Honer", 5999);
System.out.println("排序之前");
//排序之前的遍历
for (int i = 0; i < products.length; i++) {
System.out.println(products[i]);
}
System.out.println("----------------------------------------------");
//将comparator对象作为参数进行传入,排序
Arrays.sort(products, comparator);
System.out.println("排序之后");
//排序后的遍历
for (int i = 0; i < products.length; i++) {
System.out.println(products[i]);
}
}
运行效果:
按照名称进行排序的comparator
//按照名称进行排序
@Test
public void test2(){
//new一个comparator接口的匿名实现类
Comparator comparator = new Comparator() {
//按照商品的名称进行排序
@Override
public int compare(Object o1, Object o2) {
if (o1 == o2){
return 0;
}
if (o1 instanceof Product && o2 instanceof Product){
//强转
Product p1 = (Product) o1;
Product p2 = (Product) o2;
return p1.getName().compareTo(p2.getName());
}
throw new RuntimeException("类型不匹配");
}
};
//商品数组
Product[] products = new Product[5];
//全参构造器,在new对象时就对属性进行赋值
products[0] = new Product("Huawei", 5999);
products[1] = new Product("XiaoMi", 4999);
products[2] = new Product("iPhone", 9999);
products[3] = new Product("vivo", 3999);
products[4] = new Product("Honer", 5999);
System.out.println("排序之前");
//排序之前的遍历
for (int i = 0; i < products.length; i++) {
System.out.println(products[i]);
}
System.out.println("----------------------------------------------");
//将comparator对象作为参数进行传入,排序
Arrays.sort(products, comparator);
System.out.println("排序之后");
//排序后的遍历
for (int i = 0; i < products.length; i++) {
System.out.println(products[i]);
}
}