Java中equals与==的比较解析

本文深入探讨Java中final关键字的作用及限制,通过实例说明final如何确保变量不可变,并指出其无法阻止对象状态变化的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、本质区别

比较方式作用原理比较内容适用场景
==比较内存地址(引用比较)对象在堆中的物理地址基本类型和对象引用比较
equals比较逻辑内容(内容比较)对象实际存储的数据值对象内容的语义相等判断

二、具体使用场景

1. 基本数据类型比较

int a = 5;
int b = 5;
System.out.println(a == b);  // true(值比较)
// 基本类型没有equals方法

2. 对象比较

String s1 = new String("hello");
String s2 = new String("hello");

System.out.println(s1 == s2);      // false(不同内存地址)
System.out.println(s1.equals(s2)); // true(内容相同)

3. 字符串常量池特例

String s3 = "hello";
String s4 = "hello";

System.out.println(s3 == s4);      // true(指向字符串常量池同一对象)
System.out.println(s3.equals(s4)); // true

三、equals方法规范

1. 正确实现equals的五大原则

  1. 自反性x.equals(x)必须返回true

  2. 对称性x.equals(y)y.equals(x)结果相同

  3. 传递性:如果x.equals(y)y.equals(z),则x.equals(z)

  4. 一致性:多次调用结果不变(不依赖可变字段)

  5. 非空性x.equals(null)必须返回false

2. 典型equals实现

@Override
public boolean equals(Object o) {
    // 1. 地址相同
    if (this == o) return true;
    
    // 2. 类型检查
    if (o == null || getClass() != o.getClass()) return false;
    
    // 3. 字段比较
    Person person = (Person) o;
    return age == person.age && 
           Objects.equals(name, person.name);
}

四、特殊案例解析

1. Integer缓存问题

Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1 == i2);  // true(使用缓存)

Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4);  // false(超出缓存范围)

2. BigDecimal比较

BigDecimal d1 = new BigDecimal("2.0");
BigDecimal d2 = new BigDecimal("2.00");

System.out.println(d1.equals(d2));  // false(精度不同)
System.out.println(d1.compareTo(d2) == 0);  // true(值相同)

五、深度问题

Q1:为什么重写equals必须重写hashCode?
A:违反hashCode契约会导致哈希集合异常:

Map<Person, String> map = new HashMap<>();
map.put(new Person("Alice", 20), "CEO");

// 如果只重写equals不重写hashCode,这里会返回null
System.out.println(map.get(new Person("Alice", 20))); 

Q2:String的equals实现原理?
A:JDK源码实现:

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

Q3:如何比较两个数组内容?
A:使用Arrays.equals()

int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};

System.out.println(arr1 == arr2);  // false
System.out.println(Arrays.equals(arr1, arr2));  // true

Q4:==比较对象时,比较的是hashCode吗?
A:不是!==比较的是对象地址(内存物理位置),与hashCode()无关。默认的hashCode()实现通常与地址相关,但可能被重写。

六、最佳实践

  1. 基本类型:总是使用==

  2. 对象比较

    • 需要内容比较时:重写equals+hashCode

    • 需要同一性检查时:使用==

  3. 字符串比较

    • 常量比较:"literal".equals(var)(避免NPE)

    • 变量比较:Objects.equals(str1, str2)(Java7+)

  4. 工具类使用

    • Objects.equals(a, b)(处理null安全)

    • Arrays.equals()比较数组内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值