final修饰的字符串String用 == 比较的问题

那_年 2016-11-01 03:25:08
String比较有两种,==与equals();
==比较的是地址
equals比较的是值。那么 下面程序求解释下。主要是final修饰后用==比较为true

public class test3 {
public static void main(String[] args) {
String a = "hello2";
final String b = "hello";
String d = "hello";
String c = b + 2;
String e = d + 2;
System.out.println(c);
System.out.println(e);

System.out.println((a == c));
System.out.println((a == e));

System.out.println(a.equals(c));
System.out.println(a.equals(e));

}
}


运行结果:
hello2
hello2
true
false
true
true

怎么解释a == c,结果为true。
public class Test {
public static void main(String[] args) {
String a = "hello2";
final String b = getHello();
String c = b + 2;
System.out.println((a == c));

}

public static String getHello() {
return "hello";
}
}


结果:
false

又怎么解释这个结果为false
...全文
1018 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
Forward233 2019-11-16
  • 打赏
  • 举报
回复
引用 5 楼 自由自在_Yu 的回复:

        String a = "hello2"; 
        final String b = "hello";
        String d = "hello";
        String c = b + 2; 
        String e = d + 2;
怎么解释a == c,结果为true。 对于a来说,hello2保存在堆内存中,在栈中分配一个地址 地址a-->hello2 分配对于c来说,b是一个常量,开始是保存在常量池中的,当执行b+2时, 才会把b+2当成一个新的字符串hello2取出来,然后读取内存发现已经存在了 hello2,所以不再创建,直接把c指向a在内存中的地址,因此a == c; 对于d,内存中原来是不存在hello的,所以执行到d的时候就会在内存中新开辟一个地址 用于保存hello,这样执行d+2的时候,e指向的地址不是a,所以e != a
瞎几把扯啊 ,String d = "hello";之前final String b = "hello";hello已经在常量池了好吧,怎么会开辟新的常量。。。直接引用啊
Forward233 2019-11-16
  • 打赏
  • 举报
回复
引用 1 楼 lercent 的回复:
这其实和内存有关,不是由final引起的,我们都知道字符串是对象,存在内存中的堆中,例如 String x = “a”,对象“a”是在堆里,然后把“a”的地址赋给变量x,String y = “a”,正常情况下是再在堆里创建一个新的对象“a”,在把地址赋给y。但java是做了优化的,这些简单字符串如果在堆里已经有了,在某些情况下(具体哪些,这个就要深入jvm了)就不创建新的了,直接把之前的“a”对象地址赋给了y。所以会出现你那种情况。不信内可以试试这段代码: String a = "a"; String b = "a"; System.out.println(a == b);//true
你连楼主问的都没看明白,瞎回答啥呢
ps45221 2016-11-09
  • 打赏
  • 举报
回复
引用 10 楼 mlbblkss 的回复:
一直没有结贴是因为之前没有接触JVM原理,最近看了JVM原理,再回头看各位前辈的回复,豁然开朗。
自己总结一下。java中String是被看做对象的。String s="hello",在编译的时候会被替换成String s=new String("hello")。它的引用过程是这样的,首先new的时候,查看内存(堆)中是不是存在字面值是"hello"的字符串,如果存在,则直接指向这个字符串的引用对象,如果不存在,就创建一个对象。比如对象o,字面值为"hello",s指向这个对象o,这里值得注意的是,对象在堆中也是有自身的引用的,指向对象元素的首地址,栈中的对象变量指向堆中的对象引用。而String类型对象被看做值不变对象,就是说一旦值发生变化,就会查看是否有字面值一样的对象,有则指向,无则创建。
而final修饰的字符串,就和楼上几位前辈说的一样,在编译的时候,就已经被替换为"hello"了,并没有存储在内存中。懂了这些原理,处理这些问题就简单多了。

但是现在貌似又发现了个新问题,就是字符串连接的原理是什么,这个百度搜索都不好搜,还是请各位帮忙看看,代码如下:
public class T {
public static void main(String[] args) {
String a = "hello";
String a1 = "hello";
String d = a+2;
String d1 = a1+2;
System.out.println((d == d1));
}
}


结果是:false

这个结果说明,d和d1是值相同,但引用地址不同的两个对象。求帮忙解释下原因

Ok,这贴还挺纠结的。
首先字符串连接,就是加号,这个原理就是StringBuilder,然后append,最后toString,相当于new 出来的string,所以d != d1.
有种情况比较特殊,就是用final常量,上面已经解释过了,不再详细说明。
最好的方法就是看字节码:


那_年 2016-11-08
  • 打赏
  • 举报
回复
@lercent @Sun1956 @yuxiangaaaaa 看看是不是这样圈人。。 如果圈对的话,请帮忙看看楼上的问题。
那_年 2016-11-08
  • 打赏
  • 举报
