大杂烩 -- equals、hashCode联系与区别

基础大杂烩 -- 目录

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 

Equals

1、默认情况(没有覆盖equals方法)下equals方法都是调用Object类的equals方法,而Object的equals方法主要用于判断对象的内存地址引用是不是同一个地址(是不是同一个对象)。

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

2 、如果类中覆盖了equals方法,那么就要根据具体的代码来确定equals方法的作用了,覆盖后一般都是通过对象的内容是否相等来判断对象是否相等。

    @Override
    public boolean equals(Object obj) {
        // 1.地址相等
        if (this == obj)
            return true;
        // 2.不为空
        if (obj == null)
            return false;
        // 3.类型相同
        if (getClass() != obj.getClass())
            return false;
        StudentOverrideEquals other = (StudentOverrideEquals) obj;
        // 4.属性相等
        if (age != other.age)
            // 4.1基本数据类型判断值
            return false;
        // 4.2引用数据类型。1.空值判断,2.非空调用自身equals()
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

HashCode

1.默认情况(没有覆盖hashCode方法)下hashCode方法都是调用Object类的hashCode方法,而Object的hashCode方法的返回值的默认实现是根据对象的内存地址进行计算。

    public native int hashCode();

2.如果类中覆盖了hashCode方法,那么就要根据具体的代码来确定hashCode方法的返回值,覆盖后一般都是通过对象的属性计算hashCode值。

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

 

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 

不覆写equals、不覆写hashCode(Tt02)

   覆写equals、不覆写hashCode(Tt03)

不覆写equals、   覆写hashCode(Tt04)

   覆写equals、   覆写hashCode(Tt05)

   覆写equals、   覆写hashCode(返回值不同)(Tt06)

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 

 

Tt02:不覆写equals、不覆写hashCode

Class : Student

package limeMianShi.duolaidian.equals_hashcode;

/**
 * 没有覆盖equals、hashCode方法
 * 
 * @author lime
 *
 */
public class Student {

    private String name;
    private int age;
    public Student() {
        super();
    }
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    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;
    }
    
}

Class : main

package limeMianShi.duolaidian.equals_hashcode;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * 没有覆盖equals、hashCode方法
 * 
 * @author lime
 *
 */
public class Test02 {

    public static void main(String[] args) {
        List<Student> list = new LinkedList<Student>();
        Set<Student> set = new HashSet<Student>();
        Student stu1 = new Student("lime",25);
        Student stu2 = new Student("lime", 25);
        System.out.println("stu1 == stu2 : "+(stu1 == stu2)); 
        System.out.println("stu1.equals(stu2) : "+stu1.equals(stu2));
        
        System.out.println("stu1-->HashCode:" + stu1.hashCode());
        System.out.println("stu2-->HashCode:" + stu2.hashCode());
        
        list.add(stu1);
        list.add(stu2);
        System.out.println("list size:"+ list.size());
        
        set.add(stu1);
        set.add(stu2);
        System.out.println("set size:"+ set.size());
    }
}

Console : 

stu1 == stu2 : false
stu1.equals(stu2) : false
stu1-->HashCode:1865127310
stu2-->HashCode:515132998
list size:2
set size:2

Tt03:覆写equals、不覆写hashCode

Class : StudentOverrideEquals

package limeMianShi.duolaidian.equals_hashcode;

/**
 * 覆写equals方法
 * 
 * @author lime
 *
 */
public class StudentOverrideEquals {

    private String name;
    private int age;

    public StudentOverrideEquals() {
        super();
    }

    public StudentOverrideEquals(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    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;
    }

