java 中的“==”与equals---hashcode

1. 堆栈用途简述

  • 堆内存用来存放由new创建的对象(包括由基本类型包装起来的类:Integer、String、Double,实际上每个基本类型都有他的包装类)和数组(引用类型、包装类)。
  • 栈内存存放对象在堆中的内存地址(基本类型直接存储在栈内存中)

2. == 与 Equals()

  • 基本类型 '==' 比较值,不能使用equals
  • 对于引用数据类型(对象)来说,'==' 和 'equals'都是用来比较两个变量的地址
  • String类重写了equals方法,所以String.equals()可以比较两个字符串内容是否相等。
 public static void main(String[] args) {
        // integer 在常量区存储范围是[-128,127],超出这个范围的值会在堆内存中创建一个新对象来保存值
        Integer a = 100;
        Integer b = 100;
        System.out.println(a == b);       // 基本类型  == 比较值 不能使用equals()
        System.out.println(a.equals(b)); 
        // 引用类型  == 比较内存地址  equals比较内容(String 类型除外)

        //c、d是两个新对象,内存地址不同
        Integer c = 150;
        Integer d = 150;
        System.out.println(c == d);         // 比较内存地址
        System.out.println(c.equals(d));  // 未重写equals方法,比较内容是否相同

        String str = "aaa";
        String str1 = "aaa";
        System.out.println(str == str1);   // 字面量方式创建字符串,值存储在栈内,地址相同
        System.out.println(str.equals(str1));

        String s = new String("bbb");
        String s1 = new String("bbb");
        System.out.println(s == s1); // new出来的对象重新分配内存地址,s与s1地址不同,故输出false  变量值存储在堆内,栈存储的是值最堆中的地址
        System.out.println(s.equals(s1)); //String类型重写了equals方法 要判断对象的内存地址和值
    }

输出结果:

Object类中的equals方法:

 public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

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

使用equals() 进行比较时方法时,我们还应了解hashcode。

hashcode方法返回对象的哈希码值。
* hashCode 的常规协定是: 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,
* 前提是对象上 equals 比较中所用的信息没有被修改。
* 如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
package com.lxj.demoTest;

import org.junit.Test;

public class HashCodeTest {
    /**
    * hashcode() 获取哈希值
    */
    @Test
    public void testHash() {
        Integer a = 10;
        System.out.println(a.hashCode());

        String str = "abc";
        System.out.println(str.hashCode());

        User user = new User();
        System.out.println(user.hashCode());
    }
}

结果分析: 

  • integer类型的数据,返回的hash值为数据本身;
  • 对象类型的数据,返回的一串字符;
  • String类型的数据,返回一串字符;

比较两个值是否相等时,先通过比较两个值的哈希值(hashcode),然后再重写equals()方法来判定两个值是否相等(hashcode不相同则两个值必定不相等,hashcode相同,两个值可能相等)

package com.lxj.boomFilter;

import java.util.HashSet;
import java.util.Set;

public class HashDemo {
    private int i;

    public int getI() {
        return i;
    }
    public void setI(int i) {
        this.i = i;
    }
    /**
     * @param object
     * @return
     */
    public boolean equals(Object object) {
        if (object == null) {
            return false;
        }
        if (object == this) {
            return true;
        }
        if (!(object instanceof HashDemo)) {
            return false;
        }
        HashDemo other = (HashDemo) object;
        if (other.getI() == this.getI()) {
            return true;
        }
        return false;
    }

    public int hashCode() {
        return i % 10;
    }

    public final static void main(String[] args) {
        HashDemo a = new HashDemo();
        HashDemo b = new HashDemo();
        a.setI(1);
        b.setI(1);
        Set<HashDemo> set = new HashSet<HashDemo>();
        set.add(a);
        set.add(b);
        System.out.println(a.hashCode() == b.hashCode());
        System.out.println(a.equals(b));
        System.out.println(set);
    }
}

未重写 equals方法时,输出结果为 true false [com.lxj.boomFilter.HashDemo@1][com.lxj.boomFilter.HashDemo@1],此时HashSet中存放两个对象。
重写equals 方法后,执行输出结果为 true true [com.lxj.boomFilter.HashDemo@1],HaseSet中存放一个对象

运行结果: 

   

3. HashCode源码(转)

Object对hashCode()的方法实现

 public native int hashCode();

String 对hashCode()的方法实现

  public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
 
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

Integer对hashCode()的实现

@Override
    public int hashCode() {
        return Integer.hashCode(value);
    }

四、了解String对hashCode的计算

1、在String对象的创建,都是将String数据拆分为char类型    private final char value[];

2、对于计算hash值,为了区别"123"和"321"计算hash值一样的问题,对hash值计算时添加"权重"的思想;

所以对于Stirng类型的hash值计算思路:

public class Test {
    public static void main(String[] args) {
        String str = "ABC";
        System.out.println(str.hashCode());
    }
}

查询ascII码,我们知道A对应的十进制为65;B为66;C为67

 public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
 
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

计算过程为

1、(31*0+'A')     65

2、(31*0+'A')*31+'B'     65*31+66 = 2081

3、((31*0+'A')*31+'B')*31+'C'   2081*31+67=64578
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值