黑马程序员技术交流社区

标题: String中==和.equals()的疑问 [打印本页]

作者: 燃烧端午    时间: 2012-6-20 23:44
标题: String中==和.equals()的疑问
  1. public class Judge {

  2.         /**
  3.          * @param args
  4.          */
  5.         public static void main(String[] args) {
  6.                 // TODO Auto-generated method stub
  7.                 String st="abc";
  8.                 String sr="abc";
  9.                 System.out.println(st == sr);//true
  10.                 System.out.println(st.equals(sr));//true
  11.                 String st1 = new String("abc");
  12.                 String sr1 = new String("abc");
  13.                 System.out.println(st1 == sr1);//为什么会是返回false
  14.                 System.out.println(st1.equals(sr1));//true

  15.         }

  16. }
复制代码
关于String类字符串池存放给点指点吧
作者: 李伟    时间: 2012-6-21 00:00
public class Judge {

        /**
         * @param args
         */
        public static void main(String[] args) {
                // TODO Auto-generated method stub
                String st="abc";
                String sr="abc";
                System.out.println(st == sr);//true
                System.out.println(st.equals(sr));//true
                String st1 = new String("abc");
                String sr1 = new String("abc");
                System.out.println(st1 == sr1);//为什么会是返回false//因为st1和sr1是两个对象的引用,所以st1不等于sr1
                System.out.println(st1.equals(sr1));//true//这个equals()是用于比较对象内容的,因为st1和sr1的内容相同所以返回true

        }

}
作者: 张立江    时间: 2012-6-21 00:00
本帖最后由 小张童鞋 于 2012-6-21 00:06 编辑

public class Judge {

        /**
         * @param args
         */
        public static void main(String[] args) {
                // TODO Auto-generated method stub
                String st="abc";//这里st和sr都直接指向了"abc"字符串,所以==和equals都是true
                String sr="abc";
                System.out.println(st == sr);//true
                System.out.println(st.equals(sr));//true
                String st1 = new String("abc");//在常量池中定义了个"abc"字符串,因为是new出来的,所以会生成一个hash地址值X,变量str指向了这个hash地址值              
                String sr1 = new String("abc");//这里又new了一个新的hash地址值Y,定义变量sr1指向Y         
               System.out.println(st1 == sr1);//为什么会是返回false//X和Y两个hash地址值不一样,当然不能用==了
               System.out.println(st1.equals(sr1));//true//但是两个hash地址值指向的字符串是一样的,就true了

        }

}
作者: 李元峰    时间: 2012-6-21 00:06
== 比较的如果是两个对象,则是比较这两个对象的引用地址是否相等,凡是用new 出来对象都是在堆内存的,他们是不可能相等的,
.equals(object)方法比较的是调用者和object的内容是否相等,
而像这样String str = "abe";是直接拿静态数据池里面字符串常量来初始化一个 String 对象的,这是为了避免去new一个对象,用以提高效率的
作者: 田建    时间: 2012-6-21 00:07
                String st1 = new String("abc")
                String sr1 = new String("abc");
                System.out.println(st1 == sr1);//为什么会是返回false
                System.out.println(st1.equals(sr1));//true
==比较的是两个对象存放的地址,因为都是新new的对象,所以地址自然不一样,因而返回false;而equals方法比较的是字符串的内容,因而返回的为true。
关于字符串池的问题:
字符串池和String类的基本关系:
  Java运行环境有一个字符串池,由String类维护。
  1、执行语句String str="abc"时,首先查看字符串池中是否存在字符串"abc",如果存在则直接将"abc"赋给str,如果不存在则先在字符串池中新建一个字符串"abc",然后再将其赋给str。
  2、执行语句String str=new String("abc")时,不管字符串池中是否存在字符串"abc",直接新建一个字符串"abc"(注意:新建的字符串"abc"不是在字符串池中),然后将其付给str。
