黑马程序员技术交流社区

标题: String有关的问题 [打印本页]

作者: 石义良    时间: 2015-3-30 13:17
标题: String有关的问题
String a=new String("a")和String a="a"有什么区别


作者: 缤纷落叶    时间: 2015-3-30 13:17
本帖最后由 缤纷落叶 于 2015-3-30 16:58 编辑

一:String a=new string("a")的创建过程:
是直接调用String的构造方法String(xx)来创建一个新的字符串“a”,简单说就是在常量池中给“a”分配一个新的内存地址并存储,a 指向该地址
同理String b=new string("a"),也是创建一个新字符串(a),然后存储在另一个新的地址,b 指向该地址,所以用该方式创建的a和b的字符串相同或不同都不会指向同一个内存地址;
可以这么理解:a=直接分配(新地址1),地址值为‘’a‘’.
                     b=直接分配(新地址2),地址值为‘’a‘’.
二:tring a="a"的创建过程:
先看常量池中是否有"a",如果有a就指向"a"的地址;如果没有,新建一个"a"放入池中,然后a指向"a"
如果此时再创建  String b="a" ,由于池中已经有"a"了,所以b就直接指向“a";所以用该方式创建的a和b的字符串相同都指向同一个内存地址;
可以这么理解:先判断内存中是否有“a”,
                                                   1.有:a=旧地址1,地址值为‘’a‘’.
                                                           b=旧地址1,地址值为‘’a‘’.
                                                            .....................................................(省略一大堆)

                                                   2.没有: a=分配(新地址1),地址值为‘’a‘’.
                                                                b=(新地址1),地址值为‘’a‘’.
                                                                 ..................................................(省略一大堆)
作者: xw_fting    时间: 2015-3-30 13:32
1、String a="a";这个首先会在内存中寻找,如果有就调用,没有就String a = new String("a");
2、String a = new String("a");这个不管内存中有没有,都会创建。

作者: 通往牛逼的路上    时间: 2015-3-30 16:02
String a;
a== null;
a 没有指向一个对象
String a = new String ()
a != null;
a 指向了一个对象

作者: 温开创    时间: 2015-3-30 17:18
这个作为我们初学者都会遇到的问题,文字什么的肯定是看了之后还是记不得的,找张纸,画个栈、堆内存,然后哪个属于栈的哪个属于堆的,先搞明白,只要知道怎么画图以后学什么就很好理解了,这些要靠自己动手才记得住。
作者: 水中世界    时间: 2015-3-30 18:00
String a="a";String b="a";String c = new String("a");
则有a==b 的值是true  ; a==c的值是false

作者: 水中世界    时间: 2015-3-30 18:01
这是堆栈的区别,
一个是在堆里生成的,
一个是在栈里生成。
列如:
String a="a";String b="a";String c = new String("a");
则有a==b 的值是true  ; a==c的值是false

作者: ♂陆仁贾メ    时间: 2015-3-30 18:41
String a= new String("a");  
     会在堆中创建“a”的的实例,然后在栈中创建该实例的引用;
String a="a"
      会先在堆中查看是否有“a"的实例,,如果没有则创建。有则指向该实例
作者: yi岁⑨很乖❤    时间: 2015-3-31 12:59
【String a=new String("a")和String a="a"有什么区别】
[1].  String a="a":
创建一个String类型的引用变量a,指向常量池的实例对象"a"。
"a"这个对象放在字符串常量缓冲区,常量""不管出现多少遍,都是缓冲区中的那一个。

[2].  String a= new String("a"):
创建一个String类型的引用变量a,  new String语句创建了一个对象,它根据字符串常量"a"对象的内容来创建的一个新的String对象,
如果常量"a"已经在程序中使用过了,就不会重新创建常量"a",而是直接从字符串常量缓冲区中直接获取。 然后将变量a指向这个新创建的String对象。
也就是说:

这样分析,可以理解了嘛?希望可以帮到你哦~ 强烈求黑马币哦:#





作者: 右手年华    时间: 2015-3-31 21:22
String a="a";这个首先会在内存中寻找,如果有就调用,没有就String a = new String("a");
2、String a = new String("a");这个不管内存中有没有,都会创建。
作者: 翰墨    时间: 2015-4-1 10:21

