A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© zhou1234 中级黑马   /  2014-12-9 16:02  /  1780 人查看  /  14 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

class StringDemo
{
        public static void main(String[] args)
        {
                String s1="abc";//s1是一个类类型变量,s1是一个对象
                String s2=new String("abc");//与第一个的区别为 这是两个对象,而第一个为一个对象
                System.out.println(s1==s2);
                System.out.println(s1.equals(s2));

        }
}
还有 第一个是一个对象 第二个是两个对象,还是不是太懂,求大神帮忙啊

14 个回复

倒序浏览
一个字符串就是String的匿名对象,==是进行地址比较的啊,equals方法是比较字符串的,LZ可以随便找本java的书
回复 使用道具 举报

== 比较对象地址是否相同,equals 是由类覆写,可以参考一下String的源码,一看就懂。

通俗的说 ==是看看左右是不是一个东西。equals是看看左右是不是长得一样




回复 使用道具 举报
楼上说得有道理!
回复 使用道具 举报
本帖最后由 Smart_lll 于 2014-12-9 18:47 编辑

一、先说一下,一个对象和两个对象的问题:
      对于String类而言,“”和new都可以用来创建对象并在内存中开辟空间,也就是说,“abc”就是一个对象了,通过new StringBuffer();也可以创建一个对象,因此String s2=new String("abc");相当于是""和new StringBuffer();同时使用创建了两个对象。
二、再说一说“==”和equals的区别:
Java中的数据类型,可分为两类:
1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean
  他们之间的比较,应用双等号(==),比较的是他们的值。
2.复合数据类型(类)
      当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址,但在一些类库当中这个方法被覆盖掉了,如String类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了,它比较的是内存中字符串是否相同。
       对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号(==)进行比较的,所以比较后的结果跟双等号(==)的结果相同。
public class StringDemo {
        public static void main(String[] args) {
                String s1 = "abc";
                String s2 = "abc";
                if (s1 == s2) {
                        System.out.println("s1== s2");
                } else {
                        System.out.println("s1 != s2");
                }
        }
}
编译并运行程序,输出:s1 == s2
说明:s1 与 s2 引用同一个内存地址值!
2.接着程序修改,改成和楼主相同的:

public class StringDemo {
        public static void main(String[] args) {
                String s1 = "abc";
                String s2 = new String("abc");
                if (s1 == s2) {
                        System.out.println("s1 == s2");
                } else {
                        System.out.println("s1 != s2");
                }
                if (s1.equals(s2)) {
                        System.out.println("s1 equals s2");
                } else {
                        System.out.println("s1 not equals s2");
                }
        }
}
程序输出:
s1 != s2
s1 equals s2
说明:s1 s2分别引用了两个内存地址值。
<:#希望能给楼主帮助,有错误请指出!:#>
回复 使用道具 举报
==比较的是地址值,equals比较的是内容
回复 使用道具 举报 1 0
Rdw 初级黑马 2014-12-9 20:42:41
7#
学习了!!
回复 使用道具 举报
(单独把一个东西说清楚,然后再说清楚另一个,这样,它们的区别自然就出来了,混在一起说,则很难说清楚)
==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符。
如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存,例如Objet obj = new Object();变量obj是一个内存,new Object()是另一个内存,此时,变量obj所对应的内存中存储的数值就是对象占用的那块内存的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较。
equals方法是用于比较两个独立对象的内容是否相同,就好比去比较两个人的长相是否相同,它比较的两个对象是独立的。例如,对于下面的代码:
String a=new String("foo");
String b=new String("foo");
两条new语句创建了两个对象,然后用a,b这两个变量分别指向了其中一个对象,这是两个不同的对象,它们的首地址是不同的,即a和b中存储的数值是不相同的,所以,表达式a==b将返回false,而这两个对象中的内容是相同的,所以,表达式a.equals(b)将返回true。
在实际开发中,我们经常要比较传递进行来的字符串内容是否等,例如,String input = …;input.equals(“quit”),许多人稍不注意就使用==进行比较了,这是错误的,随便从网上找几个项目实战的教学视频看看,里面就有大量这样的错误。记住,字符串的比较基本上都是使用equals方法。
如果一个类没有自己定义equals方法,那么它将继承Object类的equals方法,Object类的equals方法的实现代码如下:
boolean equals(Object o){
return this==o;
}
这说明,如果一个类没有自己定义equals方法,它默认的equals方法(从Object 类继承的)就是使用==操作符,也是在比较两个变量指向的对象是否是同一对象,这时候使用equals和使用==会得到同样的结果,如果比较的是两个独立的对象则总返回false。如果你编写的类希望能够比较该类创建的两个实例对象的内容是否相同,那么你必须覆盖equals方法,由你自己写代码来决定在什么情况即可认为两个对象的内容是相同的。
回复 使用道具 举报
二:String对象的特点
        字符串最大特点:一旦被初始化就不可以被改变。
        String类复写了Object类中的equals方法,该方法用于判断字符串是否相同。
        如果没有复写Object的equals方法,那么==和equals()功能是一样的,都是比较对象的地址值

        String s1 = "abc";
        String s2 = new String("abc");
        String s3 = "abc";

       比较结果:
                s1 == s2 (false)
                s1.equals(s2); (true)
                s1 == s3 (true)
        原因:String s1 = "abc",当这句话执行时,就在内存中创建了"abc"和s1,并将"abc"的地址值赋给了s1,
        当执行String s2 = new String("abc");程序会在内存中new一个新的对象,并将这个对象的地址值赋给s2,
        当执行String s3 = "abc"时,程序检测到内存中已经存在了abc这个对象,为了节约内存,程序会直接将该地址值赋给s3
        又因为String复写了equals方法,==比较的是地址值,equals比较的是内容,所以s1 == s2(false),s1.equals(s2)(true),s1 == s3(true)

        s1和s2有什么区别?
                s1在内存中有一个对象。
                s2在内存中有两个对象
