Object中的方法以及对象相等的判定

看图说话

Object有以下几个方法

  • getClass()

    final类型,主要是用来获得运行时的类型

  • hashCode()

    返回该对象的哈希码值,方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。该方法常用于hash查找,重写equals方法一般都要重写hashCode方法

  • equals()

    equals方法一般和==是不一样的,但是在Object中,两者一样。子类一般都要重写这个方法

  • clone()

    创建并返回对象的副本,它实现对象的浅复制

  • toString()

    返回对象的字符串表示

  • notify()

    唤醒在该对象上等待的某个线程

  • notifyAll()

    唤醒在该对象上等待的所有线程

  • wait()

    wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait方法一直等待,直到获得锁或者被中断。wait(long timeout)设定了一个超时间隔,如果在规定时间没有获得锁就返回。

    调用wait方法后线程进入睡眠状态,直到以下事件发生:

    1. 其他线程调用了该对象的notify/notifyAll方法
    2. 其他线程调用interrupt中断了该线程
    3. 时间间隔到了
  • finalize()

    该方法用于释放资源,当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法

    当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法

判断两个对象是否相等(对象的内容和hashcode必须相等)

1.==和equals区别

  • ==用于判断对象的地址是否相等
  • equals方法也用作判断对象是否相等,有两种情况:
    1. 类没有覆盖equals方法,则当用equals比较该类的两个对象时,相当于调用父类的equals方法,等同于==。
    2. 类覆盖了equals方法,一般会将equals重写成判断两个对象的内容是否相等,如果它们的内容相等,就返回true。

举个例子:

public class Person {
    private int age;
    public Person(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public static void main(String[] args) {
        Person p1 = new Person(10);
        Person p2 = new Person(10);
        String s1 = new String("123");
        String s2 = new String("123");
        System.out.println(p1 .equals(p2));#false
        System.out.println(s1.equals(s2));#true
    }
}

解析

  • 虽然Person对象的内容相等,但是未复写equals方法,执行的还是Object中的equals方法,比较的还是地址
  • String中重写了equals方法,比较的是对象的内容

String中equals源码:

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
    	//判断对象是否是String类型
        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;
    }

2.hashcode与equals的关系

hashcode的作用是用来获取哈希码,也称作散列码。返回的类型是int,用于确定对象在hash表中的位置。Object中有hashcode方法,意味着所有的类都有hashcode方法。

为什么在重写equals方法时,需要重写hashcode方法?

为了提高程序的效率才实现hashCode方法,两个对象在进行比较的时候,如果它们的hashCode不相等,那么就没有必要进行equals方法比较了。

举个例子:在集合中,List集合中的元素是有序的,元素可以重复的;set集合是无序的,元素不能重复。那么如何保证集合里的元素是不能重复的,虽然可以使用equals方法,但是效率太低。假如集合里的元素本来有10000个,那么再新增一个元素,如果一个一个比较,那么效率实在太低。这时候就体现hashcode的优势了,java采用hash表,利用哈希算法,就是将对象数据根据该对象的特征使用特定的算法将其定义到一个地址上,那么在后面定义进来的数据,只要看对应的hashcode地址上是否有值,那么就用equals比较,如果没有则直接插入,只要就大大减少了equals的使用次数,执行效率就大大提高了。

样例,重写了equals方法,没有重写hashcode方法:

public class Person {
    private int age;
    public Person(int age) {
        this.age = age;
    }
	//getter、setter方法略
    @Override
    public boolean equals(Object obj) {
        return true;
    }
    public static void main(String[] args) {
        Person p1 = new Person(10);
        Person p2 = new Person(10);
        System.out.println("p1:"+p1.hashCode());#p1:1163157884
        System.out.println("p2:"+p2.hashCode());#p2:1956725890
        System.out.println(p1 .equals(p2));#true

        HashSet<Object> hashSet = new HashSet<>();
        hashSet.add(p1);
        hashSet.add(p2);
        System.out.println(hashSet);#[Person{age=10}, Person{age=10}]
    }
    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }
}

虽然p1和p2的内容相等,但是我没有重写hashcode方法,所以p1、p2的hashcode不相等;我们知道hashset中不能有相同对象,但是测试用例中竟然有两个同样的Person对象,原因如下:

hashset在添加元素时会做以下判断

  1. 如果添加的元素的hashcode相等并且equals比较时也为true,就认为是同一个元素。
  2. 如果不符合上面的条件,就会认为添加的元素是一个新元素。

样例,简单重写了equals方法和hashcode方法:

public class Person {
    private int age;
    public Person(int age) {
        this.age = age;
    }
	//getter、setter方法略
    @Override
    public boolean equals(Object obj) {
        return true;
    }

    @Override
    public int hashCode() {
        return 0;
    }
    public static void main(String[] args) {
        Person p1 = new Person(10);
        Person p2 = new Person(10);

        System.out.println(p1 .equals(p2));# true
        System.out.println("p1:"+p1.hashCode());# 0
        System.out.println("p2:"+p2.hashCode());# 0
        HashSet<Object> hashSet = new HashSet<>();
        hashSet.add(p1);
        hashSet.add(p2);

        System.out.println(hashSet);#[Person{age=10}]
       
[Person{age=10}]
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }
}

从结果看出,p1、p2的内容相等并且hashcode也相等,hashset中只有一个元素。

小结

  • 如果两个对象相等,则hashcode一定也是相同的
  • 两个对象相等,对两个对象分别调用equals方法都返回true
  • 两个对象有相同的hashcode值,它们也不一定是相等的
  • 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
  • hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

参考

Object有哪些方法

Java中如何判断两个对象是否相等

hashcode和equals

http://www.cnblogs.com/shenliang123/archive/2012/04/16/2452206.html

posted @ 2019-03-28 19:40  小永coding  阅读(1451)  评论(0编辑  收藏  举报