Java基础(三):Java字符串比较之==,equals与 hashCode方法的区别与联系

概述

==: 比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,便是否是指相同一个对象。比较的是真正意义上的指针操做。html

equals:用来比较的是两个对象的内容是否相等,因为全部的类都是继承自java.lang.Object类的,因此适用于全部对象,String中的类是重写了object类里的equal()方法,而在本来的object类中,返回的是==的判断,若是没有对该方法进行覆盖的话,调用的仍然是Object类中的方法。java

hashCode : Object 的 native方法 , 获取对象的哈希值,用于肯定该对象在哈希表中的索引位置,它其实是一个int型整数。算法

关系运算符==

基本数据类型

在Java中有八种基本数据类型:数组

  • 浮点型:float(4 字节), double(8 字节)this

  • 整型:byte(1 字节), short(2 字节), int(4 字节) , long(8 字节)spa

  • 字符型: char(2 字节).net

  • 布尔型: boolean设计

对于这八种基本数据类型的变量,变量直接存储的是“值”,基本数据类型之间的比较须要用双等号(==),由于他们比较的是值指针

引用数据类型

接口、类、数组等非基本数据类型code

Java中的字符串String属于引用数据类型。由于String是一个类

引用类型的变量存储的并非“值”自己,而是与其关联的对象在内存中的地址,当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,因此,除非是同一个new出来的对象,他们的比较后的结果为true,不然比较后结果为false。由于每new一次就会从新开辟一个新的堆内存空间

String s1 = "小新";
String s2 = "小新";
System.out.println(s1 == s2);   //true
String str1 = new String("小新");
String str2 = new String("小新");
System.out.println(s1 == str1); //false
System.out.println(str1 == str2); //false
复制代码

s1 == s2为true,是由于s1和s2都是字符串字面值"小新"的引用,指向同一块地址,因此相等。

s1== str1为false,是由于经过new产生的对象在堆中,str1是堆中变量的引用,而s1是指向字符串字面值"小新"的引用,地址不一样因此不相等。

str1 == str2为flase,是由于即便内容相同,因为不是指向同一个对象,也会返回false。

小结

  • 若操做数的类型是基本数据类型,则该关系操做符判断的是左右两边操做数的是否相等
  • 若操做数的类型是引用数据类型,则该关系操做符判断的是左右两边操做数的内存地址是否相同。也就是说,若此时返回true,则该操做符做用的必定是同一个对象。

equals

来源

equals,是Objec类的方法,源代码以下:

public boolean equals(Object obj) {
    return (this == obj);
}
复制代码

可见Objec的equals方法,直接调用==,比较对象地址,便是否指向同一个对象。

不一样的子类,能够重写此方法,进行两个对象的equals的判断。

String类源码中重写的equals方法以下:

public boolean equals(Object anObject) {   
    if (this == anObject) {     // 先判断是否为同一对象
        return true;
    }
    if (anObject instanceof String) {   // 再判断类型是否一致,
        // 最后判断内容是否一致.
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
        char v1[] = value;
        char v2[] = anotherString.value;
        int i = offset;
        int j = anotherString.offset;
        while (n-- != 0) {
            if (v1[i++] != v2[j++])
            return false;
        }
        return true;
        }
    }
    return false;
}
复制代码

使用equals方法,内部实现分为三个步骤:

  • 先比较引用是否相同(是否为同一对象),
  • 再判断类型是否一致(是否为同一类型),
  • 最后比较内容是否一致

equals 重写原则

  • 自反型,对于任何非null的引用值x,也就是本身等于本身x.equals(x)是true
  • 对称性,对于任何非null的引用值x和y,也就是x.equals(y)等于y.equals(x)
  • 传递性,对于任何非null的引用值x,y和z,若是x.equals(y)返回是“true”,并且y.equals(z)返回是“true”,那么x.equals(z)也应该返回是“true”
  • 一致性,对于任何非null的引用值x和y,屡次调用x.equals(y)获得的结果是同样的,只要引用没有被修改
  • 非空性,全部的对象都不能为空,对于任意非空引用x,x.equals(null)应该返回false。

小结

所以,对于 equals 方法:

  • Object类中equals方法本意是比较两个对象是否相同
  • 必要的时候,咱们须要重写该方法,避免违背本意,且要遵循上述原则

hashCode

来源

hashCode 方法是基类Object中的 实例native方法,所以对全部继承于Object的类都会有该方法。

他的源码以下:

public native int hashCode();
复制代码

说明是一个本地方法,它的实现是根据本地机器相关的。固然咱们能够在本身写的类中覆盖hashcode()方法,好比String、Integer、Double等这些类都是覆盖了hashcode()方法的。例如在String类中定义的hashcode()方法以下:

public int hashCode() {
    int h = hash;
    if (h == 0) {
        int off = offset;
        char val[] = value;
        int len = count;

        for (int i = 0; i < len; i++) {
            h = 31 * h + val[off++];
        }
        hash = h;
    }
    return h;
}
复制代码

想要弄明白hashCode的做用,必需要先知道Java中的集合。   ​ 总的来讲,Java中的集合(Collection)有两类,一类是List,再有一类是Set。前者集合内的元素是有序的,元素能够重复;后者元素无序,但元素不可重复。这里就引出一个问题:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢? ​ 这就是Object.equals方法了。可是,若是每增长一个元素就检查一次,那么当元素不少时,后添加到集合中的元素比较的次数就很是多了。也就是说,若是集合中如今已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大下降效率。
​ 因而,Java采用了哈希表的原理。哈希(Hash)其实是我的名,因为他提出一哈希算法的概念,因此就以他的名字命名了。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上,初学者能够简单理解,hashCode方法实际上返回的就是对象存储的物理地址(实际可能并非)。
​ 这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一会儿能定位到它应该放置的物理位置上。若是这个位置上没有元素,它就能够直接存储在这个位置上,不用再进行任何比较了;若是这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。因此这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大下降了,几乎只须要一两次。

hashCode()和equals()关系

  • equals()相等的两个对象,hashcode()必定相等;
  • hashcode()相等,那么equals()有可能相等,也有可能不等 ;
  • 若是hashcode()不等,equals()必定不相等;
  • 通常来说,equals 这个方法是给用户调用的,而 hashcode 方法通常用户不会去调用 ;
  • 当一个对象类型做为集合对象的元素时,那么这个对象应该拥有本身的equals()和hashCode()设计,并且要遵照前面所说的几个原则。

为何重写equals的同时也要重写hashCode?

1.使用hashcode方法提早校验,能够避免每一次比对都调用equals方法,提升效率

2.保证是同一个对象,若是重写了equals方法,而没有重写hashcode方法,会出现equals相等的对象,hashcode不相等的状况,重写hashcode方法就是为了不这种状况的出现。

小结

  1. hashcode是系统用来快速检索对象而使用
  2. equals方法本意是用来判断引用的对象是否一致
  3. 重写equals方法和hashcode方法时,equals方法中用到的成员变量也一定会在hashcode方法中用到,只不过前者做为比较项,后者做为生成摘要的信息项,本质上所用到的数据是同样的,从而保证两者的一致性

参考资料

blog.csdn.net/justloveyou…

www.cnblogs.com/aspirant/p/…

www.iteye.com/blog/bijian…

相关文章
相关标签/搜索