回复
一直没有结贴是因为之前没有接触JVM原理,最近看了JVM原理,再回头看各位前辈的回复,豁然开朗。 自己总结一下。java中String是被看做对象的。String s="hello",在编译的时候会被替换成String s=new String("hello")。它的引用过程是这样的,首先new的时候,查看内存(堆)中是不是存在字面值是"hello"的字符串,如果存在,则直接指向这个字符串的引用对象,如果不存在,就创建一个对象。比如对象o,字面值为"hello",s指向这个对象o,这里值得注意的是,对象在堆中也是有自身的引用的,指向对象元素的首地址,栈中的对象变量指向堆中的对象引用。而String类型对象被看做值不变对象,就是说一旦值发生变化,就会查看是否有字面值一样的对象,有则指向,无则创建。 而final修饰的字符串,就和楼上几位前辈说的一样,在编译的时候,就已经被替换为"hello"了,并没有存储在内存中。懂了这些原理,处理这些问题就简单多了。 但是现在貌似又发现了个新问题,就是字符串连接的原理是什么,这个百度搜索都不好搜,还是请各位帮忙看看,代码如下:
public class T {
    public static void main(String[] args)  {
    	String a = "hello"; 
    	String a1 = "hello"; 
    	String d = a+2; 
    	String d1 = a1+2; 
    	 System.out.println((d == d1));		
    }
}
结果是:false 这个结果说明,d和d1是值相同,但引用地址不同的两个对象。求帮忙解释下原因
自由自在_Yu 2016-11-02
  • 打赏
  • 举报
回复

        String a = "hello2"; 
        final String b = "hello";
        String d = "hello";
        String c = b + 2; 
        String e = d + 2;
怎么解释a == c,结果为true。 对于a来说,hello2保存在堆内存中,在栈中分配一个地址 地址a-->hello2 分配对于c来说,b是一个常量,开始是保存在常量池中的,当执行b+2时, 才会把b+2当成一个新的字符串hello2取出来,然后读取内存发现已经存在了 hello2,所以不再创建,直接把c指向a在内存中的地址,因此a == c; 对于d,内存中原来是不存在hello的,所以执行到d的时候就会在内存中新开辟一个地址 用于保存hello,这样执行d+2的时候,e指向的地址不是a,所以e != a
自由自在_Yu 2016-11-02
  • 打赏
  • 举报
回复
引用 2 楼 Sun1956 的回复:
首先第一个问题,

String a = "hello2";
final String b = "hello";
String d = "hello";
String c = b + 2; 
这里b被你声明成了final的了,所以就是常量,常量表达式String c = b + 2;,JVM会优化成String c = "hello" + 2;,这个结果是变成编译期就是已知了,指向常量池中的hello2字符串,也就是a。 第二个问题:明白了第一个问题,你就应该自己知道了,因为这里的b虽然是常量,但是在编译期是不能获得值的,只有在运行的时候才会调用函数,初始化赋值,所以这时的String c = b+2是运行期间计算出来的,而加号连接运算符,内部则是调用的StringBuilder,然后toString,所以c相当于是new出来的String,即c是指向堆内存的地址,c内部的char数组才指向常量池中的字符串,所以明显a != c
扯了一堆 跟人家的答案不一样啊
sky_08_06_02 2016-11-02
  • 打赏
  • 举报
回复
自由自在_Yu 2016-11-02
  • 打赏
  • 举报
回复
引用 8 楼 Sun1956 的回复:
[quote=引用 7 楼 yuxiangaaaaa 的回复:] [quote=引用 6 楼 Sun1956 的回复:] [quote=引用 5 楼 yuxiangaaaaa 的回复:]

        String a = "hello2"; 
        final String b = "hello";
        String d = "hello";
        String c = b + 2; 
        String e = d + 2;
怎么解释a == c,结果为true。 对于a来说,hello2保存在堆内存中,在栈中分配一个地址 地址a-->hello2 分配对于c来说,b是一个常量,开始是保存在常量池中的,当执行b+2时, 才会把b+2当成一个新的字符串hello2取出来,然后读取内存发现已经存在了 hello2,所以不再创建,直接把c指向a在内存中的地址,因此a == c; 对于d,内存中原来是不存在hello的,所以执行到d的时候就会在内存中新开辟一个地址 用于保存hello,这样执行d+2的时候,e指向的地址不是a,所以e != a
麻烦你去看下字节码,String c = b + 2;是不是像你说的这样,是运行生成的? 你编译完之后,用javap看下,c就已经是hello2了,根本没有执行这个加号拼接这个操作。 [/quote] 你写的 自己执行一下 就知道是a == c 了呀,你分析的结果是明显a != c[/quote] 那个String c = b+2;是对应题主第二个问题里面的代码,明明加了分隔,没有显示

////问题1
String a = "hello2";
final String b = "hello";
String d = "hello";
///问题2
String c = b + 2;
[/quote] 好吧 我说呢,怎么分析半天得出个错误的结果
ps45221 2016-11-02
  • 打赏
  • 举报
回复
引用 7 楼 yuxiangaaaaa 的回复:
[quote=引用 6 楼 Sun1956 的回复:] [quote=引用 5 楼 yuxiangaaaaa 的回复:]

        String a = "hello2"; 
        final String b = "hello";
        String d = "hello";
        String c = b + 2; 
        String e = d + 2;
