测试java的比较方法可以分为四种:==, equals(), compareTo(), compare()
这些方法对于初学者来说,大多数人总是傻傻分不清楚,那么它们都有是么区别呢?
对于==,相信大家非常熟悉,几乎日常写代码都或多或少会用到,那么你真的清楚它的底层逻辑吗?
对于数值型基本数据类型,==比较的是存储在栈中的值。
测试代码:
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");
}
}
}
对于引用类型的数据,等号比较的两个变量中存放的地址是否相同。
测试代码:
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
}
}
所以,对于基本数据类型,我们提倡使用==来进行比较。
在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()方法进行比较。
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);
}
}
}
运行结果:
注意:
Comparable
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);
}
}
}
运行结果:
注意:
Comparator
==:适用于数值存储在栈中的基本数据类型的值比较。
equals():适用于引用数据类型的值比较,一般对于自定义类,我们需要手动重写equals()方法,对于包装类直接调用开发者提供好的重写equals()方法即可。
comparaTo():这个排序被称为类的自然顺序(实体类内实现),提供方法的接口是Comparable
Compare():这个排序是定制排序(无法修改实体类时,直接在调用方创建)。提供方法的接口是Comparator
文章借鉴:
java中Comparable讲解_bug_Cat的博客-CSDN博客
Java 解惑:Comparable 和 Comparator 的区别 - 知乎 (zhihu.com)