String a="a";a是一个类类型变量,在内存中只有"a"一个对象。
String a=new String("a");a在内存中有两个对象,new一个,”a”一个

作者: yxnheima    时间: 2015-4-1 12:11
String a = "a";是一个字面量,存储在栈中;
String a = new String("a"); 创建一个对象,对象的内容是"a",引用a存储在栈中,引用a所指的那个对象存在堆中。
作者: qq250144825    时间: 2015-4-1 22:22
String a = "a";是一个局部变量,存储在栈中;
String a = new String("a"); 用new创建一个对象,毕老师有说过用new创建的都为实例,存储在堆中;

所以区别应该在于一个存储的内存区不一样
作者: 一袭蓝10    时间: 2015-4-2 17:18
String a="a";先在内存中找是不是有"a"这个对象,如果有,就让a指向"a".如果没有"a",就创建一个新的对象保存"a". String a=new String("a")就是不管内存里是不是已经有"a"这个对象,都创建一个对象来保存"a"
作者: 陈佳    时间: 2015-4-3 10:27
String a = new String("a")会在内存中创建一个字符串“a”的副本,所以内存中会有两个“a”对象
作者: 宸宸    时间: 2015-4-3 12:47

String a=new String("a")  在内存中有两个对象 new String,“a"
String a="a"  在内存中只有一个对象 “a"
作者: 百谈千语    时间: 2015-4-3 20:18
就是用来讲没什么差别,也可以先定义String a;
a="XXX";这样感觉更好点分开,到时候定义和赋值两个动作使用起来更加方便
作者: 靳颖颖    时间: 2015-4-3 23:08
只要new出来的  ,在内存中他就有两个指针指向字符串a,而第二个只有一个对象,第一个是两个对象
作者: hello_csu    时间: 2015-4-4 18:13

String a=new String("a"),其实是先创建常量字符串a,而后在创建堆对象'a'
String a="a"只有一个a
作者: wk843620202    时间: 2015-4-4 23:23
String a=new String("a")在内存中有两个对象。
String a="a"在内存中有一个对象。

作者: 杨大萌    时间: 2015-4-5 11:03
首先,字符串类是一个被final修饰的类,字符串对象一旦被赋值,不可以改变。所以,在内存的方法区中会有一片区域称为常量池,字符串在内存中都放在常量池中。String a="a"这条语句,就是string类型变量a指向常量池中的一个字符串对象“a”。而String a=new String("a");这条语句,是在堆内存中创建一个string对象a,被初始化为“a”。所以这个a可以为null。
作者: 杨大萌    时间: 2015-4-5 11:06
还有就是,string a=new  String("a");在内存中有两个对象,一个是string对象
,一个是常量池中的“a”。而String a="a",在内存中只有一个对象。就是常量池中的那个
作者: shw16888    时间: 2015-4-5 11:15
String a="a"定义一个局部变量,将a变量存储在栈内存中,String a=new String("a")创建一个String 对象的实例,会在栈内存和堆内存开辟空间,引用变量a指向该对象并存储在栈内存,将"a"存储在堆内存中
作者: woshixtdx    时间: 2015-4-5 14:05
你看下面结果应该就知道怎么会事的
String aa="abc"  
Sring bb =new String("abc")
String cc ="abc"
Stirng dd = new  String("abc")
System.out.println(aa==bb); false
System.out.println(aa==cc);  true
System.out.println(bb==dd);  false
注:Sting aa="abc"  的解释因为字符串不可以改变的,常量池中已经有了abc所以不新建了,所以是同一对象。它们是在date区中。
Stirng dd = new  String("abc")  很明显是一下对像,bb和dd不是指向同一个对像所以不相同
作者: woshixtdx    时间: 2015-4-5 14:07
你看下面结果应该就知道怎么会事的
String aa="abc"  
Sring bb =new String("abc")
String cc ="abc"
Stirng dd = new  String("abc")
System.out.println(aa==bb); false
System.out.println(aa==cc);  true
System.out.println(bb==dd);  false
注:Sting aa="abc"  的解释因为字符串不可以改变的,常量池中已经有了abc所以不新建了,所以是同一对象。它们是在date区中。
Stirng dd = new  String("abc")  很明显是一下对像,bb和dd不是指向同一个对像所以不相同
作者: Angelsmile    时间: 2015-4-5 20:17
很显然这涉及到Java的内存机制。String a = new String("a")中的变量a指向两个地方,一个是在常量池中,一个是在堆内存中,常量池的为"a",堆内存中为new的一个对象,这样的好处是我们每次都new了一新的对象,可方便的对新的对象赋值,弊端是占用的内存多一点。String a="a"就简单一些,变量a指向常量池中的“a”,这样的好处是减少了内存的占用,缺点却是致命的,如果之前已经有一个指向“a”的对象,那么String a="a"并没有新建一个对象,而是指向之前建立的对象,修改a时很可能把之前建立的对象也改变了。所以为了安全起见,String a=new String("a")使用更广泛。
作者: 樱空之雪    时间: 2015-4-5 21:33
String a = new String(“a”);在内存中有两个对象存在,首先在常量池中找”a”,
如果没有就创建一个,然后把该对象的地址值赋值给了new String(“a”);
最后把new的对象复制给引用a。但是 String a = “a”;只在常量池里面有一个对象。
作者: 小邱    时间: 2015-4-5 21:59
String a=new String("a");中a的值是对象的地址值,而String a="a";中a的值是字符串“a”
作者: 1017161726    时间: 2015-4-6 12:17
缤纷落叶 发表于 2015-3-30 16:53
一:String a=new string("a")的创建过程:
是直接调用String的构造方法String(xx)来创建一个新的字符串“a ...

