java中“==“与equals的区别

首先“==”是运算符号,比较的是“==”两边变量的值;equals是Object类的一个方法,Object是所有类的父类,所以所有类都可以使用equals方法,在没有被重写的情况下,equals方法是用来比较两个对象的引用是否相等,即是否指向同一个对象。

下面看一段代码

package com.flychuer;

public class TestMain {

    public static void main(String[] args) {

        int a1 = 10;
        int a2 = 10;

        Object obj = new Object();
        Object obj1 = new Object();
        Object obj2 = new Object();

        System.out.println(a1==a2);

        System.out.println(obj1==obj2);
        System.out.println(obj1.equals(obj2));
    }
}

运行结果:

 从运行结果中可以看出,a1==a2 的结果为true,而 obj1==obj2 的执行结果为false。

原因分析:

变量a1、a2是int类型的基本数据类型,变量本身保存的就是值,也就是这两个变量保存的都是数组:10,所有相等,结果返回true。基本数据类型包含byte、short、int、long、float、double、boolean、char八种,基本数据类型不能使用equals方法。

变量obj1、obj2是引用类型的变量,他们存储的是Object对象的地址,每次使用new关键字时都会在堆中开辟一块内存保存new的对象,并把这个对象的地址保存在引用类型的变量中,因为变量obj1、obj2都new了对象,所有是在堆中开辟了两块空间,保存了两个Object对象,所以obj1、obj2保存的对象地址不一样。

八种基本数据类型对应的类是引用数据类型,可以使用equals方法,“==”和equals比较结果与Object结果一样。

那么为什么 obj1.equals(obj2) 执行结果也是false呢?我们可以查看一下Object类中equals方法的源码

    public boolean equals(Object obj) {
        return (this == obj);
    }

 当两个变量指向同一个对象时,这个方法才会返回true。

        obj1 = obj;
        obj2 = obj;
        System.out.println(obj1==obj2);
        System.out.println(obj1.equals(obj2));

 这样写的话,两个执行结果全为true。

下面我们看一下String类型中“==”和equals的区别,首先执行一下代码

public class TestMain {

    public static void main(String[] args) {

        String str1 = "abc";
        String str2 = "abc";
        String str3 = "ab" + "c";
        String str4 = "ab";
        str4 = str4 + "c";
        String str5 = new String("abc");
        String str6 = new String("abc");

        System.out.println(str1==str2);
        System.out.println(str1.equals(str2));
        System.out.println(str1==str3);
        System.out.println(str1.equals(str3));
        System.out.println(str1==str4);
        System.out.println(str1.equals(str4));
        System.out.println(str1==str5);
        System.out.println(str1.equals(str5));
        System.out.println(str5==str6);
        System.out.println(str5.equals(str6));
    }
}

执行结果:

 What!!!

为什么 str1==str2 和 str1.equals(str2) 执行结果为true,和我们刚才说的引用数据类型的变量的情况不相符啊。

这就要从jvm说起了,java文件编译成class文件时,除了类的版本、字段、方法、接口等描述信息,还有常量池,用于存放编译期生成的各种字面量和符号引用,代码中的 “abc” 就是一个字面量,程序运行时类加载器又会把常量池中的信息放到运行时常量池中,使用String str = "abc" 的方式给String变量赋值时,每次都会从运行时常量池中查找这个字面量,找到后把地址赋值给String变量,所以变量str1、str2保存的同一个地址,指向的是同一个对象。

String类重写了Object类的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;
    }

从代码中可以看出,如果String类型变量执行同一个对象,或者他们指向的对象值完全一样,返回值为true,否则为false,所以代码中使用equals比较的结果都是true。

为什么 str1==str3 结果为true,而 str1==str4 结果是false呢?

先看一下官方文档:https://docs.oracle.com/javase/8/docs/api/java/lang/String.html

example:

     String str = "abc";
 

is equivalent to:

     char data[] = {'a', 'b', 'c'};
     String str = new String(data);
 

Here are some more examples of how strings can be used:

     System.out.println("abc");
     String cde = "cde";
     System.out.println("abc" + cde);
     String c = "abc".substring(2,3);
     String d = cde.substring(1, 2);
 

The class String includes methods for examining individual characters of the sequence, for comparing strings, for searching strings, for extracting substrings, and for creating a copy of a string with all characters translated to uppercase or to lowercase. Case mapping is based on the Unicode Standard version specified by the Character class.

The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings. String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method. String conversions are implemented through the method toString, defined by Object and inherited by all classes in Java. For additional information on string concatenation and conversion, see Gosling, Joy, and Steele, The Java Language Specification.

翻译为

该类String包括用于检查序列的单个字符、比较字符串、搜索字符串、提取子字符串以及创建所有字符都转换为大写或小写的字符串副本的方法。大小写映射基于Character类指定的 Unicode 标准版本。

Java 语言为字符串连接运算符 ( + ) 以及将其他对象转换为字符串提供了特殊支持。字符串连接是通过StringBuilder(or StringBuffer) 类及其append方法实现的。字符串转换是通过Java 中所有类toString定义Object和继承的方法实现的 。有关字符串串联和转换的其他信息,请参阅 Gosling、Joy 和 Steele, Java 语言规范 

再看下class文件反编译代码 String str3 = "ab" + "c"; 编译后变为:String str3 = "abc";

 使用 jclasslib bytecode viewer 工具查看calss文件

ldc指令负责把数值常量或String常量值从常量池中推送至栈顶,astore指令将栈顶引用型数值存入指定本地变量,由此可见变量str1、str2、str3赋值的jvm指令一样,操作的String常量值相同。

接下来分析 String str4 = "ab"; str4 = str4 + "c"; 查看class文件jvm指令

可以看出jvm先找到字面量“ab”放如栈中,然后创建StringBuilder对象保存“ab”,再找到字面量“c”,使用StringBuilder对象调用append方法,将“c”添加到“ab”后,最后使用toString方法转换为String类型。

再分析 String str5 = new String("abc"); String str6 = new String("abc"); 两句的jvm指令

 在堆中开辟了两块内存空间保存String类型的数据,并用str5、str6分别保存两块内存空间的地址。

综上所述 str1==str4、str1==str5、str5==str6 的结果都是false。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值