回复 使用道具 举报
恩恩 谢谢大家 瞬间懂了:lol
回复 使用道具 举报
第一个是直接定义了一个变量,s2用new定义了一个对象 ,所以这两个是两个对象
回复 使用道具 举报
==是爪哇中一个比较运算符 运算完结果要么是真要么是假   例如3==4吗 返回的肯定就是假   而equal是Object()类中的一个方法  用于比较两个对象  记住是对象  其实内部比较的是这2个对象的地址  通常都是被覆盖  建立子类 对象特有的比较两个对象相同的条件依据   两个有着巨大的差别  没什么可比性  
回复 使用道具 举报
唐的 初级黑马 2014-12-10 00:04:47
13#
1.   栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。

2.   栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共 享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要 在运行时动态分配内存,存取速度较慢。

==是判断两个对象是否是同一个对象
equals是进行值的判断
String   a   =   new   String( "aaa ");
String   b   =   new   String( "a ");
b   +=   "aa ";
则   a==b   //错误
  a.equals(b)//正确
除了String和封装器,equals()和“==”没什么区别
但String和封装器重写了equals(),所以在这里面,equals()指比较字符串或封装对象对应的原始值是否相等, "== "是比较两个对象是否为同一个对象
首先,我们先来看一下java中变量的语义:

java的变量有两种语义,原始类型的变量是值语义(value),也就是说,你给一个原始类型变量赋值,就改变了这个数据值本身。对象类型的变量是引用语义,也就是说,给一个对象类型的变量赋值只是让它指向另一个对象,但不改变原来引用的那个对象的值。

然后,我们了解一下String的特性以及java对于Sting特别的处理方式:

《String的特性》

1、String类是final的,不可被继承。

2、String类是的本质是字符数组char[], 并且其值不可改变。

3、String类对象有个特殊的创建的方式,就是直接指定比如String x = “abc”,”abc”就表示一个字符串对象。而x是”abc”对象的地址,也叫做”abc”对象的引用。

4、String对象可以通过“+”串联。串联后会生成新的字符串。

5、Java运行时会维护一个String Pool(String池),JavaDoc翻译很模糊“字符串缓冲区”。String池用来存放运行时中产生的各种字符串,并且池中的字符串的内容不重复。而一般对象不存在这个缓冲池,并且创建的对象仅仅存在于方法的堆栈区。

6、创建字符串的方式很多,归纳起来有三类:

其一,使用new关键字创建字符串,比如String s1 = new String(“abc”);

其二,直接指定。比如String s2 = “abc”;

其三,使用串联生成新的字符串。比如String s3 = “ab” + “c”;

《String对象的创建》

String对象的创建也有很多门道,关键是要明白其原理。

原理1:当使用任何方式来创建一个字符串对象s=X时,Java运行时(运行中JVM)会拿着这个X在String池中找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串s,否则,不在池中添加。

原理2:Java中,只要使用new关键字来创建对象,则一定会(在堆区或栈区)创建一个新的对象。

原理3:使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对象。

原理4:使用包含变量的表达式来创建String对象,则不仅会检查维护String池,而且还会在堆栈区创建一个String对象。

《不可变类》