本来大致理解这两个语句的区别,听这哥们一讲顿时清楚明晰了。赞赞赞
作者: Aelous_6    时间: 2015-4-6 12:33
以String a = "a" ;方式声明字符串会在栈内存中的字符串池中创建变量a,如果字符串池中已有a,则不会在创建a并且以后以这种方式声明字符串变量“a”与a有  a==“a”,

以String s = new String("a"); 方式声明,会现在栈内存的字符串池中先判断“a”是否存在。如果不存在就在字符串中创建“a”的变量,并在堆内存创建字符串对象并把地址值赋给s;如果字符串吃池中存在就不会再在字符串池中创建“a”变量。接着在堆内存中创建字符串对象并把地址值赋给s。
作者: 熏陶    时间: 2015-4-7 21:14
第一个String a=new String("a")是两个对象,即常量池一个,new出来的堆内存一个。第二个String a="a"只是一个对象,就在常量池,是不可改变的量。
作者: 郝聚德    时间: 2015-4-9 00:16
new  就是在堆内存中开辟了一个空间

作者: 侯永凯    时间: 2015-4-9 21:18


String a=new String("a")  在内存中会创建两个对象 new String(),“a"
String a="a"  在内存中只有一个对象 “a"
作者: 蜡笔    时间: 2015-4-10 14:17
使用起来是一样的。区别是他们是两个不同的对象,判断==返回的的是false,判断equals返回的是true,应为String类复写了Object中的equals方法
作者: Hello_Java    时间: 2015-4-10 23:23
String a = new String("a");--在堆内存中有创建了一个对象,方法区的常量池有一个。String a = "a"--只创建了一个对象。答得不好,互相学习。
作者: 星之钥匙    时间: 2015-4-11 22:08
String a=new String("a")在堆中建立了一个新的对象,并且赋值,String  a在常量区,如果有就直接调用,没有就创建
作者: xiangdong_1995    时间: 2015-4-14 22:19
String a =new String ("a") 这是创建了一个对象   左面的String在栈内存里面   右面的new String 在堆内存里面创建了一个对象   值为a     右面的String a=“a”   是直接就给复制了差距就是一个在堆内存里面创建的  用完就消失了 一个不在堆内存里面不会随着对象的消失儿消失
作者: Struggle_168    时间: 2015-4-15 11:45
String a,只是声明了一个变量,存储在"栈"中。。。String a = new String(),不仅在栈中声明了这个变量,同时在“堆”中划分了一片区域(为空),变量存储只想这片区域的地址。。。String a = "This sucks!",就是把“堆”中填充上"This sucks!"的内容
作者: Struggle_168    时间: 2015-4-15 11:47
补充一下:
String a:定义一个字符串类型的变量名为a的变量
String a = new String () :这句活的作用是创建一个对象
String是数据类型,但不是字符串类型,这里指的是引用类型,是一个String类。
String ()是构造函数
new在堆内存中开辟一个空间,String ()完成构造函数的初始化动作后,把空间的地 址值赋值给a
作者: 小小ye    时间: 2015-4-15 19:54
String a= new String("a")是创建一个对象,String a=“a”;是一个定义就像int a=1思想一样;
作者: babadan    时间: 2015-4-20 18:30
String a=new String("a")有两个对象
String a="a"有一个对象
作者: itheima_llt    时间: 2015-4-22 00:10
回帖是必须的,这个可以有!
作者: dengxing    时间: 2015-4-22 21:01
前一个a代表在内存中有两个对象,new了一个对象,"a"本身也是一个对象。而后一个a是一个类类型的变量,它指向一个对象即"a".它代表在内存中有一个对象。“a”本身就代表一个对象
作者: flowerdance    时间: 2015-4-22 22:01
关于这个问题 我找到的分析如下 楼主仔细看就应该能整明白
.String 是一个特殊的包装类数据。即可以用String str = new String("abc");的形式来创建,也可以用Stringstr = "abc";的形式来创建(作为对比,在JDK 5.0之前,你从未见过Integer i =3;的表达式,因为类与字面值是不能通用的,除了String。而在JDK 5.0中,这种表达式是可以的!因为编译器在后台进行Integer i= newInteger(3)的转换)。前者是规范的类的创建过程,即在Java中,一切都是对象,而对象是类的实例,全部通过new()的形式来创建。 Java中的有些类,如DateFormat类,可以通过该类的getInstance()方法来返回一个新创建的类,似乎违反了此原则。其实不然。该类 运用了单例模式来返回类的实例,只不过这个实例是在该类内部通过new()来创建的,而getInstance()向外部隐藏了此细节。那为什么在 Stringstr = "abc";中,并没有通过new()来创建实例,是不是违反了上述原则?其实没有。
5. 关于String str = "abc"的内部工作。Java内部将此语句转化为以下几个步骤:
(1)先定义一个名为str的对String类的对象引用变量:String str;
(2) 在栈中查找有没有存放值为"abc"的地址,如果没有,则开辟一个存放字面值为"abc"的地址,接着创建一个新的String类的对象o,并将o的字符 串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为"abc"的地址,则查找对象o,并返回o的地址。
(3)将str指向对象o的地址。
值得注意的是,一般String类中字符串值都是直接存值的。但像String str = "abc";这种场合下,其字符串值却是保存了一个指向存在栈中数据的引用!
为了更好地说明这个问题,我们可以通过以下的几个代码进行验证。
  String str1 = "abc";
  String str2 = "abc";
  System.out.println(str1==str2);  //true