而你的问题属于第二种@
作者: 郑冬    时间: 2012-6-21 00:09
所有的“==”都是基于指针级的,也就是说只有它们指向的是同一个对象才被认为是相等. 而对于对象值的相等判断则需要重写并使用.equal()方法 在多数常用类,譬如String中,.equal()已经被默认重写为是值相等的了   
作者: 薄炳鑫    时间: 2012-6-21 00:13
先给你解释一下==和equals比较的内容
==比较的是两个对象引用的地址值,当两个对象引用都指向同一个对象时就会出现相等。
equals比较的是两个对象的hash值,而且String的hash值是通过字符串内容生成的,所以相同的字符串会出现相等的hash值。
  1. public class Judge {

  2.         /**
  3.          * @param args
  4.          */
  5.         public static void main(String[] args) {
  6.                 // TODO Auto-generated method stub
  7.                 String st="abc";
  8.                 String sr="abc";//这里的两个对象引用指向同一个abc
  9.                 System.out.println(st == sr);//true
  10.                 System.out.println(st.equals(sr));//true
  11.                 String st1 = new String("abc");
  12.                 String sr1 = new String("abc");
  13.                 System.out.println(st1 == sr1);//因为上面创建对象的两个方法,创建了两个不同的对象,使得对象引用有了两个不同的地址值。
  14.                 System.out.println(st1.equals(sr1));//根据equals方法比较的字符串hash值相同,所以两个值相等。

  15.         }

  16. }
复制代码

作者: 王晓新    时间: 2012-6-21 00:18
String str = "abc";
String str = new String("abc");
两种的形式来创建,用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。
而String str = "abc";是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。
比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true ,可以看出str1和str2是指向同一个对象的。
String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false ,用new的方式是生成不同的对象。每一次生成一个。
        因此用String str1 = "abc"; 方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。
作者: 胡大强    时间: 2012-6-21 00:39
equals检测的是两对象是否相等,即他们的内容是否相等
==比较的是基本数据类型或者引用,或者说他们指向内存的地址。

s1 = new String("java"); //创建的是字符串对象
s1.equals("java"); //返回true  比较s1对象的内容是不是"java”.
s1 == "java" //返回false 比较s1对象在内存中存放的地址和"java”的地址是不是同一个地址
//如果
s1 = "java"; //注意这种赋值方式和上面的区别
s1 == "java" //返回true


作者: 周朋飞    时间: 2012-6-21 00:44
                      String s1 = "Monday";     
            String s2 = new String("Monday");
            System.out.println(s1==s2);
            System.out.println(s1.equals(s2));
== 永远比较的是地址
equals 比较的是内容是片面的: Object类equals比较的还是地址;String首先比较地址,如果地址相同则返回true ,其次在比较内容
作者: 山水游客    时间: 2012-6-21 07:42
public class Judge {


        /**

         * @param args

         */

        public static void main(String[] args) {

                // TODO Auto-generated method stub

                String st="abc";

                String sr="abc";

                System.out.println(st == sr);//true

                System.out.println(st.equals(sr));//true

                String st1 = new String("abc");

                String sr1 = new String("abc");

                System.out.println(st1 == sr1);//为什么会是返回false   

                System.out.println(st1.equals(sr1));//true


        }


}
步骤:
1) 栈中分别开辟一块空间存放引用str1,sr1;
2) String sr1 = new String("abc"); 堆中开辟一块新空间存放另外一个(不同于st1所指)新建的String对象;
3) 引用sr1指向另外新建的那个String对象 ;
4) st1和str1指向堆中不同的String对象,地址也不相同,输出为false;
用equals方法用于判断字符串是否相同


作者: 逝去的记忆ヽ    时间: 2012-6-21 09:19
首先是数据保存位置


栈(heap)内存中存放基本类型,引用,局部变量;
堆(stack)内存中存放new出来的对象;
方法区(共享区,数据区)中存放静态变量,字符串常量,方法代码。方法区的代码被调用时,将在栈中开辟空间。运行完后,栈中的空间被释放。


对于==  

如果是基本数据类型,那么它们是存在方法区中。方法区中只允许有一个相同的数据,如果多次用到同一个数据类型,则会指向方法区中相同的地址。

正是因为如此,才会说  对于基本数据类型,直接盘对是否相等。例如:

String a="asd";

String b=new String("asd") 这样,物理地址一样,==返回true,但是按照最开始的理解,用equals()方法应该也返回true了。但是结果是返回false.

这是为什么呢?因为.equals()在比较的时候,首先要比较的是两个是不是一个类型,然后再比较物理地址是不是一样,必须两者都满足,才返回true.
作者: sbeeqnui1987    时间: 2012-6-21 09:32
解释一下==号,他比较的是一个对象在内存中的地址值,
比如2个字符串对象
String s1 = new String("str");
String s2 = new String("str");
如果用==号比较,会返回false,因为创建了两个对象,他们在内存中地址的位置是不一样的。