    @Override
    public boolean equals(Object obj) {
        // 1.地址相等
        if (this == obj)
            return true;
        // 2.不为空
        if (obj == null)
            return false;
        // 3.类型相同
        if (getClass() != obj.getClass())
            return false;
        StudentOverrideEquals other = (StudentOverrideEquals) obj;
        // 4.属性相等
        if (age != other.age)
            // 4.1基本数据类型判断值
            return false;
        // 4.2引用数据类型。1.空值判断,2.非空调用自身equals()
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

Class : main

package limeMianShi.duolaidian.equals_hashcode;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * 覆写equals方法
 * 
 * @author lime
 *
 */
public class Test03 {

    public static void main(String[] args) {
        List<StudentOverrideEquals> list = new LinkedList<StudentOverrideEquals>();
        Set<StudentOverrideEquals> set = new HashSet<StudentOverrideEquals>();
        StudentOverrideEquals stu1 = new StudentOverrideEquals("lime",25);
        StudentOverrideEquals stu2 = new StudentOverrideEquals("lime", 25);
        System.out.println("stu1 == stu2 : "+(stu1 == stu2)); 
        System.out.println("stu1.equals(stu2) : "+stu1.equals(stu2));
        
        System.out.println("stu1-->HashCode:" + stu1.hashCode());
        System.out.println("stu2-->HashCode:" + stu2.hashCode());
        
        list.add(stu1);
        list.add(stu2);
        System.out.println("list size:"+ list.size());
        
        set.add(stu1);
        set.add(stu2);
        System.out.println("set size:"+ set.size());
    }
}

Console : 

stu1 == stu2 : false
stu1.equals(stu2) : true
stu1-->HashCode:1865127310
stu2-->HashCode:515132998
list size:2
set size:2

Tt04:不覆写equals、覆写hashCode

Class : StudentOverrideHashCode

package limeMianShi.duolaidian.equals_hashcode;


/**
 * 覆盖hashCode方法
 * 
 * @author lime
 *
 */
public class StudentOverrideHashCode {

    private String name;
    private int age;
    public StudentOverrideHashCode(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public StudentOverrideHashCode() {
        super();
    }
    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;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
}

Class : main

package limeMianShi.duolaidian.equals_hashcode;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * 覆写hashCode方法
 * 
 * @author lime
 *
 */
public class Test04 {

    public static void main(String[] args) {
        List<StudentOverrideHashCode> list = new LinkedList<StudentOverrideHashCode>();
        Set<StudentOverrideHashCode> set = new HashSet<StudentOverrideHashCode>();
        StudentOverrideHashCode stu1 = new StudentOverrideHashCode("lime",25);
        StudentOverrideHashCode stu2 = new StudentOverrideHashCode("lime", 25);
        System.out.println("stu1 == stu2 : "+(stu1 == stu2)); 
        System.out.println("stu1.equals(stu2) : "+stu1.equals(stu2));
        
        System.out.println("stu1-->HashCode:" + stu1.hashCode());
        System.out.println("stu2-->HashCode:" + stu2.hashCode());
        
        list.add(stu1);
        list.add(stu2);
        System.out.println("list size:"+ list.size());
        
        set.add(stu1);
        set.add(stu2);
        System.out.println("set size:"+ set.size());
    }
}

Console : 

stu1 == stu2 : false
stu1.equals(stu2) : false
stu1-->HashCode:3323549
stu2-->HashCode:3323549
list size:2
set size:2

Tt05:覆写equals、覆写hashCode

Class : StudentOverrideEqualsHashCode

package limeMianShi.duolaidian.equals_hashcode;

/**
 * 覆盖equals 和 hashCode方法
 * 
 * @author lime
 *
 */
public class StudentOverrideEqualsHashCode {

    private String name;
    private int age;
    public StudentOverrideEqualsHashCode(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public StudentOverrideEqualsHashCode() {
        super();
    }
    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;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        StudentOverrideEqualsHashCode other = (StudentOverrideEqualsHashCode) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

Class : main

package limeMianShi.duolaidian.equals_hashcode;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * 覆写equals、hashCode方法
 * 
 * @author lime
 *
 */
public class Test05 {

    public static void main(String[] args) {
        List<StudentOverrideEqualsHashCode> list = new LinkedList<StudentOverrideEqualsHashCode>();
        Set<StudentOverrideEqualsHashCode> set = new HashSet<StudentOverrideEqualsHashCode>();
        StudentOverrideEqualsHashCode stu1 = new StudentOverrideEqualsHashCode("lime",25);
        StudentOverrideEqualsHashCode stu2 = new StudentOverrideEqualsHashCode("lime", 25);
        System.out.println("stu1 == stu2 : "+(stu1 == stu2)); 
        System.out.println("stu1.equals(stu2) : "+stu1.equals(stu2));
        
        System.out.println("stu1-->HashCode:" + stu1.hashCode());
        System.out.println("stu2-->HashCode:" + stu2.hashCode());
        
        list.add(stu1);
        list.add(stu2);
        System.out.println("list size:"+ list.size());
        
        set.add(stu1);
        set.add(stu2);
        System.out.println("set size:"+ set.size());
    }
}

Console : 

stu1 == stu2 : false
stu1.equals(stu2) : true
stu1-->HashCode:3323549
stu2-->HashCode:3323549
list size:2
set size:1

Tt05:覆写equals、覆写hashCode(返回值不同)

Class : StudentOverrideEqualsHashCodeneq

package limeMianShi.duolaidian.equals_hashcode;

/**
 * equals 相等,hashCode不等
 * 
 * @author lime
 *
 */
public class StudentOverrideEqualsHashCodeneq {

    private String name;
    private int age;
    public StudentOverrideEqualsHashCodeneq(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public StudentOverrideEqualsHashCodeneq() {
        super();
    }
    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;
    }
    @Override
    public int hashCode() {
        return (int) (Math.random()*10);
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        StudentOverrideEqualsHashCodeneq other = (StudentOverrideEqualsHashCodeneq) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

Class : main

package limeMianShi.duolaidian.equals_hashcode;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * 覆写equals、hashCode(返回值不同)方法
 * 
 * @author lime
 *
 */
public class Test06 extends Object{

    public static void main(String[] args) {
        List<StudentOverrideEqualsHashCodeneq> list = new LinkedList<StudentOverrideEqualsHashCodeneq>();
        Set<StudentOverrideEqualsHashCodeneq> set = new HashSet<StudentOverrideEqualsHashCodeneq>();
        StudentOverrideEqualsHashCodeneq stu1 = new StudentOverrideEqualsHashCodeneq("lime",25);
        StudentOverrideEqualsHashCodeneq stu2 = new StudentOverrideEqualsHashCodeneq("lime", 25);
        System.out.println("stu1 == stu2 : "+(stu1 == stu2)); 
        System.out.println("stu1.equals(stu2) : "+stu1.equals(stu2));
        
        System.out.println("stu1-->HashCode:" + stu1.hashCode());
        System.out.println("stu2-->HashCode:" + stu2.hashCode());
        
        list.add(stu1);
        list.add(stu2);
        System.out.println("list size:"+ list.size());
        
        set.add(stu1);
        set.add(stu2);
        System.out.println("set size:"+ set.size());
    }
}

Console : 

stu1 == stu2 : false
stu1.equals(stu2) : true
stu1-->HashCode:1
stu2-->HashCode:6
list size:2
set size:2

Tt07:覆写equals、覆写hashCode(修改属性值,改变hashCode,remove)

Class :StudentOverrideEqualsHashCode

package limeMianShi.duolaidian.equals_hashcode;

/**
 * 覆盖equals 和 hashCode方法
 * 
 * @author lime
 *
 */
public class StudentOverrideEqualsHashCode {

    private String name;
    private int age;
    public StudentOverrideEqualsHashCode(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public StudentOverrideEqualsHashCode() {
        super();
    }
    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;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        StudentOverrideEqualsHashCode other = (StudentOverrideEqualsHashCode) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

Class : main

package limeMianShi.duolaidian.equals_hashcode;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * 覆写equals、hashCode方法。修改参与计算hashCode的属性
 * 
 * @author lime
 *
 */
public class Test07{

    public static void main(String[] args) {
        List<StudentOverrideEqualsHashCode> list = new LinkedList<StudentOverrideEqualsHashCode>();
        Set<StudentOverrideEqualsHashCode> set = new HashSet<StudentOverrideEqualsHashCode>();
        StudentOverrideEqualsHashCode stu1 = new StudentOverrideEqualsHashCode("lime",25);
        StudentOverrideEqualsHashCode stu2 = new StudentOverrideEqualsHashCode("lime", 25);
        System.out.println("stu1 == stu2 : "+(stu1 == stu2)); 
        System.out.println("stu1.equals(stu2) : "+stu1.equals(stu2));
        
        System.out.println("stu1-->HashCode:" + stu1.hashCode());
        System.out.println("stu2-->HashCode:" + stu2.hashCode());
        
        list.add(stu1);
        list.add(stu2);
        System.out.println("list size:"+ list.size());
        
        set.add(stu1);
        set.add(stu2);
        System.out.println("set size:"+ set.size());
        
        System.out.println("修改stu1的name");
        stu1.setName("oracle");
        System.out.println("stu1-->HashCode:" + stu1.hashCode());
        set.remove(stu1);
        System.out.println("set size:"+ set.size());
    }
}

Console : 

stu1 == stu2 : false
stu1.equals(stu2) : true
stu1-->HashCode:3323549
stu2-->HashCode:3323549
list size:2
set size:1
修改stu1的name
stu1-->HashCode:-1008860090
set size:1

结果分析:

set添加元素时,首先判断hashCode一致,在判断equals一致。

set移除元素时,首先判断hashCode一致,根据hashCode移除元素。

当我们将某个对象存到set中时,如果该对象的属性参与了hashcode的计算,那么以后就不能修改该对象参与hashcode计算的那些属性了,否则会引起意向不到的错误的。正如测试中,不能够移除stu1对象。

hashSet本质是封装hashMap

package java.util;

import java.io.InvalidObjectException;

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable{

    static final long serialVersionUID = -5024744406713321676L;

    private transient HashMap<E,Object> map;

    private static final Object PRESENT = new Object();

    public HashSet() {
        map = new HashMap<>();
    }

    public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }

    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
    }

    public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }

    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }

    public Iterator<E> iterator() {
        return map.keySet().iterator();
    }

    public int size() {
        return map.size();
    }

    public boolean isEmpty() {
        return map.isEmpty();
    }

    public boolean contains(Object o) {
        return map.containsKey(o);
    }

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }

    public void clear() {
        map.clear();
    }

    @SuppressWarnings("unchecked")
    public Object clone() {
        try {
            HashSet<E> newSet = (HashSet<E>) super.clone();
            newSet.map = (HashMap<E, Object>) map.clone();
            return newSet;
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }
    }

    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        s.defaultWriteObject();

        s.writeInt(map.capacity());
        s.writeFloat(map.loadFactor());

        s.writeInt(map.size());

        for (E e : map.keySet())
            s.writeObject(e);
    }

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();

        int capacity = s.readInt();
        if (capacity < 0) {
            throw new InvalidObjectException("Illegal capacity: " + capacity);
        }

        float loadFactor = s.readFloat();
        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
            throw new InvalidObjectException("Illegal load factor: " +
                                             loadFactor);
        }

        int size = s.readInt();
        if (size < 0) {
            throw new InvalidObjectException("Illegal size: " +
                                             size);
        }

        capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f), HashMap.MAXIMUM_CAPACITY);

