Java~数据结构(六)~Java中对象的比较(基本类型和引用类型分别是如何比较的、Comparator/Comparable接口、hashCode和equals方法等)

30 篇文章 4 订阅
7 篇文章 1 订阅

引入-如果在优先级队列中放入自定义类对象有什么要求?

  • 优先级队列要求:插入的元素不能是null或者元素之间必须能够比较。
  • 如果在优先级队列中插入自定义对象,必须是可以比较的对象。为什么?因为优先级队列底层是用堆实现的,向堆中插入元素,必然是需要上下调整的,如果插入的元素无法比较。会抛出异常。

基本类型的比较(Int,char,boolean等)

  • Java中的基本类型可以直接比较大小。如下
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
public class Compare {
    public static void main(String[] args) {
        int a=10;
        int b=20;
        System.out.println(a>b);
        System.out.println(a<b);
        System.out.println(a==b);
        
        char c1='A';
        char c2='B';
        System.out.println(c1>c2);
        System.out.println(c1<c2);
        System.out.println(c1==c2);
        
        boolean flg1=true;
        boolean flg2=false;
        System.out.println(flg1==flg2);
        System.out.println(flg1!=flg2);
        
    }
}

对象类型的比较

  • 对象类型不能用> < 等比较,但是可以用==比较。
  • 因为自定义类型默认是继承自Object类,而Object类中提供了equals方法,==默认情况下就是调用equals方法。这个方法会比较两个对象的地址来判断是否是同一个对象,不会比较内容。
  • 如果想要比较两个对象的内容是否相等,就必须重写equlas方法。

下面对比着看

1.==和equals()方法

  • ==比较两个对象时,比较的是对象在内存中的地址是否一致,也就是比较两个对象是否为同一个对象。
  • equals()方法可以依据对象的值来判定是否相等。
  • equals方法是Object类中的默认方法,查看Object中equals()的默认实现:
public boolean equals(Object obj){
  return(this == obj);
}
  • 从默认实现中可以看出,没有重写过的equals方法和==是一样的。都是比较两个对象的内存地址。
  • 为什么用equals方法直接比较两个字符串对象可以判断是否相等?因为Java中的String类中重写了equals方法。源代码如下:
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof 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;
}

  • 不仅String类,Java中很多类自身都重写了equals()方法。

重写equals方法使用举例:

public class Student {
    private String name;
    private int age;
    public Student(String name,int age){
        this.name=name;
        this.age=age;
    }

    //重写equals方法。便于比较
    @Override
    public boolean equals(Object obj){
        return true;//我们这样写,就是不管三七二十一,全给返回true
    }

    public static void main(String[] args) {
        Student sn=new Student("zhagnsan",20);
        Student sz=new Student("lisi",18);
        System.out.println(sn.equals(sz)); //true
        System.out.println(sn.equals(" "));//true 无论和什么对象比较都返回true.
    }
}

2.hashCode()方法和equals()方法

  • hashCode()方法是Object类中默认的方法。
  • hashCode()方法的作用是服务于建立在散列表上的类,比如Java集合中的HashMap,HashSet等。hashCode()方法获取对象中的哈希值,通过哈希值来确定对象在哈希表中的索引位置(哈希值本身是一个int型的整数)

举例:

public static void main(String[] args) {
        Student s1=new Student("ss",18);
        Student s2=new Student("zz",19);
        HashSet<Student> stuSet=new HashSet<>();
        stuSet.add(s1);
        stuSet.add(s2);
        System.out.println(s1.equals(s2));
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(stuSet);
    }


true
Student@1b6d3586
Student@4554617c
[Student@4554617c, Student@1b6d3586]

Process finished with exit code 0

  • HashSet集合不会存储重复的对象。按理来说,s1和s2应该是相等的。不应该被重复放进stuSet中,但是结果显示,出现了重复的对象,因为s1和s2的哈希值不同,所以就会被存在HashSet的不同位置。
  • 将对象存储在HashSet时,会先根据对象的哈希值找到相应的索引位置看是否有对象。如果没有就会直接插入,如果有,就会用equals方法来判断位置上的对象与待插入对象是否为相同对象。相同就用新值刷新旧值。不相等就将待插入对象挂在已存在对象的后面。

3.Comparator接口和Comparable接口

  • 重写equals方法可以判断自定义类的对象是否相等,但是无法判断大小。Java中提供了两个接口来实现对象大小的比较。一个是Comparator,一个是Comparable。
Comparable接口
  • 自定类型如果实现了Comparable接口,就表示该类的对象可以进行比较。
  • 实现Comparable接口需要重写其中的compareTo方法。
  • Comparable接口具体实现如下:
public interface Comparable<E>{
// 返回值:
// <0 表示当前对象小于O表示的那个对象
// ==0 表示当前对象和要比较的对象相等
// >0 表示当前对象大于要比较的对象对象
      int compareTo(E o);
}

具体使用:

public class Student implements Comparable<Student>{
    private String name;
    private int age;
    public Student(String name,int age){
        this.name=name;
        this.age=age;
    }
       @Override
       public int compareTo(Student o){
         return this.age<o.age ? -1:(this.age==o.age?0:1);
       }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public static void main(String[] args) {
        Student s1=new Student("ss",18);
        Student s2=new Student("zz",19);
        Student s3=new Student("kk",21);

        TreeSet<Student> stuSet=new TreeSet<>();
        stuSet.add(s1);
        stuSet.add(s2);
        stuSet.add(s3);
        stuSet.forEach(a-> System.out.println(a));
    }
}
  • 重写了ComparaTo方法后,student对象进行比较时,就会按照age的大小进行比较。我们要做的,只是在ComparaTo方法中明确比较的规则。
Comparator接口
  • 实现Comparator接口需要重写其中的compare方法。
public class Student {  
	private String name;
	private int age;

	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	@Override
	public String toString() {
		return "name:"+name + " age:"+age;
	}
	
	public static void main(String[] args) {
	    Student stu1 = new Student("sakuraamy",20);
		Student stu2 = new Student("sakurabob",21);
		Student stu3 = new Student("sakura",19);

		ArrayList<Student> stuList = new ArrayList<>();
		stuList.add(stu1);
		stuList.add(stu2);
		stuList.add(stu3);

    //直接用内部类的的方式实现Comparator接口
		Collections.sort(stuList, new Comparator<Student>() {
			@Override
			public int compare(Student o1, Student o2) {
				return (o1.age<o2.age ? -1 : (o1.age == o2.age ? 0 : 1));
				//return o1.name.compareTo(o2.name);
			}
		});
		System.out.println(stuList);
	}
}


  • 由此可见,实现Comparator接口比实现Comparable接口更简单和灵活。

总结

很多场景需要明确要求两个对象是可以比较的。关于Java中两个对象的比较规则如下:

  • 如果是两个基本类型,可以直接进行> < 和==比较
  • 如果是两个引用类型,不可以直接进行> < 比较,但是可以进行==比较。(默认调用Object中的equals方法)
  • 对于自定义类型,默认是比较地址,比较两个对象是否是同一个对象,如果想要比较内容,需要重写equals方法。
  • 对于自定义类型,若想依据某种规则来比较大小,可以实现Comparable接口或者Comparator接口,前者需要重写compareTo方法,后者需要重写compare方法。后者更灵活一些。

自定义类型也是引用类型,只不过是除了Java本身提供的String这种之外的,你自己定义的,比如Student类

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值