美文网首页技术干货
深入理解Java的==和equals

深入理解Java的==和equals

作者: 打铁大师 | 来源:发表于2017-08-05 01:38 被阅读0次

    关系操作符==

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

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

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

    完毕!!

    相关文章

      网友评论

        本文标题:深入理解Java的==和equals

        本文链接:https://www.haomeiwen.com/subject/spnblxtx.html