java中的字符串比较问题:为什么s1和s2不相等,s1和s3相等

public class Test {
public static void main(String[] args) {
String s1 = "length: 10";
String s2 = "length: "+s1.length();
String s3 = "length: " + 10;
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
System.out.println(s1 == s2);
System.out.println(s1 == s3);
}
}
希望有高手能把String的怎么在堆栈开辟的解释清楚点,并把上面的问题解释通俗点,谢谢
最新回答
雪蝶宿秋风

2024-11-07 01:37:51

你分析一下内存就很好理解了,我把图画出来了

当定义s3的时候系统会自动把"length: " + 10 转换成 “length: 10” ,让后看看栈空间里面有没有这个值存在,如果有的话就不会在划分空间来存放,直接引用已经存在的值,所以s1跟s3同时引用的都是"length: 10",但s2里面有s1.length()这个是需要通过计算的,每次计算出来的临时的值都会存放在堆空间里面,所以他们引用的地址是不同的,你看看图吧,

你可以测试一下String s4 = "length: "+s1.length(); System.out.println(s2 == s4); 出来的结果应该是false的,因为他们临时计算出来的值的地址都不一样的。希望你能理解吧,你看看马士兵的视频,有讲java的变量内存分配的

姐丶心已打烊

2024-11-07 02:45:55

你这个问题,实质是Java中字符串比较的问题。

(1)问题所在。

Java中判断两个字符串“内容”是否一样,要调用String的equals方法。Java中的“==”比较的是两个字符串的存储地址是否相等。

(2)分析

正如你的程序的运行结果所示,三个字符串的哈希码是一样的,这表明它们的内容完全一样。但它们在内存中的存储地址是不一样的,要了解为什么会这样,需要深入理解Java虚拟机的运行机制,推荐你参考《Java编程思想》一书。

(3)程序修改与验证

将你的程序修改如下:

public class Test {

public static void main(String[] args) {

 String s1 = "length: 10";

 String s2 = "length: "+s1.length();

 String s3 = "length: " + 10;

 System.out.println(s1);

 System.out.println(s2);

 System.out.println(s3);

 System.out.println(s1.hashCode());

 System.out.println(s2.hashCode());

 System.out.println(s3.hashCode());

 System.out.println(s1 == s2);

 System.out.println(s1 == s3);

 System.out.println(s1.equals(s2));//增加部分

 System.out.println(s1.equals(s3));//增加部分

}

}

程序的运行结果如截图所示。

追问
我想知道的是为什么s1和s2地址不相等而s1和s3地址相等
凉城无爱

2024-11-07 06:11:50

分太少了,就简单说了,首先要知道==比较的是引用,equals比较的是内容。其次还要知道引用放置在栈内,内容放置在堆内。再其次要知道这里没有使用new所以所有数值都是要进入常量池进行比较。当程序加载的时候常量池中存储的有length: 10、10、length: 、s1.length(),其中常量10和length是没有任何引用指向它们的。而length: 10是有s1引用指向它的。s1.length()也是有引用指向的,只不过没有体现出来,或者说s1.length()可以看成是int i=10;或者int i=s1.length();所以这里的s1.length()这个常量10是有引用的指向的一个常量,所以跟上面那个没有引用指向的10是有区别的,而==恰恰是比较引用的,既然引用都不同了,拼接后的引用s2自然跟s1和s3都不一样。所以s2无论是跟s1比较还是跟s3比较结果都是false。
失约

2024-11-07 10:33:53

这个问题是字符串缓冲池的问题。
String对象的声明有两种格式,一种是类似基本数据类型的声明格式,如下:
String m ="test";
还有一种是对象的声明格式
String m = new String("test");
在进行字符串的+运算时,+会去检索参与运算的双方是格式1的形式还是格式2的形式。
格式1的形式的两个字符串加认为是在栈内存中的字符串连接后重定向,产生一个新的字符串对象,并且存放在栈内从中。
而如果参加加运算的双方中只要有一个是引用类型的,则运算实际上是将结果放到字符串缓冲池中。字符串缓冲池是一个内存空间,里面存放+运算的临时结果。
例如:
"a"+"b"不放入缓冲池中
String m = "a"; m+"b" 就要放入缓冲池。而且这里还有一个特殊的现象,如下:
m+"b"放入缓冲池,再执行m+"b"仍然放入缓冲池,并且缓冲池中的地址还不一样,是两块空间。换句话说String m = "a"; m+m==m+m 的结果是false。
返回你的题目来看
String s1 = "length: 10";
String s2 = "length: "+s1.length();//这里的s1.length()是个引用
String s3 = "length: " + 10;//这里的10就不是引用了
不知道这样解释你是否明白。
如果想把字符串缓冲池中的内容标准化,就是转换到栈内存中,可以使用String类中的intern()方法,这个就是专门做这个功能的。
追问
我看看,我也觉得是常量池的问题,自己不是很了解这个,就想请个高手了解下
追答
哇靠,你这个追问让我如何回答?我无语。
追问
哈哈,不是还是没明白,能解释得再通俗点吗
追答
把术语去掉就没有真实原理了,加上术语看不明白,让我如何是好?
简单来说吧
+两边只要有引用的东西,结果就进入字符串缓冲池,如果没有就直接连接两个字符串。
直接连接的字符串只要内容一样地址就一样,而缓冲池中的东西每次连接均会有一个全新的副本,也就拥有不同的地址信息,所以==是不一样的。
这样够吗?
追问
我觉得你说得有道理,但是我没完全明白你的意思,最好通俗点
追答
我已经够俗的了。
真的没法再俗了,如果你还不能理解,我也没办法了。你需要补充一下基础概念了。
追问
谢谢了
追答
不客气
︷决戰紫禁之巓︷

2024-11-07 00:11:53

String s1 = "length: 10";
这种定义对象存放在内存的对象池中
String s3 = "length: " + 10;
这用定义和上面一样,因为10为常量,编译时会被优化
成: String s1 = "length: 10";这种形式
在对象池中如果两个值相等,就不开辟新的空间,用同一个地址
所以s1和s3地址相等。

String s2 = "length: "+s1.length();
注意:这个它不会优化 ,因为 s1.length();为变量
还注意String类的特点,它是恒值的,即赋值后不能变
所以当要改变值时会新建一个对象,引用指向新建的对象

地址当然会改变了
String s2 = "length: "+s1.length();
会新建一个对象在执行“+s1.length();”操作时
在编译阶段:s1和s2是不同地址s1和s3是同一个地址,因为s2的值不确定,s2
的值在运用阶段才确定。

在运行阶段:s1地址不变,s2地址会改变,会生成新的对象

所以:不管在什么时间s1和s2地址都是不一样的