equals的情况比较复杂,它是java.lang.Object类中的一个方法。因为java中所有的类都默认继承于Object,所以所有的类都有这个方法。

在Object类源码中是这样写的。
public boolean equals(Object obj) {
return (this == obj);
}
他同样使用==号进行内存地址的比较。但是许多java类中都重写了这个方法,比如String。
public boolean equals(Object anObject) {
if (this == anObject) {
     return true;
}
if (anObject instanceof String) {
     String anotherString = (String)anObject;
     int n = count;
     if (n == anotherString.count) {
  char v1[] = value;
  char v2[] = anotherString.value;
  int i = offset;
  int j = anotherString.offset;
  while (n-- != 0) {
      if (v1[i++] != v2[j++])
   return false;
  }
  return true;
     }
}
return false;
    }

String里的方法,如果==号比较不相等,还会进行一下值的比较。
所以equals方法具体的作用要看当前的那个类是如何实现重写父类中该方法的。如果没有重写该方法,那么他和==号等价。
作者: 熊雪莲    时间: 2012-6-21 15:05
我总结了一下~==操作比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量在堆中存储的地址是否相同,即栈中的内容是否相同。equals操作表示的两个变量是否是对同一个对象的引用,即堆中的内容是否相同。
如果两个都是基本数据类型比较:
那么都在栈中存储,只需要比较是否等值就可以了
如果两个都是引用数据类型比较:
那么都在堆中存储,在堆中存储的话就要看对象指向的内容是否一致来分析了,像楼楼的问题中创建了两个对象,所以两个对象存在栈中的地址肯定不一样,所以用==返回False,但是又因为对象都指向“abc”,即对象的内容一样所以equals比较的话返回True
关于String类
使用String str = "abc";的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象
作者: 李元峰    时间: 2012-6-21 15:19
熊雪莲 发表于 2012-6-21 15:05
我总结了一下~==操作比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量在堆中存储的地址是否 ...

你恰恰说反了,你弄混了吧?
作者: 马超    时间: 2012-6-21 15:25
public class Judge {

        /**
         * @param args
         */
        public static void main(String[] args) {
                // TODO Auto-generated method stub
                String st="abc";
                String sr="abc";
                System.out.println(st == sr);//true
                System.out.println(st.equals(sr));//true
                String st1 = new String("abc");
                String sr1 = new String("abc");
                System.out.println(st1 == sr1);//为什么会是返回false ,因为这里 ==  是用来比较两个对象 即 st1 和st2 的引用是不是相同,new产生两个对象,返回的结果肯定是false             
     System.out.println(st1.equals(sr1));//,在复写掉Object中的equals()之前呢,他的作用和 == 是一样一样的,复写掉之后,他的作用就成了比较两个对象的内容是不是一样的啦,结果都是“abc”,所以返回true

        }

}
作者: 柯玲    时间: 2012-6-22 12:41
"=="比较的是对象
equals()比较的是内容
String st1 = new String("abc");
String sr1 = new String("abc");
System.out.println(st1 == sr1);//此句中str1和str2在栈内存中开辟了两个空间,指向的地址值不同,所以输出false
System.out.println(st1.equals(sr1));//此句中str1和str2包含的内容都是abc,内容相等,所以输出true


作者: 柯玲    时间: 2012-6-22 12:45
还有补充一点,equals()是复写Object中的方法,它建立了本对象自己比较相同的特有方式,比较的是数值是否相同
作者: oracleserver    时间: 2012-6-22 16:03
作为一个Java的初学者,刚开始学习时,我对于他们一直是出于很模糊的认识,没有清醒的认识它们本质上的区别

  在JAVA中,==与equals都有比较判断对象是否相等的作用,但具体用法却并不相同。==是运算符号,而equals则属于方法。

  当==两边的对象属于基本类型时,==的作用仅是比较对象的值是否相等,如果相等返回true,否则返回false;当两边的对象属于引用数据类型时,==的作用是判断对象的内存地址是否一致,如果同时指向同一地址,则返回true,否则返回false.

  equals两边对象只能属于引用数据类型,因为equals是方法,所以它是如何具体判断对象是否相等是根据程序而定的,equals是属于object类,默认是判断内存地址是否相同,但在object的子类中可以重写equals方法,如在String类中只是比较对象内容是否一致,一致则返回true,否则返回false

  比如: String s1="abc";

  String s2="abc";

  s1.equals(s2) 是true 因为equals比较的是对象的内容

  而 s1==s2 是false 因为当两边的对象属于引用数据类型时,==的作用是判断对象的内存地址是否相同,s1和s2创建了不同的对象,所以内存地址肯定不同。