怎么解释a == c,结果为true。 对于a来说,hello2保存在堆内存中,在栈中分配一个地址 地址a-->hello2 分配对于c来说,b是一个常量,开始是保存在常量池中的,当执行b+2时, 才会把b+2当成一个新的字符串hello2取出来,然后读取内存发现已经存在了 hello2,所以不再创建,直接把c指向a在内存中的地址,因此a == c; 对于d,内存中原来是不存在hello的,所以执行到d的时候就会在内存中新开辟一个地址 用于保存hello,这样执行d+2的时候,e指向的地址不是a,所以e != a
麻烦你去看下字节码,String c = b + 2;是不是像你说的这样,是运行生成的? 你编译完之后,用javap看下,c就已经是hello2了,根本没有执行这个加号拼接这个操作。 [/quote] 你写的 自己执行一下 就知道是a == c 了呀,你分析的结果是明显a != c[/quote] 那个String c = b+2;是对应题主第二个问题里面的代码,明明加了分隔,没有显示

////问题1
String a = "hello2";
final String b = "hello";
String d = "hello";
///问题2
String c = b + 2;
自由自在_Yu 2016-11-02
  • 打赏
  • 举报
回复
引用 6 楼 Sun1956 的回复:
[quote=引用 5 楼 yuxiangaaaaa 的回复:]

        String a = "hello2"; 
        final String b = "hello";
        String d = "hello";
        String c = b + 2; 
        String e = d + 2;
怎么解释a == c,结果为true。 对于a来说,hello2保存在堆内存中,在栈中分配一个地址 地址a-->hello2 分配对于c来说,b是一个常量,开始是保存在常量池中的,当执行b+2时, 才会把b+2当成一个新的字符串hello2取出来,然后读取内存发现已经存在了 hello2,所以不再创建,直接把c指向a在内存中的地址,因此a == c; 对于d,内存中原来是不存在hello的,所以执行到d的时候就会在内存中新开辟一个地址 用于保存hello,这样执行d+2的时候,e指向的地址不是a,所以e != a
麻烦你去看下字节码,String c = b + 2;是不是像你说的这样,是运行生成的? 你编译完之后,用javap看下,c就已经是hello2了,根本没有执行这个加号拼接这个操作。 [/quote] 你写的 自己执行一下 就知道是a == c 了呀,你分析的结果是明显a != c
ps45221 2016-11-02
  • 打赏
  • 举报
回复
引用 5 楼 yuxiangaaaaa 的回复:

String a = "hello2";
final String b = "hello";
String d = "hello";
String c = b + 2;
String e = d + 2;

怎么解释a == c,结果为true。
对于a来说,hello2保存在堆内存中,在栈中分配一个地址 地址a-->hello2
分配对于c来说,b是一个常量,开始是保存在常量池中的,当执行b+2时,
才会把b+2当成一个新的字符串hello2取出来,然后读取内存发现已经存在了
hello2,所以不再创建,直接把c指向a在内存中的地址,因此a == c;
对于d,内存中原来是不存在hello的,所以执行到d的时候就会在内存中新开辟一个地址
用于保存hello,这样执行d+2的时候,e指向的地址不是a,所以e != a

麻烦你去看下字节码,String c = b + 2;是不是像你说的这样,是运行生成的?
你编译完之后,用javap看下,c就已经是hello2了,根本没有执行这个加号拼接这个操作。



ps45221 2016-11-01
  • 打赏
  • 举报
回复
首先第一个问题,

String a = "hello2";
final String b = "hello";
String d = "hello";
String c = b + 2; 
这里b被你声明成了final的了,所以就是常量,常量表达式String c = b + 2;,JVM会优化成String c = "hello" + 2;,这个结果是变成编译期就是已知了,指向常量池中的hello2字符串,也就是a。 第二个问题:明白了第一个问题,你就应该自己知道了,因为这里的b虽然是常量,但是在编译期是不能获得值的,只有在运行的时候才会调用函数,初始化赋值,所以这时的String c = b+2是运行期间计算出来的,而加号连接运算符,内部则是调用的StringBuilder,然后toString,所以c相当于是new出来的String,即c是指向堆内存的地址,c内部的char数组才指向常量池中的字符串,所以明显a != c
lercent 2016-11-01
  • 打赏
  • 举报
回复
这其实和内存有关,不是由final引起的,我们都知道字符串是对象,存在内存中的堆中,例如 String x = “a”,对象“a”是在堆里,然后把“a”的地址赋给变量x,String y = “a”,正常情况下是再在堆里创建一个新的对象“a”,在把地址赋给y。但java是做了优化的,这些简单字符串如果在堆里已经有了,在某些情况下(具体哪些,这个就要深入jvm了)就不创建新的了,直接把之前的“a”对象地址赋给了y。所以会出现你那种情况。不信内可以试试这段代码: String a = "a"; String b = "a"; System.out.println(a == b);//true

62,614

社区成员

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

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