java里面的疑点

genguyige 2010-11-30 07:34:13
很久没发帖了 分儿闲着也是闲着 就来发个帖

都知道 java里面是有字符串缓存的 那么如果有这样一个实例

public class test3 {

public static void main(String[] args) {
String b=new String("hello"); //1
//String b="hello";
String a="hello"; //2
System.out.println(a==b);
}
}


现在 我在1处定义一个字符串 那么系统在堆中会给我创建两个对象 一个是new 出来的 一个是字符串常量"hello"
而我现在在2处在定义一个变量a 那么系统就会去找堆中有没有这个字符串"hello"的缓存对象
如果没有的话那么就会创建一个 如果有的话就指向那里 但是现在的情况堆中应该是有啊 为什么也输出false呢?
a和b所引用的对象难道不一样吗?



我只是有些疑问希望得到一个合理的解释
如果大家也有类似的关于java的疑点 可以贴上来大家一起讨论
本帖100分 有更好的疑点的我可以再加分.
...全文
275 35 打赏 收藏 转发到动态 举报
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
lxy15329 2010-12-02
  • 打赏
  • 举报
回复
学习了,String 类确实是个老大难问题
小灰狼 2010-12-02
  • 打赏
  • 举报
回复
因为在
String b=new String("hello");
这条语句之前的时候,就已经有个字符串"hello"了,然后又new 出来一个字符串,这时就有两个了
最后
String a = "hello";
这条语句其实指向的是第 new String 之前创建的那个 hello
congcongking 2010-12-02
  • 打赏
  • 举报
回复
在java编程思想这本书的103面是这样说的,==和!=比较的是对象的引用。
我学过c语言后,觉得引用就是指针而已。指针里存放的是地址。
二面向对象程序设计,将指针变化成引用,说指针,实际上还是说的引用,说引用还是说的指针,到最后还是地址。
所以,String a=new String("a");
String b="a";
boolean c=a==b;
那么c的值就是false.因为他们比较的是引用。引用是什么,引用就是对象的一个名字,就是一个实例的名字。比较的也就是指针。从而比较的也是地址。
别人家的老公 2010-12-02
  • 打赏
  • 举报
回复
这样的老生常谈的问题不要一而再再而三地翻出来的好不好

有空去看看别人的帖子吧

我们是可以站在别人的肩膀上看世界的
方杭尽 2010-12-02
  • 打赏
  • 举报
回复
一个原则:

带new关键字产生对象的方法不论任何情况都会另外开辟内存来存储对象.
renjianguokeivor 2010-12-02
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 goldenfish1919 的回复:]
CSDN上有很多关于这方面的资料,但还是忍不住多说一句。你的很多理解都是错误的。
系统在堆中会给我创建两个对象?
是有两个String对象,但是,一个在堆里面,一个在常量池中。
去找堆中有没有这个字符串"hello"的缓存对象?
谁说的?
还是看字节码吧:
public static void main(java.lang.String[]);
Code:
Stack=3,……
[/Quote]
。。。
mengyalizuopeng 2010-12-02
  • 打赏
  • 举报
回复
很多困惑和疑问而且均来自于最基础的知识
折腾了一阵子又查了查书,终于对 String 这个特殊的对象有了点感悟

public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
}
}
有什么问题呢?

1. 来自 String 的忧虑
上面这段程序中,到底有几个对象呢?
可能很多人脱口而出:两个,s1 和 s2
为什么?
String 是 final 类,它的值不可变。
看起来似乎很有道理,那么来检测一下吧,稍微改动一下程序
就可以看到结果了:

public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
}
}
呵呵,很多人都会说已经不止两个对象了
编译并运行程序,输出:s1 == s2
啊!
为什么 s1 == s2 ?
== 分明是在说:s1 与 s2 引用同一个 String 对象 -- "Monday"!

2. 千变万化的 String
再稍微改动一下程序,会有更奇怪的发现:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
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");
}
}
我们将 s2 用 new 操作符创建
程序输出:
s1 != s2
s1 equals s2
嗯,很明显嘛
s1 s2分别引用了两个"Monday"String对象
可是为什么两段程序不一样呢?

3. 在 String 的游泳池中游泳
哈哈,翻了翻书终于找到了答案:
原来,程序在运行的时候会创建一个字符串缓冲池
当使用 s2 = "Monday" 这样的表达是创建字符串的时候,程序首先会
在这个String缓冲池中寻找相同值的对象,在第一个程序中,s1先被
放到了池中,所以在s2被创建的时候,程序找到了具有相同值的 s1
将 s2 引用 s1 所引用的对象"Monday"

第二段程序中,使用了 new 操作符,他明白的告诉程序:
“我要一个新的!不要旧的!”与是一个新的"Monday"Sting对象被创
建在内存中。他们的值相同,但是位置不同,一个在池中游泳
一个在岸边休息。哎呀,真是资源浪费,明明是一样的非要分开做什么呢?