注意,我们这里并不用str1.equals(str2);的方式,因为这将比较两个字符串的值是否相等。==号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是,str1与str2是否都指向了同一个对象。
结果说明,JVM创建了两个引用str1和str2,但只创建了一个对象,而且两个引用都指向了这个对象。
我们再来更进一步,将以上代码改成:
  String str1 = "abc";
  String str2 = "abc";
  str1 = "bcd";
  System.out.println(str1 + "," + str2);  //bcd, abc
  System.out.println(str1==str2);  //false
这就是说,赋值的变化导致了类对象引用的变化,str1指向了另外一个新对象!而str2仍旧指向原来的对象。上例中,当我们将str1的值改为"bcd"时,JVM发现在栈中没有存放该值的地址,便开辟了这个地址,并创建了一个新的对象,其字符串的值指向这个地址。
事 实上,String类被设计成为不可改变(immutable)的类。如果你要改变其值,可以,但JVM在运行时根据新值悄悄创建了一个新对象,然后将这 个对象的地址返回给原来类的引用。这个创建过程虽说是完全自动进行的,但它毕竟占用了更多的时间。在对时间要求比较敏感的环境中,会带有一定的不良影响。
再修改原来代码:
  String str1 = "abc";
  String str2 = "abc";
  
  str1 = "bcd";
  
  String str3 = str1;
  System.out.println(str3);  //bcd

  String str4 = "bcd";
  System.out.println(str1 == str4);  //true   
