在学习Java中的final时碰到困惑,求解释
在学习Java中的final时遇到困惑,求解释
有如下代码:
public class Final {
final String a;
public Final(){
a="g";
}
public void display(){
System.out.println(a=="g");
}
public static void main(String []args){
Final f=new Final();
f.display();
}
}
运行结果为true
再做修改:
public class Final {
final String a;
public Final(){
a="g";
}
public void display(){
System.out.println(a+a=="gg");
}
public static void main(String []args){
Final f=new Final();
f.display();
}
}
运行结果为false
有人解释说final字符串变量必须在编译时能够确定值的时候才能相等,但是为什么第一段代码相等时为true呢?
------解决方案--------------------
楼主这段代码真正的问题在于字符串的比较,和final 没有太多关系,建议楼主查查String 的 equal 方法和 “==”的区别
------解决方案--------------------
建议查查String 的 equal 方法和 == 的区别
------解决方案--------------------
第一个a直接对应字符串常量池中的"g",第二个2个"g"相加最终组成一个新的字符串"gg"
------解决方案--------------------
String 本身就是final的。final的意思是内存地址中的内容不可更改。貌似这个例子和final没太大关系。第一个相同,是因为内存地址一样,第二个不同是因为a+a会组成新的字符串指向新的内存地址。
------解决方案--------------------
字符串比较equals,==比的是两个所指向的堆
------解决方案--------------------
==这样的比较都是引用比较,即地址相比较,第一个的字符串‘’g“在常量区,两个的引用都指向同一个地址,所以为true;第二个a+a是将常量区的”g“拷贝出在组装成gg,这时已经是两个不同的地方的gg,所以他们的引用是不相同的,故为false
------解决方案--------------------
楼上已经说了很多了,lz需要明白字符串的一些机制了。
------解决方案--------------------
4、6楼说的有道理,本人在补充一点:
String a="g";
System.out.println(("g"+"g")=="gg");//true
System.out.println(a+a=="gg");//false
"g"、"gg"是真正的字符串对象且是常量,而a仅是引用。
String m="ja"+"av";相当于String m="java";其中:"ja"和“av”是常量已存在于池中。
而String m0="ja";String m1="av";String m2=m0+m1;这个过程中m0指向池内存中的“ja”;
m2 指向堆内存中“java”;所以当然不相等。“+”号会生成一个StringBuffer的对象然后再调用它的append方法。
------解决方案--------------------
抱歉,昨天说的有误,在此修改下。
String m0="ja";String m1="va";String m2=m0+m1;
判断m2=="java"中,m2是引用,而“java”是真正对象,所以这两个比较,当然不相等。
希望对楼主有帮助。
------解决方案--------------------
我用反编译工具查看了一下第二段java代码
------解决方案--------------------
这里不是Final 的问题,而是你的选择比较的问题。java中运算是从有到左的。System.out.println(a+a=="gg");这里是这样的,先判断a=="gg"然后前面a+a了,所以为false。你把前面a+a打上括号即可。
打印为true
------解决方案--------------------
final a = "g";
System.out.println(a=="g");
这时的常量a 是编译器可以确定的。
final a = "g";
System.out.println((a+a)=="g");
在这里 尽管a 也是可以确定的,但是这个+(加号)会产生不确定的因素,因此编译器不可以确定。
还有就是字符串常量池:String a =“g” 和 System.out.println((a =="g"); 他会比较两个 'g' 的地址,就从这个例子来看他们都是在字符串常量池里相同的引用。
至于a+a ,就是一个老生常谈的话题由于String 不可变的 所以 (a+a)会生成一个新的地址 从而不能与 "gg" 常量池里面的地址相同。
------解决方案--------------------
a+a 生成的还是一个引用,而a+a =="gg";==比较的是二者地址,"gg"是在池内存中的,而a+a是在堆内存的,所以二者不相等。
这个绝对是正解。
------解决方案--------------------
a+a 相当于 String s = new String(“gg”) ; 这样你就应该明白为啥为false了吧
------解决方案--------------------
你这解释是错的,难道你不知道==的运算等级是最低的吗?况且 你自己打印一下就知道答案是false。求不要装懂,误导不好。
有如下代码:
public class Final {
final String a;
public Final(){
a="g";
}
public void display(){
System.out.println(a=="g");
}
public static void main(String []args){
Final f=new Final();
f.display();
}
}
运行结果为true
再做修改:
public class Final {
final String a;
public Final(){
a="g";
}
public void display(){
System.out.println(a+a=="gg");
}
public static void main(String []args){
Final f=new Final();
f.display();
}
}
运行结果为false
有人解释说final字符串变量必须在编译时能够确定值的时候才能相等,但是为什么第一段代码相等时为true呢?
------解决方案--------------------
楼主这段代码真正的问题在于字符串的比较,和final 没有太多关系,建议楼主查查String 的 equal 方法和 “==”的区别
------解决方案--------------------
建议查查String 的 equal 方法和 == 的区别
------解决方案--------------------
第一个a直接对应字符串常量池中的"g",第二个2个"g"相加最终组成一个新的字符串"gg"
------解决方案--------------------
String 本身就是final的。final的意思是内存地址中的内容不可更改。貌似这个例子和final没太大关系。第一个相同,是因为内存地址一样,第二个不同是因为a+a会组成新的字符串指向新的内存地址。
------解决方案--------------------
字符串比较equals,==比的是两个所指向的堆
------解决方案--------------------
==这样的比较都是引用比较,即地址相比较,第一个的字符串‘’g“在常量区,两个的引用都指向同一个地址,所以为true;第二个a+a是将常量区的”g“拷贝出在组装成gg,这时已经是两个不同的地方的gg,所以他们的引用是不相同的,故为false
------解决方案--------------------
楼上已经说了很多了,lz需要明白字符串的一些机制了。
------解决方案--------------------
4、6楼说的有道理,本人在补充一点:
String a="g";
System.out.println(("g"+"g")=="gg");//true
System.out.println(a+a=="gg");//false
"g"、"gg"是真正的字符串对象且是常量,而a仅是引用。
String m="ja"+"av";相当于String m="java";其中:"ja"和“av”是常量已存在于池中。
而String m0="ja";String m1="av";String m2=m0+m1;这个过程中m0指向池内存中的“ja”;
m2 指向堆内存中“java”;所以当然不相等。“+”号会生成一个StringBuffer的对象然后再调用它的append方法。
------解决方案--------------------
抱歉,昨天说的有误,在此修改下。
String m0="ja";String m1="va";String m2=m0+m1;
判断m2=="java"中,m2是引用,而“java”是真正对象,所以这两个比较,当然不相等。
希望对楼主有帮助。
------解决方案--------------------
我用反编译工具查看了一下第二段java代码
import java.io.PrintStream;楼主应该看到了吧,a+a那块,新生成了类。说明他应该存放在了堆。而“gg”存放在栈,所以导致的不想等
public class Final
{
final String a = "g";
public Final()
{
}
public void display()
{
System.out.println((new StringBuilder(String.valueOf(a))).append(a).toString() == "gg");
}
public static void main(String args[])
{
Final f = new Final();
f.display();
}
}
------解决方案--------------------
这里不是Final 的问题,而是你的选择比较的问题。java中运算是从有到左的。System.out.println(a+a=="gg");这里是这样的,先判断a=="gg"然后前面a+a了,所以为false。你把前面a+a打上括号即可。
System.out.println((a+a)=="gg");
打印为true
------解决方案--------------------
final a = "g";
System.out.println(a=="g");
这时的常量a 是编译器可以确定的。
final a = "g";
System.out.println((a+a)=="g");
在这里 尽管a 也是可以确定的,但是这个+(加号)会产生不确定的因素,因此编译器不可以确定。
还有就是字符串常量池:String a =“g” 和 System.out.println((a =="g"); 他会比较两个 'g' 的地址,就从这个例子来看他们都是在字符串常量池里相同的引用。
至于a+a ,就是一个老生常谈的话题由于String 不可变的 所以 (a+a)会生成一个新的地址 从而不能与 "gg" 常量池里面的地址相同。
------解决方案--------------------
a+a 生成的还是一个引用,而a+a =="gg";==比较的是二者地址,"gg"是在池内存中的,而a+a是在堆内存的,所以二者不相等。
这个绝对是正解。
------解决方案--------------------
a+a 相当于 String s = new String(“gg”) ; 这样你就应该明白为啥为false了吧
------解决方案--------------------
你这解释是错的,难道你不知道==的运算等级是最低的吗?况且 你自己打印一下就知道答案是false。求不要装懂,误导不好。