4. 继续潜水
再次更改程序:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
s2 = s2.intern();
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");
}
}
这次加入:s2 = s2.intern();
哇!程序输出:
s1 == s2
s1 equals s2
原来,程序新建了 s2 之后,又用intern()把他打翻在了池里
哈哈,这次 s2 和 s1 有引用了同样的对象了
我们成功的减少了内存的占用

5. == 与 equals() 的争斗
String 是个对象,要对比两个不同的String对象的值是否相同
明显的要用到 equals() 这个方法
可是如果程序里面有那么多的String对象,有那么多次的要用到 equals ,
哦,天哪,真慢啊
更好的办法:
把所有的String都intern()到缓冲池去吧
最好在用到new的时候就进行这个操作
String s2 = new String("Monday").intern();
嗯,大家都在水池里泡着了吗?哈哈
现在我可以无所顾忌的用 == 来比较 String 对象的值了
真是爽啊,又快又方便!
lingxuch 2010-12-01
  • 打赏
  • 举报
回复
b=new String("hello");

第一,肯定会在堆中创建一个新对象,注意是新对象

第二,它要检查String 池中是否有"hello"这个对象,没有的话,会在常量池中生成一个

所以上面的代码是至少创建一个对象,但不一定会创建两个,因为在创建对象前可能会在string池中存在相应的对象了,至于b==a为false,那是因为b 指向的是new出来的新对象,而不是string池中的对象。
龙四 2010-12-01
  • 打赏
  • 举报
回复
现在 我在1处定义一个字符串 那么系统在堆中会给我创建两个对象 一个是new 出来的 一个是字符串常量"hello"
而我现在在2处在定义一个变量a 那么系统就会去找堆中有没有这个字符串"hello"的缓存对象
如果没有的话那么就会创建一个 如果有的话就指向那里 但是现在的情况堆中应该是有啊 为什么也输出false呢?



这种理解是不对的,确实是去找常量池中的对象,常量池中的对象也是在堆中,但不是去找堆中有没有hello
龙四 2010-12-01
  • 打赏
  • 举报
回复
常量池本身在方法区里,而方法区本身在jvm规范中并没有规定在哪里实现,可以在堆中,也可以在栈中,对于String str = "aaa"这样的东西,在方法区中的常量池有一个CONSTANT_String_info表中,这个表指向一个CONSTANT_UTF8_info表,而这个CONSTANT_UTF8_info指向堆中的"aaa"字符串

第一次执行String str = "aaa";的时候,堆中是没有aaa这个对象的,然而在编译的时候已经确定在方法区的常量池中会有这么一个标志,可能尚未被解析,第一次使用的时候会去解析这个常量池,并在堆中创建对象,当然,jvm实现也可以采用早解析或者迟解析或者两者都有的方式。


new String("aaa")的时候,只是再在堆中分配一个aaa的字符串对象而已
java_qq 2010-12-01
  • 打赏
  • 举报
回复
底层的东西,学习。
whut_lcy 2010-12-01
  • 打赏
  • 举报
回复
...............
fantasy0126 2010-12-01
  • 打赏
  • 举报
回复
忍不住说一声,常量池在栈里?不要胡说啦,栈里存的是执行代码好吧!常量池是属于类的,在方法区里,和类的定义存在一起的。哎,如果不清楚jvm的实现还是不要考虑这个问题啦,真的不合适
fengke01242010 2010-12-01
  • 打赏
  • 举报
回复
String a="hello";//在常量池中
String b=new String("hello");//一个有单独地址的对象
==比较的是内存地址,所以是false了
如果用equals来比较,就是true了
这个问题每周都会出现一次啊
水中影子 2010-12-01
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 sunyiz 的回复:]

String a="hello";//在常量池中
String b=new String("hello");//一个有单独地址的对象
==比较的是内存地址,所以是false了
如果用equals来比较,就是true了
这个问题每周都会出现一次啊
[/Quote]
+1
ov_bbs 2010-12-01
  • 打赏
  • 举报
回复
二楼,三楼的说的已经很清楚了
china__java 2010-12-01
  • 打赏
  • 举报
回复
呵呵,学习了
phenix33 2010-11-30
  • 打赏
  • 举报
回复
java中字符串池是存在于栈中还是存在于堆中?
很多人都会疑惑
应该说是在常量池中
phenix33 2010-11-30
  • 打赏
  • 举报
回复
http://topic.csdn.net/u/20101128/19/5f460114-7eac-490a-ba07-9611e43bf53d.html

LZ看看这里吧,已经讲解的够详细了
「已注销」 2010-11-30
  • 打赏
  • 举报
回复
也就是说 如果1 2 都是new的话同样是false 1 2 都不是new的时候才是true
加载更多回复(14)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