深入理解Java的==和equals

关系操作符==

关系操作符== ,适用于所有的基本数据类型,同时也适用于对象。

  • == 用于基本数据类型,比较的是数据的值

Java中有8种基本数据类型,其中有4种整型(int ,short,long,byte)、2种浮点类型(float,double)、1种用于表示Unicode编码的字符单元的字符类型char和1种用于表示真值的boolean类型。

下面对基本数据类型进行相等性测试:

public class Test {
  public static void main(String[] args) {
      boolean b1 = true;
      boolean b2 = true;
      System.out.println("b1 == b2: "+(b1==b2));
      char c1 = 'c';
      char c2 = 'c';
      System.out.println("c1 == c2: "+(c1==c2));
      byte by1 = 1;
      byte by2 =1;
      System.out.println("by1 == by2: "+(by1==by2));
      short sh1 = 2;
      short sh2 =2;
      System.out.println("sh1 == sh2: "+(sh1==sh2));
      int n1 = 1;
      int n2 =1;
      System.out.println("n1 == n2: "+(n1==n2));
      long l1 = 1L;
      long l2 = 1L;
      System.out.println("l1 == l2: "+(l1==l2));
      float f1 =1F;
      float f2 = 1F;
      System.out.println("f1 == f2: "+(f1==f2));
      double d1 = 3.14;
      double d2 = 3.14;
      System.out.println("d1 == d2: "+(d1==d2));
   }
}

结果如下:

b1 == b2: true
c1 == c2: true
by1 == by2: true
sh1 == sh2: true
n1 == n2: true
l1 == l2: true
f1 == f2: true
d1 == d2: true

上面的测试都是对同一类型的值进行比较(如 by1与by2都是byte类型的整数)
如果,我们对不同类型的数字进行比较会得出什么结果?

 public class Test {
    public static void main(String[] args) {
      int n= 100;
      byte b = 100;
      long l = 100L;
      short s = 100;
      System.out.println("n==b: "+ (n==b));
      System.out.println("b==l: "+ (b==l));
      System.out.println("l==s: "+(l==s));

      float f1 = 3.14F;
      float f2 =100F;
      double d1 = 3.14;
      double d2 = 100;
      System.out.println("f1==d1: "+(f1==d1));
      System.out.println("f2==n: "+(f2==n));
      System.out.println("d2==n:"+(d2==n));
  }
}

结果:

n==b: true
b==l: true
l==s: true
f1==d1: false
f2==n: true
d2==n:true

结论:

1、不同类型的整数之间可以进行相等性比较。
2、不同类型的小数之间不要使用==比较,因为精度不同。
3、 整数和小数可以进行相等性比较,整数会自动转成相应的浮点类型。

  • == 用于对象,比较的是对象的引用

先看个下面这个例子,创建两个字符串对象s1和s2,然后进行相等性比较。

public class Test {
    public static void main(String[] args) {
     String s1 = new String("abc");
     String s2 = new String("abc");
     System.out.println(s1 == s2);
    }
}

结果: false

虽然s1和s2的值相等,但是s1和s2的引用却是不同时的,这是两个对象,因此返回false。

接下来看个奇怪的问题:

public class Test {
      public static void main(String[] args) {
         String s1 = "abc";
         String s2 = "abc";
         System.out.println(s1 == s2);
      }
  }

你猜出正确结果吗?

你可能会想,这不是生成了两个字符串吗,一定是不相等的。

输出结果是:

true

这是为什么?
原因是:在java中,字符串是不可修改的,是不可变的。修改字符串实际是将变量引用了新的字符串。不可变字符串有个优点:编译器可以让字符串共享。
上面的代码可以这么理解:当创建s1时,存储池放置了一个字符串,当创建s2时,发现创建的是同样的字符串,就不再放入字符串了,因为这样会重复,所以s2就直接引用了存储池中已经存在的字符串。
如果s1改变了,那么存储池就会再放入一个新字符串,这时候,s1,s2指向的字符串地址就不一样了。

  • ==用于包装器对象
public class Test {
   public static void main(String[] args) {
     Integer a =1000;
     Integer b=1000;
     System.out.println(a==b);

     Integer c =100;
     Integer d=100;
     System.out.println(c==d);
  }
}

