一、问题背景
我们先来看这样一个背景,如果有一个学生类,成员属性有姓名name(String),年龄age(int),分数score(double).
public class Test {
class student{
String name;
int age;
double score;
public student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}
}
那么我们如果想要比较相关学生的年龄该如何比较呢?如果想寻找分数相同的同学我们该如何去寻找呢?这就涉及到java里面对象的比较
二、基本类型的比较
java中 == 、>、<可以用于直接比较基本数据类型数值的大小,实际上 == 这个符号可以用于比较时,主要有三种形式
- " =="既可以判断基本类型(基本数据类型里面没有String),又可以判断引用类型,当左右两边都是引用类型时,比较的实际上是两个引用的地址,当两边是基本类型的时候,那么实际上比较的是数值。
- "=="如果判断基本类型,判断的是值是否相等。eg: int i=10;double d=10.0 ;i == d;//正确
- "=="如果判断引用类型,断的是地址是否相等,即判定是不是同一个对象。
示例
public static void main(String[] args) {
int a = 10;
int b = 20;
double a1 = 10.0;
System.out.println(a > b);
System.out.println(a == b);
System.out.println(a == a1);
char c1 = 'A';
char c2 = 'B';
System.out.println(c1 > c2);
System.out.println(65 == c1);
System.out.println(c1 == c2);
boolean b1 = true;
boolean b2 = false;
System.out.println(b1 == b2);
System.out.println(b1 != b2);
}
student student1 = new student("zhangsan", 1, 10.0);
student student2 = new student("lisi", 2, 11.0);
student student3 = new student("wangwu", 3, 10.0);
student student4 = new student("zhaoliu", 4, 12.0);
student student5 = student1;
System.out.println(student1 == student5);//true,student1与student5指向用一个对象,所以引用是同一个
student student6 = new student("zhangsan", 1, 10.0);
System.out.println(student1 == student6);//false,student1与student5指向不同对象
System.out.println(student1>student2);//编译错误
Java中引用类型的变量不能直接按照 > 或者 < 方式进行比较。 那为什么= =可以比较?
因为:对于用户实现自定义类型,都默认继承自Object类,而Object类中提供了equal方法,而==默认情况下调用的就是equal方法,但是该方法的比较规则是:没有比较引用变量引用对象的内容,而是直接比较引用变量的地址,但有些情况下该种比较就不符合题意。
下面代码就是java原生object类里的eques
// Object中equal的实现,可以看到:直接比较的是两个引用变量的地址
public boolean equals(Object obj) {
return (this == obj);
}
三、对象的比较
3.1覆写(重写)eques方法
一般覆写 equals 的套路应该有以下步骤
- 如果指向同一个对象,返回 true
- 如果传入的为 null,返回 false
- 如果传入的对象类型不是 Card,返回 false
- 按照类的实现目标完成比较,例如这里只要花色和数值一样,就认为是相同的牌
- 注意下调用其他引用类型的比较也需要 equals,例如下面代码里的 name 的比较覆写
- 基类equal的方式虽然可以比较,但缺陷是:equal只能按照相等进行比较,不能按照大于、小于的方式进行比较。
示例
@Override
public boolean equals(Object o) {
if (this == o) return true;//如果两个是同一个对象,那么返回true;
if (o == null || getClass() != o.getClass()) return false;// o如果是null对象,或者o和引用类型不是同一个类
//if(o == null || !(o instanceof student)){
// return false;
// }//也可以这样写
student student = (student) o;//object类是所有类型的父类,所以要是想取得o里面的成员属性,需要向下转型
return age == student.age && Double.compare(student.score, score) == 0 && this.name.equals(student.name);
}
3.2 基于Comparble接口类的比较
Comparble是JDK提供的泛型的比较接口类,源码实现具体如下:
public interface Comparable<E> {
// 返回值:
// < 0: 表示 this 指向的对象小于 o 指向的对象
// == 0: 表示 this 指向的对象等于 o 指向的对象
// > 0: 表示 this 指向的对象大于 o 指向的对象
int compareTo(E o);
}
比如在上面的代码里,在比较score大小时就调用了原生Double类型里面的compare方法(Double实现了Compable接口)
对用用户自定义类型,如果要想按照大小与方式进行比较时:在定义类时,实现Comparble接口即可,然后在类中重写compareTo方法。
示例
public class Test {
static class student implements Comparable<student>{
String name;
int age;
double score;
public student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public int compareTo(student o) {
return this.age-o.age;
}
}
3.3 基于比较器比较
用户自定义比较器类,实现Comparator接口
public interface Comparator<T> {
// 返回值:
// < 0: 表示 o1 指向的对象小于 o2 指向的对象
// == 0: 表示 o1 指向的对象等于 o2 指向的对象
// > 0: 表示 o1 指向的对象等于 o2 指向的对象
int compare(T o1, T o2);
}
示例:
import java.util.Comparator;
class Card {
public int rank; // 数值
public String suit; // 花色
public Card(int rank, String suit) {
this.rank = rank;
this.suit = suit;
}
}
class CardComparator implements Comparator<Card> {
// 根据数值比较,不管花色
// 这里我们认为 null 是最小的
@Override
public int compare(Card o1, Card o2) {
if (o1 == o2) {
return 0;
}
if (o1 == null) {
return -1;
}
if (o2 == null) {
return 1;
}
return o1.rank - o2.rank;
}
public static void main(String[] args){
Card p = new Card(1, "♠");
Card q = new Card(2, "♠");
Card o = new Card(1, "♠");
// 定义比较器对象
CardComparator cmptor = new CardComparator();
// 使用比较器对象进行比较
System.out.println(cmptor.compare(p, o)); // == 0,表示牌相等
System.out.println(cmptor.compare(p, q)); // < 0,表示 p 比较小
System.out.println(cmptor.compare(q, p)); // > 0,表示 q 比较大
}