Java的比较机制

测试java的比较方法可以分为四种:==, equals(), compareTo(), compare() 

这些方法对于初学者来说,大多数人总是傻傻分不清楚,那么它们都有是么区别呢?

1.==:

对于==,相信大家非常熟悉,几乎日常写代码都或多或少会用到,那么你真的清楚它的底层逻辑吗?

(1)基本数据类型:

对于数值型基本数据类型,==比较的是存储在栈中的值。

测试代码:

public class Test {
    public static void main(String[] args) {
        int a = 10;
        int b = 10;
        if (a > b){
            System.out.println("a > b");
        } else if (a == b) {
            System.out.println("a = b");
        }else {
            System.out.println("a < b");
        }
    }
}

Java的比较机制_第1张图片Java的比较机制_第2张图片

(2)引用数据类型:

对于引用类型的数据,等号比较的两个变量中存放的地址是否相同。

测试代码:

public class Test {
    public static void main(String[] args) {
        
        String str1="abc"; // 创建引用str1,在字符串常量池里面创建"abc"
        String str2="abc"; // 创建引用str2,"abc"在字符串常量池里已存在,不创建,直接返回串池中"abc"的地址
        String str3=new String("abc"); // 创建引用str3,把字符串常量池的字符串"abc"复制到堆中
        System.out.println(str1==str2); // true
        System.out.println(str1==str3); // false
    }
}

Java的比较机制_第3张图片

所以,对于基本数据类型,我们提倡使用==来进行比较。

2.equals():

在Object类中定义了一个equals的方法,equals的源码是这样写的:

public boolean equals(Object obj) {       
    return (this == obj);
}

可以看到,这个方法的初始默认行为是比较对象的内存地址值,嗯......这么看来这个方法好像有点多余。所以,在一些类库当中这个方法被重写了。

对于包装类,如String,Integer等等,一般有提供重写了的equals(Object anObject)方法。

/* java.lang.String代码片段--equals()方法 */
public boolean equals(Object anObject) {
        if (this == anObject) { // 判断引用地址是否相同
            return true; 
        }
        if (anObject instanceof String) { // 判断anObject是否是String实例
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) { // 判断字符串长度是否相同
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) { // 判断字符串中的字符是否相同一一对应
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

测试代码: 

public class Test {
    public static void main(String[] args) {
        String str1="abc"; // 创建引用str1,在字符串常量池里面创建"abc"
        String str2="abc"; // 创建引用str2,"abc"在字符串常量池里已存在,不创建,直接返回串池中"abc"的地址
        String str3=new String("abc"); // 创建引用str3,把字符串常量池的字符串"abc"复制到堆中
        System.out.println(str1.equals(str2)); // true
        System.out.println(str1.equals(str3)); // true

    }
}

所以在一些自定义类或者包装类中,我们通常推荐使用重写的equals()方法进行比较。

3.compareTo()方法:

compareTo()方法由Comparable接口提供,要想调用这个方法,我们需要实现这个接口。Comparable是排序接口,若一个类实现了Comparable接口,就意味着这个类支持排序,而且这个排序被称为类的自然顺序(实体类实现)。

这个类的对象的列表可以被Collections.sort和Arrays.sort来执行排序。同时这个类的实例具备作为sorted map的key和sorted set的元素的资格,所以,例如TresSet实现了SortSet的子接口,如果TresSet想要存储自定义的程序类,就必须手动实现Comparable接口。

假如说我们有这样一个需求,需要设计一个Goods(物品)类,有两个属性:名称(name)、价格(price),按照价格的大小进行排序,那么实现可以这样:

public class Goods implements Comparable{
    private String name;
    private int price;

    public Goods(String name, int price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String toString() {
        return "goods{name:"+this.name+"price:"+this.price+"}";
    }

    @Override
    public int compareTo(Goods o) {
        // 通过比较价格实现比较物品
        if (this.price > o.price) {
            return 1;
        } else{
            return -1;
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

/*
 *测试类
 */
public class Test {
    public static void main(String[] args) {
        Goods[] goods={
                new Goods("水杯",25),
                new Goods("台灯",49),
                new Goods("拖鞋",19)
        };
        Arrays.sort(goods);
        for (Goods good : goods) {
            System.out.println(good);
        }
    }
}

 运行结果:

Java的比较机制_第4张图片

注意:

Comparable接口里面有一个泛型T,T的选择为可以与之比较的对象的类型,一般就是实现该接口类的本身,可以这样想和Goods类比较的当然是Goods本身了,所以class Goods implements Comparable

4.Compare()方法

Compare()是Comparator接口提供的一个方法。

Comparator也是一个比较器,但是属于挽救设计的一种,Comparator 是定制排序。(无法修改实体类时,直接在调用方创建),一般来说尽量减少。

适用场景: 别人向我们提供一个类,这个类没有事先实现Comparable接口,如果在不允许改变源代码的情况下,我们可以使用Comparator接口。

别人提供的类:

/**
 * 别人提供好的类,不能修改
 */
public final class Goods {
    private String name;
    private int price;

    public Goods(String name, int price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String toString() {
        return "goods{name:"+this.name+"price:"+this.price+"}";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

我们自己实现一个比较器GoodsComparator:

public class GoodsComparator implements Comparator {
    @Override
    public int compare(Goods o1, Goods o2) {
        return Integer.compare(o1.getPrice(), o2.getPrice());
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        Demo2.Goods[] goods={
                new Demo2.Goods("水杯",25),
                new Demo2.Goods("台灯",49),
                new Demo2.Goods("拖鞋",19)
        };
        Arrays.sort(goods,new GoodsComparator()); // 比较对象的集合,比较器
        for (Goods good : goods) {
            System.out.println(good);
        }
    }
}

运行结果:

Java的比较机制_第5张图片

注意:

Comparator泛型模板T为比较器可以比较的对象的类型,如要实现比较Goods,则T为Goods,所以class GoodsComparator implements Comparator

总结:

==:适用于数值存储在栈中的基本数据类型的值比较。

equals():适用于引用数据类型的值比较,一般对于自定义类,我们需要手动重写equals()方法,对于包装类直接调用开发者提供好的重写equals()方法即可。

comparaTo():这个排序被称为类的自然顺序(实体类内实现),提供方法的接口是Comparable

Compare():这个排序是定制排序(无法修改实体类时,直接在调用方创建)。提供方法的接口是Comparator,一般来说尽量减少。

文章借鉴:

java中Comparable讲解_bug_Cat的博客-CSDN博客

Java 解惑:Comparable 和 Comparator 的区别 - 知乎 (zhihu.com)

你可能感兴趣的:(Java进阶,java,开发语言)