str3这个对象的引用直接指向str1所指向的对象(注意,str3并没有创建新对象)。当str1改完其值后,再创建一个String的引用str4,并指向因str1修改值而创建的新的对象。可以发现,这回str4也没有创建新的对象,从而再次实现栈中数据的共享。
我们再接着看以下的代码。
  String str1 = new [t1] String("abc");
  String str2 = "abc";
  System.out.println(str1==str2);  //false
创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。
  String str1 = "abc";
  String str2 = new String("abc");
  System.out.println(str1==str2);  //false
创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。
以上两段代码说明,只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。
6. 数据类型包装类的值不可修改。不仅仅是String类的值不可修改,所有的数据类型包装类都不能更改其内部的值。
7. 结论与建议:
(1) 我们在使用诸如String str ="abc";的格式定义类时,总是想当然地认为,我们创建了String类的对象str。担心陷阱!对象可能并没有被创建!唯一可以肯定的是,指向 String类的引用被创建了。至于这个引用到底是否指向了一个新的对象,必须根据上下文来考虑,除非你通过new()方法来显要地创建一个新的对象。因 此,更为准确的说法是,我们创建了一个指向String类的对象的引用变量str,这个对象引用变量指向了某个值为"abc"的String类。清醒地认 识到这一点对排除程序中难以发现的bug是很有帮助的。
(2)使用String str ="abc";的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于 Stringstr = newString("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,[t2] 是否有必要创建新对象,从而加重了程序的负担。这个思想 应该是享元模式的思想,但JDK的内部在这里实现是否应用了这个模式,不得而知。
(3)当比较包装类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==。
(4)由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。



总结:基本数据类型,存储在栈中,“abc”存储在栈中,只要是使用new一个对象,则存储在堆中,而且在栈中,在新建一个新的变量或对象时,会首 先看一下是否已经存在,存在则不创建新的。那在栈中的数据是否不涉及垃圾回收呢。那这部分内容,如何处理呢,还有就是,对象的作用域,程序存储在哪儿呢

对于栈中的数据来说,当超过变量的作用域的时候,会消失。哦,明白了,那种栈的形式



实例化后,也就是用了new运算符号,在堆内存建立一个对象,对象是一块区域,里面包含着每个属性



只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。
楼主 分给我吧 我要黑马币换技术分拿入学名额 技术分不容易拿好蛋疼的 谢了
作者: lhwinner    时间: 2015-4-23 10:20
String a=new String("a")这样创建String会在内存中有两个对象,字符串变量a相当于字符串对象a的副本,而String a="a"在内存中只有一个对象
作者: l_z    时间: 2015-4-26 13:38
这种细节以前还真没注意到,学习学习
作者: 裴健华    时间: 2015-4-30 17:33
没有区别。String a="a"的时候,java语言有个自动装箱功能,“a”自动转换为string类型对象,编译的时候java替你进行String a=new String("a")操作
作者: kk8023    时间: 2015-5-3 09:30
缤纷落叶 发表于 2015-3-30 16:53
一:String a=new string("a")的创建过程:
是直接调用String的构造方法String(xx)来创建一个新的字符串“a ...

精辟!楼主说的蛮细的
作者: as12510    时间: 2015-5-4 00:31
new 的东西会在堆内存中创建,又由于是String字符串类型的,所以会在方法区也创建一份。而赋值等于字符串,不会出现在堆内存中。。所以  最大的区别就是 new的会出现两个"a",而赋值的  只有一个(在方法区)。
作者: 赵旗    时间: 2015-5-9 09:05
String a = new String{"a"};
先在常量池中保存一个"a" , new 在堆中创建一个新的String对象 并将他初始化值为"a"

String a="a"
看常量池中是否有"a"如果有就指向他  如果没有就创建一个"a"
作者: 繁复    时间: 2015-5-20 19:25
是一个开辟空间的问题,String a = "a";会现在内存中找有没有"a"如果有是指向,没有再new String("a") 另外,在以后你接触的字符串转码问题的时候,new String()提供了很好的转码方法




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