作者: 周兴中    时间: 2012-6-23 01:07
String s1="abc";
String s2="abc";
以上两句话表示s1和s2都指向了堆内存中的"abc"
因为"=="比较的是对象的地址值,所以 s1==s2 为true

那为什么
String s3=new String("java");
s3=="java" 的结果却为false,难道是这句话先是在堆内存中又创建了一个String对象,其值为java吗?

作者: 游洪波    时间: 2012-6-23 14:19
String st="abc";  //创建一个对象st 然后将内存中 “abc”这个对象赋给 st;
String sr=“abc”;//创建一个对象st 然后将内存中 “abc”这个对象赋给 st;
用==号比较的是两个对象在内存中存放的地址
那么这样一来 “abc”这个对象又分别赋给了st和sr 所以 st和sr同时指向了“abc”这个内存地址,所以第一个比较结果为true
用equals()比较的是连个对象的值
这样的话st和sr的值都是“abc”那么这次比较的结果自然是true
同理如果用 new String(“”)的话结果就会成这样
String st=new String(“abc”);大家都知道new关键字是用来创建对象的,那么String st=new String(“abc”);这个就相当与在创建一个st对象值是“abc” 要知道这里是创建的st对象 不是上边的“abc”,然后下边有写了String sr=new String(“abc”);这样就又在内存中开辟了一个新的对象sr值也是“abc”。
这样的话我们用==号比较st和sr时,他们不是一个对象所以地址也不相同,所以这个结果是false
下边那么equals()方法的比较就不用我多说了吧。

作者: 郑庆伟    时间: 2012-6-23 14:54
建议你看一个,JDK源代码。你可以看下它的实现机制,或者用GC查看。这个问题,其实字面上大家常说的。一个地址,一个值。这样只是我们更容易理解。其实,不是这样的。
作者: 安路凤    时间: 2012-6-23 17:53
01.public class Judge {

02.

03.        /**

04.         * @param args

05.         */

06.        public static void main(String[] args) {

07.                // TODO Auto-generated method stub

08.                String st="abc";

09.                String sr="abc";

10.                System.out.println(st == sr);//true

11.                System.out.println(st.equals(sr));//true

12.                String st1 = new String("abc");

13.                String sr1 = new String("abc");

14.                System.out.println(st1 == sr1);//==当比较对象时比较的是两个对象的地址,而不是比较两个对象的值,所以Str1==Sr1进行比较时,值为False

15.                System.out.println(st1.equals(sr1));//equals当比较对象时比较的是两个对象的值,它们当被New时指向的是同一个堆中的值“abc”,所以st1==sr1,值为true

16.

17.        }

18.

19.}


作者: 孙飞    时间: 2012-6-24 09:05
本帖最后由 feigecal 于 2012-6-24 09:09 编辑

程序在运行的时候会创建一个字符串缓冲池,当使用 String sr="abc";这样的表达时创建字符串的时候,程序首先会在这个String缓冲池中寻找相同值的对象,在上面,String st="abc";中st先被放到了池中,所以在sr被创建的时候,程序找到了具有相同值的 st,将 sr 引用 st 所引用的对象"abc"。下面,使用了 new 操作符,他明白的告诉程序:"我要重新创建一个对象"。于是一个新的"abc"Sting对象被创建在内存中。他们的值相同,但是位置不同,只是浪费了资源。==比较的是2个对象的地址,而equals比较的是2个对象的内容,不管是上面还是下面,对象 的内容都是abc所以你的equals()运算都是true。


我也是刚搞清楚,希望帮到你,共同进步,呵呵
作者: 李东升    时间: 2012-6-24 16:02
用new关键字后,实例化了对象,那么str1和str2就是两个引用,这两个引用指向的是两块内存,所以用“==”比较就不相同了。
作者: 封明川    时间: 2012-6-24 22:54
String st1 = new String("abc");  //这个在堆内存中新建了一个空间,值为“abc”,地址保存在st1中
String sr1 = new String("abc");   //这个在堆内存中又新建了一个空间,值为“abc”,地址保存在sr1中
System.out.println(st1 == sr1);//为什么会是返回false  ::st1 和 sr1存放的地址不同,肯定不相等了




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2