HashSet 介绍, equals() 和hashcode()方法介绍

第一点,Set集合中是不允许有重复元素的,
第二点,Set集合中是无顺序的
第三点:
* 为什么 add方法在添加String类型和普通的对象Person的时候结果不太一样,在它的帮助文档中是这样解释的
* //Adds the specified element to this set if it is not already present. More formally,
* adds the specified element e to this set if this set contains no element e2
* such that (e==null ? e2==null : e.equals(e2)).
* If this set already contains the element, the call leaves the set unchanged and returns false.
可以看到,对于增加一个非空对象e,首先要保证集合中不存在一个对象,其地址和e相同,同时要满足在存在的集合中不存在e2 使得 e.equals(e2)成立,
那么这个就可以解释了,对于String对象,equals方法比较的是内容,所以只有一个a被添加到set中
对于Person对象,equals方法比较的是地址,所以两个对象都会被添加到Set中
*/

关于第三点的更详细的原理解释:
当使用HashSet 时,hashCode()方法就会得到调用,判断已经存储在集合中的对象的hash code 值是否与增加的对象的 hash code 值一致;如果不一致,直接加进去;如果一致,再进行 equals 方法的比较,equals 方法如果返回 true,表示对象已经加进去了,就不会再增加新的对象,否则加进去

// 举几个例子更加了解上面说的几点

import java.util.HashSet;

public class HashSetTest {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet(); 
        // 第一点,Set集合中是不允许有重复元素的,
        // 第二点,Set集合中是无顺序的
        hashSet.add("a");
        hashSet.add("b");
        hashSet.add("c");
        hashSet.add("d");
        hashSet.add("a");
        System.out.println(hashSet); // d b c a
        /*第三点:
         * 为什么 add方法在添加String类型和普通的对象Person的时候结果不太一样,在它的帮助文档中是这样解释的
         * //Adds the specified element to this set if it is not already present. More formally, 
         * adds the specified element e to this set if this set contains no element e2 
         * such that (e==null ? e2==null : e.equals(e2)). 
         * If this set already contains the element, the call leaves the set unchanged and returns false.
          可以看到,对于增加一个非空对象,首先要保证两个对象的地址是不一致的才能添加,
          同时要满足在存在的集合中不存在e2  使得 e.equals(e2)成立,
          那么这个就可以解释了,对于String对象,equals方法比较的是内容,所以只有一个a被添加到set中
          对于Person对象,equals方法比较的是地址,所以两个对象都会被添加到Set中
         */

        /*
         * 当使用HashSet 时,hashCode()方法就会得到调用,判断已经存储在集合中的对象的hash code 值
         * 是否与增加的对象的 hash code 值一致;如果不一致,直接加进去;
         * 如果一致,再进行 equals 方法的比较,equals 方法如果返回 true,
         * 表示对象已经加进去了,就不会再增加新的对象,否则加进去
         */
        //对于String类型,它重写了hashCode()方法, 它的hashcode值的计算方法如下:
//      The hash code for a String object is computed as 
//       s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

        hashSet.clear();
        String s1= new String("a");
        String s2=new String("a");
        // 因此在添加String的时候,s1和s2的hashcode值是一样的,之后就回去比较equals方法,也一样,所以不添加
        hashSet.add(s1);
        hashSet.add(s2);
        System.out.println(hashSet); //[a]

        hashSet.clear();
        People people1 =new People("zhangsan");
        People people2 =new People("lisi");
        // 在添加People的时候,people1和people2的hashcode值是不一样的,因此添加到hashSet中去
        hashSet.add(people1);
        hashSet.add(people2);
        System.out.println(hashSet); //[Set.People@3e2de41d, Set.People@36db4bcf]

    }

}

知识点介绍:equals 方法一旦被重写,hashcode方法也一定要被重写,反之亦然。

equals方法的特性:
a) 自反性:x.equals(x)应该返回 true
b) 对称性:x.equals(y)为 true,那么y.equals(x)也为true。
c) 传递性:x.equals(y)为 true 并且y.equals(z)为true,那么 x.equals(z)也应该为 true。
d) 一致性:x.equals(y)的第一次调用为 true,那么 x.equals(y)的第二次、第三次、第 n次调用也应该为true,前提条件是在比较之间没有修改 x 也没有修改 y。
e) 对于非空引用 x,x.equals(null)返回false

hashcode()方法特性:
a) 在 Java 应用的一次执行过程当中,对于同一个对象的 hashCode 方法的多次调用,他们应该返回同样的值(前提是该对象的信息没有发生变化) 。
b) 对于两个对象来说,如果使用equals方法比较返回true,那么这两个对象的hashCode值一定是相同的。
c) 对于两个对象来说,如果使用equals方法比较返回false,那么这两个对象的hashCode值不要求一定不同(可以相同,可以不同) ,但是如果不同则可以提高应用的性能。
d) 对于Object类来说,不同的Object对象的hashCode值是不同的(Object类的hashCode值表示的是对象的地址,它会把地址转化为一个整数) 。

//Object类中你的源代码, native代表着这是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI(java native interface)接口调用其他语言来实现对底层的访问。

public native int hashCode();

// equals方法源代码
    public boolean equals(Object obj) {
        return (this == obj);
    }
// toString() 方法源代码,Object类的toString返回: 类名+@+对象的地址(转化为16进制的整形字符串)
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

如果想实现一个功能:People类根据名字来进行能否加到hashSet中去的一个判断依据, 即如果两个People对象名字相同,那么只能允许一个对象添加到hashSet中去,
实现方法,重写equals和hashCode 方法,记住这两个方法是要一起重写的,一个被重写,另一个也要被重写, 有两种重写方式,一个是自己重写,一个系统自动生成,下面代码中有介绍

class People {
    String name;
    String age;

    public People(String name) {
        // TODO Auto-generated constructor stub
        this.name = name;
    }

    // 可以自己重写方法
    public int hashCode() {
        return this.name.hashCode();
    }
    public boolean equals(Object obj) {
        if (this == obj){  // 判断地址是否相同
            return true;
        }
        if (obj == null){ // 判断是否为空
            return false;
        }
        if (obj instanceof People){  // 是否是People对象
            People people = (People) obj;
            if(this.name.equals(people.name)){
                return true;
            }
        }
        return false;

    }



    // eclipse 提供了自带的生成的办法,方便快捷,通过点击 Source----Generate hashCode() and equals()
//  @Override
//  public int hashCode() {
//      final int prime = 31;
//      int result = 1;
//      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;
//      People other = (People) obj;
//      if (name == null) {
//          if (other.name != null)
//              return false;
//      } else if (!name.equals(other.name))
//          return false;
//      return true;
//  }

}

你可能感兴趣的:(java)