Java基础- 对象相等判断


hashCode equals ==

    • 对象相等判断
      • equals和==区别
      • hashCode 与 equals(重要) ※※
        • hashCode()介绍
        • hashCode()介绍(常见的几个问题)
        • 为什么要有 hashCode(HashSet如何检查重复)(重要)
        • 对象的相等与指向他们的引用相等,两者有什么不同?
        • hashCode()与equals()的相关规定(重要)
        • 代码详讲hashCode()与equals() ==内容
      • 值传递
        • 为什么 Java 中只有值传递
        • 值传递和引用传递有什么区别


对象相等判断

equals和==区别

==

  • 基本数据类型 ==比较的是值是否相同
  • 引用数据类型 ==比较的是否 相同对象
    equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
  • 类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
  • 类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)

额外说明String中的比较

  • String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,
    而String的equals方法比较的是对象的值。
  • 当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相
    同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象

hashCode 与 equals(重要) ※※

hashCode()介绍
  • hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode()函数
  • 散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的值。这其中就利用到了散列码!(可以快速找到所需要的对象)
  • 总结 hashCode()是一个堆内对象位置返回的一个int数值,他不是对象位置,但代表对象位置
hashCode()介绍(常见的几个问题)
  • HashSet如何检查重复
  • 两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?
  • hashCode和equals方法的关系
    面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode
    方法?”
为什么要有 hashCode(HashSet如何检查重复)(重要)

我们以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode:
当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,
如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查hashcode 相等的对象是否真的相同(equals()方法被覆盖过,则 hashCode 方法也必须被覆盖
如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。

对象的相等与指向他们的引用相等,两者有什么不同?

对象的相等 比的是内存中存放的内容是否相等 equals
引用相等 比较的是他们指向的内存地址是否相等 ==

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

如下String类的hasCode()和equals()说明,先写一段代码

public class Hashcode {
	public static void main(String[] args) {
		String a = new String("0");
		String b = new String("0");
		String c = "1";
		String d = "1";
		
		System.out.println(a.hashCode());// 48
		System.out.println(b.hashCode());// 48
		System.out.println(a==b);		// false
		System.out.println(a.equals(b));// true
		
		System.out.println(c.hashCode());// 49
		System.out.println(d.hashCode());// 49
		System.out.println(c==d);		// true
		System.out.println(c.equals(d));// true	
	}
  • 先看hasCode()的介绍,这里拿String类说明,hasCode是object中的方法,在String类中有重写,我们结合String a = new String(“0”);计算下hasCode的值
    /**用于字符存储*/
    private final char value[];

	/**缓存字符串的哈希码*/
    private int hash; // Default to 0
    
    public int hashCode() {
        int h = hash;
        //h值默认为0,"0"对应value.length应该为1
        if (h == 0 && value.length > 0) {
            char val[] = value;
            for (int i = 0; i < value.length; i++) {
            // 这一步对应的h=31*0 +'0'  字符型+数值,字符转换unicode数字,'0'编码对应48 
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

在String类中,关于hasCode的值是一个算法(结合unicode编码),无论new多少个对象,只要值是字符串"0",hasCode值就是48,所以如果两个对象相等,则hashcode一定也是相同的

  • 再来看下equals()的说明解释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;
                // 这一步拆分循环比较每个字符串内容,不一样返回false,所以这里是内容比较
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }

String类对于equals方法覆写,循环比较每个字符串内容,不一样返回false
两个对象相等,对两个对象分别调用equals方法都返回true

  • 最后来看==的两个比较
    ①先看 == 那个输出为false的,a和b分别是new的对象,这是两个对象,hasCode值都是48,但是a == b比较输出为false,两个对象有相同的hashcode值,它们也不一定是相等的即使这两个对象指向相同的数据,equals()方法进行覆盖过,输出为true,**equals()方法被覆盖过,则 hashCode 方法也必须被覆盖,hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),否则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)**其实hasCode是一个算法,返回int类型
    ②再看第二个 == 输出为true的,c和d的hasCode值也是一样的,这里输出为true是因为,定义一个字符串"1",相当于创建了一个String对象值为"1",存放在元数据内,String对象c和d分别引用这个String对象,这里属于引用相等:比较的是他们指向的内存地址是否相等引用的同一个对象,所以相等

值传递

当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递
是值传递。Java 语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方
法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但对对象引用的改变是不会影响到调用者的

为什么 Java 中只有值传递

按值调用
java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,也就是
说,方法不能修改传递给它的任何参数变量的内容
总结
Java程序设计语言对对象采用的不是引用调用,实际上,对象引用是按值传递的。
下面再总结一下Java中方法参数的使用情况:
一个方法不能修改一个基本数据类型的参数(即数值型或布尔型》
一个方法可以改变一个对象参数的状态。
一个方法不能让对象参数引用一个新的对象。

值传递和引用传递有什么区别
  • 值传递:指的是在方法调用时,传递的参数是按值的拷贝传递,传递的是值的拷贝,也就是说传递后就互不相关了。
  • 引用传递:指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用的地址,也就是变量所对应的内存空间的地址。传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)

你可能感兴趣的:(Java基础,java,开发语言)