JAVA为了提高效率,对String类型进行了特别的处理---为string类型提供了串池定义一个string类型的变量有两种方式:

string name= “tom “;(String name=”t”+”o”+”m”的效果和此处是相同的)string name =new string( “tom “)

如果你使用了第一种方式,那么当你在声明一个内容也是 “tom “的string时,它将使用串池里原来的那个内存,而不会重新分配内存,也就是说,string saname= “tom “,将会指向同一块内存。而如果用第二种方式,不管串池里有没有”tom”,它都会在堆中重新分配一块内存,定义一个新的对象。

另外关于string类型是不可改变的问题: string类型是不可改变的,也就是说,当你想改变一个string对象的时候,比如name= “madding ” 那么虚拟机不会改变原来的对象,而是生成一个新的string对象,然后让name去指向它,如果原来的那个 “tom “没有任何对象去引用它,虚拟机的垃圾回收机制将接收它。

最后,关于定义String的堆栈问题

String s =new String()分析堆与栈,是先定义S,还是先new string()

1. String str1 = “abc”;

System.out.println(str1 == “abc”);

步骤:

1) 栈中开辟一块空间存放引用str1;

2) String池中开辟一块空间,存放String常量”abc”;

3) 引用str1指向池中String常量”abc”;

4) str1所指代的地址即常量”abc”所在地址,输出为true;

2. String str2 = new String(“abc”);System.out.println(str2 == “abc”);

步骤:

1) 栈中开辟一块空间存放引用str2;

2) 堆中开辟一块空间存放一个新建的String对象”abc”;

3) 引用str2指向堆中的新建的String对象”abc”;

4) str2所指代的对象地址为堆中地址,而常量”abc”地址在池中,输出为false;

3. String str3 = new String(“abc”);System.out.println(str3 == str2);

步骤:

1) 栈中开辟一块空间存放引用str3;

2) 堆中开辟一块新空间存放另外一个(不同于str2所指)新建的String对象;

3) 引用str3指向另外新建的那个String对象 ;

4) str3和str2指向堆中不同的String对象,地址也不相同,输出为false;

4. String str4 = “a” + “b”;System.out.println(str4 == “ab”);

步骤:

1) 栈中开辟一块空间存放引用str4;

2) 根据编译器合并已知量的优化功能,池中开辟一块空间,存放合并后的String常量”ab”;

3) 引用str4指向池中常量”ab”;

4) str4所指即池中常量”ab”,输出为true;

5. final String s = “a”; //注意:这里s用final修饰,相当于一个常量

String str5 = s + “b”;

System.out.println(str5 == “ab”);

6. String s1 = “a”;

String s2 = “b”;

String str6 = s1 + s2;

System.out.println(str6 == “ab”);

步骤:

1) 栈中开辟一块中间存放引用s1,s1指向池中String常量”a”,

2) 栈中开辟一块中间存放引用s2,s2指向池中String常量”b”,

3) 栈中开辟一块中间存放引用str5,

4) s1 + s2通过StringBuilder的最后一步toString()方法还原一个新的String对象”ab”,因此堆中开辟一块空间存放此对象,

5) 引用str6指向堆中(s1 + s2)所还原的新String对象,

6) str6指向的对象在堆中,而常量”ab”在池中,输出为false

7. String str7 = “abc”.substring(0, 2);

步骤:

1) 栈中开辟一块空间存放引用str7,

2) substring()方法还原一个新的String对象”ab”(不同于str6所指),堆中开辟一块空间存放此对象,

3) 引用str7指向堆中的新String对象,

8. String str8 = “abc”.toUpperCase();

步骤:

1) 栈中开辟一块空间存放引用str6,

2) toUpperCase()方法还原一个新的String对象”ABC”,池中并未开辟新的空间存放String常量”ABC”,

3) 引用str8指向堆中的新String对象

9.String s=”abc”;

String s1=s;

System.out.println(s1==”abc”);

s=s+”hello”;

System.out.println(s1==”abc”);

System.out.println(s==”abc”);

步骤:

1)栈中开辟一块空间存放s;

2)Sting池中开辟一块空间用于存放”abc”,栈中开辟一块空间存放变量s1;

3)系统输出true,在堆中开辟一块空间用于存放”abchello”;

4)引用s指向堆中的”abchello”;

5)系统输出true,然后输出false;
回复 使用道具 举报
我的理解:==相当于等号,1==1,而equals是比较两个字符串对象是否一样!
回复 使用道具 举报
第一个:s1,s2共用一个内存;第二个:equals方法比较字符串,创建2个不同的内存
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马