运行结果:

false
true

出现这种现象的原因是:自动装箱规范要求boolean、byte、char<=127,介于-128~127之间的short和int被包装到固定的对象中。

因此,在比较两个包装器对象时调用equals方法。

equals方法

equals方法适用于对象,而不能用于基本数据类型。

  • 自定义类的实例对象equals操作
class  Person{}

public class Test {
    public static void main(String[] args) {
       Person p1 = new Person();
       Person p2 = new Person();
       System.out.println(p1.equals(p2));
    }
}

结果是:

false

Java中所有类都默认继承Object,而Object类中的equals方法会判断两个对象是否具有相同的引用。如果两个对象具有相同的引用,它们一定是相等的。因此,两个对象的equals操作默认是比较引用。

Object类中的equals源码如下所示:

public boolean equals(Object obj) {
    return (this == obj);
}
  • 字符串的equals操作
public class Test {
     public static void main(String[] args) {
         String s1 = "noshower";
         String s2 = "noshower";
         System.out.println(s1.equals(s2));
     }
}

结果如下:

 true

String的equals方法重写了,覆盖了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类的equals方法,先是比较两个变量是否指向同一个引用,如果是,直接返回相等。如果不是,就要判断equals括号内的变量,是否是String的实例,如果不是直接返回不相等。如果是String的实例,就比较两个变量代表的字符串长度是否相等,如果不相等就返回不相等的结果。如果长度相等,就把字符串转成char数组,比较每个字符是否相等。如果都相等,就返回相等的结果。如果有一个字符不相等,就返回不相等的结果。

由此我们可以得出,String的equals方法对相同引用的变量和不同引用,但是值相等的变量,都返回true。

我们再来看一个有趣的问题:

public class Test {
    public static void main(String[] args) {
        String s = "noshower";
        System.out.println(s+"2" == "noshower2");
        System.out.println("noshower2".equals(s+"2"));
    }
}

结果如下:

false
true

这是为什么呢?

如果两个字符串放置在同一个位置上,它们必然相等。但是,完全有可能将内容相同的多个字符串的拷贝放置在不同的位置上。所以s+"2" 与"noshower2"放置在不同的位置。

实际上,只有字符串常量是共享的,而+或substring等操作产生的结果并不是共享的。

因此,千万千万不要用==测试字符串的相等性

  • 基本类型的包装类equals

这里只举例Integer包装类,因为其他包装类的实现逻辑都是一样的。都是先比较某个变量是不是这个包装类的实例,如果不是,返回false。否则,比较值是否相等。如果相等,就返回true。否则返回false。

public class Test {
    public static void main(String[] args) {
        Integer n1 =new Integer(47);
        Integer n2 =new Integer(47);
        System.out.println(n1==n2);
        System.out.println(n1.equals(n2));
    }
}

结果如下:

false
true

不是同一个引用,所以==返回false。值相等,所以equals返回true。

Integer类equals方法源码如下:

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

正如我上面所说的,先比较是不是同一个类型,再比较值是否相等。

其他几个包装类就不一一讲述了。这里贴上,它们的equals源码。

Short

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

Long

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

Byte

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

Float

public boolean equals(Object obj) {
    return (obj instanceof Float)
           && (floatToIntBits(((Float)obj).value) == floatToIntBits(value));
}

Double

 public boolean equals(Object obj) {
    return (obj instanceof Double)
           && (doubleToLongBits(((Double)obj).value) ==
                  doubleToLongBits(value));
}

Character

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

Boolean

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

完毕!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • java笔记第一天 == 和 equals ==比较的比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量...
    jmychou阅读 1,488评论 0 3
  • 集合框架: 1)特点:存储对象;长度可变;存储对象的类型可不同2)Collection(1)List:有序的;元素...
    Demo_Yang阅读 1,251评论 0 4
  • java中String的常用方法 1、length()字符串的长度 例:char chars[]={'a','b'...
    赤赤有名阅读 2,038评论 0 10
  • equals方法和==的区别 首先大家知道,String既可以作为一个对象来使用,又可以作为一个基本类型来使用。这...
    加油小杜阅读 376评论 0 0