导读:本期聚焦于小伙伴创作的《怎么在Java中判断两个对象地址是否相同?双等号==的引用比较原理详解》,敬请观看详情。在Java面试和调试中,常有人分不清==和equals的区别。==作用于引用类型时,比较的是栈中引用变量所指向堆内存对象的地址值,而非对象内容。若两个独立new出来的对象,即便字段完全一致,用==判断也返回false。只有指向同一实例或字面量常量池中的同一对象时,结果才为true。理解这一点能避免误用导致逻辑错误,也能搞清楚String驻留机制为何让某些==比较意外成立。下文从内存模型、代码演示到包装类缓存逐一拆解。

在Java语言里,当使用双等号==比较两个引用类型的变量时,实际比较的是它们所保存的对象内存地址,也就是判断这两个变量是否指向堆中的同一个实例。这一机制与基本数据类型的值比较完全不同,也是很多初学者在对象相等性判断上容易踩坑的地方。

怎么在Java中判断两个对象地址是否相同?双等号==的引用比较原理详解

一、Java内存模型与引用比较的本质

要理解==对对象的比较行为,先要看Java的内存划分。局部变量表中的引用变量存放的是地址,而对象实例本身在堆中分配。当我们写Object a = new Object();时,a里存的是堆中那个Object实例的起始地址。

使用==比较引用类型,虚拟机直接比对这两个地址数值是否相等。如果相等,说明两个引用指向同一个对象;如果不等,哪怕两个对象内部状态一模一样,也只是不同的内存实体。这和equals方法默认实现不同,后者在不重写时虽然也用==,但语义上我们常把它视为内容比较的入口。

二、基础代码示例演示

下面通过一段简单代码展示独立对象与同一引用下的==结果差异。

public class RefCompareDemo {
    public static void main(String[] args) {
        // 两个独立new的对象,地址不同
        String s1 = new String("hello");
        String s2 = new String("hello");
        System.out.println(s1 == s2); // false,地址不同

        // 同一对象赋值给两个引用
        String s3 = s1;
        System.out.println(s1 == s3); // true,指向同一实例

        // 字面量来自常量池,指向同一地址
        String s4 = "hello";
        String s5 = "hello";
        System.out.println(s4 == s5); // true,常量池复用
    }
}

从输出可以看到,new出来的两个String尽管内容都是hello,但==返回false。而字面量赋值因Java的字符串常量池机制,让s4和s5指向同一块内存,所以==为true。

这种差异提醒我们:若业务需判断字符串内容一致,必须用equals方法;若确实要确认是否为同一对象,才使用==。混淆二者会造成难以察觉的逻辑bug。

三、包装类型的缓存干扰

Integer等包装类在特定范围也会缓存对象,使得==出现看似违反直觉的结果。

public class IntegerCacheDemo {
    public static void main(String[] args) {
        Integer i1 = 127;
        Integer i2 = 127;
        System.out.println(i1 == i2); // true,命中缓存

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

Integer对-128到127的值做了池化,自动装箱时复用同一对象,因此小数值的==为true。超过范围则每次新建实例,==自然为false。这进一步说明==只认地址,不认数值。

在真实开发中,比较包装类数值应统一用equals或拆箱后比基本值,避免依赖缓存范围导致线上问题。

四、如何正确判断对象地址相同

如果需求本身就是确认两个引用是否指向同一对象,直接使用==即可,它是最快且语义明确的做法。

public class SameRefCheck {
    static class Node {
        int val;
        Node(int v) { val = v; }
    }
    public static void main(String[] args) {
        Node n1 = new Node(1);
        Node n2 = n1;
        Node n3 = new Node(1);
        System.out.println(n1 == n2); // true
        System.out.println(n1 == n3); // false
    }
}

上述代码里n2由n1赋值,二者地址相同;n3是新实例,地址不同。这种写法在需要防止重复处理同一实体、或做浅拷贝判断时非常实用。

总结来说,双等号在Java引用比较中扮演地址裁判的角色。认清它和equals的分工,结合常量池与包装缓存现象,才能写出健壮的对象比较逻辑。

Java双等号比较对象引用修改时间:2026-08-07 06:51:21

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。