        map = (((HashSet<?>)this) instanceof LinkedHashSet ?
               new LinkedHashMap<E,Object>(capacity, loadFactor) :
               new HashMap<E,Object>(capacity, loadFactor));

        for (int i=0; i<size; i++) {
            @SuppressWarnings("unchecked")
                E e = (E) s.readObject();
            map.put(e, PRESENT);
        }
    }

    public Spliterator<E> spliterator() {
        return new HashMap.KeySpliterator<E,Object>(map, 0, -1, 0, 0);
    }
}

set-->add:

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

set-->remove : 

    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }
    public V remove(Object key) {
        Node<K,V> e;
        return (e = removeNode(hash(key), key, null, false, true)) == null ?
            null : e.value;
    }

总结:

1、equals方法用于比较对象的内容是否相等(覆盖以后)

2、hashcode方法只有在集合中用到

3、当覆盖了equals方法时,比较对象是否相等将通过覆盖后的equals方法进行比较(判断对象的内容是否相等)。

4、将对象放入到集合中时,首先判断要放入对象的hashcode值与集合中的任意一个元素的hashcode值是否相等,如果不相等直接将该对象放入集合中。如果hashcode值相等,然后再通过equals方法判断要放入对象与集合中的任意一个对象是否相等,如果equals判断不相等,直接将该元素放入到集合中,否则不放入。

5、将元素放入集合的流程图:

 

啦啦啦

啦啦啦

posted @ 2017-06-14 12:24  limeOracle  阅读(288)  评论(0编辑  收藏  举报