首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > Java相关 >

,一个字符串地址的有关问题

2013-09-18 
求助,一个字符串地址的问题!String s1 aString s2 s1+ bString s3 a + bSystem.out.prin

求助,一个字符串地址的问题!



String s1 = "a";
String s2 = s1+ "b";
String s3 = "a" + "b";
System.out.println(s2 == "ab");
System.out.println(s3 == "ab");


结果是:false,true

为什么前面输出时false,而且s2指向的内容是"ab"
[解决办法]
自己写了一个类测试了一下,如下:

public class StringTest {

/**
 * @param args
 */
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1 = "a";
String s2 = s1+ "b";
String s3 = "a" + "b";
System.out.println(s2 == "ab");
System.out.println(s3 == "ab");
}

}


反编译之后main方法的字节码如下:

public static void main(java.lang.String[]);
  Code:
   Stack=3, Locals=4, Args_size=1
   0:   ldc     #16; //String a
   2:   astore_1
   3:   new     #18; //class java/lang/StringBuilder
   6:   dup
   7:   aload_1
   8:   invokestatic    #20; //Method java/lang/String.valueOf:(Ljava/lang/Objec
t;)Ljava/lang/String;
   11:  invokespecial   #26; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
   14:  ldc     #29; //String b
   16:  invokevirtual   #31; //Method java/lang/StringBuilder.append:(Ljava/lang
/String;)Ljava/lang/StringBuilder;
   19:  invokevirtual   #35; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
   22:  astore_2
   23:  ldc     #39; //String ab
   25:  astore_3


   26:  getstatic       #41; //Field java/lang/System.out:Ljava/io/PrintStream;
   29:  aload_2
   30:  ldc     #39; //String ab
   32:  if_acmpne       39
   35:  iconst_1
   36:  goto    40
   39:  iconst_0
   40:  invokevirtual   #47; //Method java/io/PrintStream.println:(Z)V
   43:  getstatic       #41; //Field java/lang/System.out:Ljava/io/PrintStream;
   46:  aload_3
   47:  ldc     #39; //String ab
   49:  if_acmpne       56
   52:  iconst_1
   53:  goto    57
   56:  iconst_0
   57:  invokevirtual   #47; //Method java/io/PrintStream.println:(Z)V
   60:  return
}



从上面的信息可以看出,在String s2 = s1+ "b";这一行,
编译优化后首先是先new了一个StringBuilder,然后把通过StringBuilder把s1和"b"连接,再赋值给s2,所以s2的值应该是StringBuilder.toString()返回对象的引用,而这个赋值应该是在运行时。
而s1和s3在编译时已经赋值分别为"a"和"ab"。

如果把s1定义成final的话,返回都是true;

public class StringTest {

/**
 * @param args
 */
public static void main(String[] args) {
// TODO Auto-generated method stub
final String s1 = "a";
String s2 = s1+ "b";
String s3 = "a" + "b";
System.out.println(s2 == "ab");
System.out.println(s3 == "ab");
}

}

反编译后的main方法的字节码:


public static void main(java.lang.String[]);
  Code:
   0:   ldc     #16; //String a
   2:   astore_1
   3:   ldc     #18; //String ab
   5:   astore_2
   6:   ldc     #18; //String ab
   8:   astore_3
   9:   getstatic       #20; //Field java/lang/System.out:Ljava/io/PrintStream;
   12:  aload_2


   13:  ldc     #18; //String ab
   15:  if_acmpne       22
   18:  iconst_1
   19:  goto    23
   22:  iconst_0
   23:  invokevirtual   #26; //Method java/io/PrintStream.println:(Z)V
   26:  getstatic       #20; //Field java/lang/System.out:Ljava/io/PrintStream;
   29:  aload_3
   30:  ldc     #18; //String ab
   32:  if_acmpne       39
   35:  iconst_1
   36:  goto    40
   39:  iconst_0
   40:  invokevirtual   #26; //Method java/io/PrintStream.println:(Z)V
   43:  return

}



从上面的信息可以看出,如果s1是字符串常量的话,是直接对s2赋值,在编译期就确定了s2的值。

因此个人认为对编译器对String的"+"处理是如果都是常量字符串或者变量都是字符串常量,在编译时就直接赋值;而涉及到另外的变量或者变量是非常量字符串就用StringBuilder进行优化。
[解决办法]
引用:
Quote: 引用:

第一个和第三个应该是在栈区创建的对象,
第二个是在堆区创建的。
第三局
String s3 = "a" + "b"; 和
String s3 = "ab";
性质一样。 


对象不会在栈区,对象引用:
Quote: 引用:

第一个和第三个应该是在栈区创建的对象,
第二个是在堆区创建的。
第三局
String s3 = "a" + "b"; 和
String s3 = "ab";
性质一样。 
那s2是怎么获取它的内容的呢?


有可能我的表达有问题,应该是第一个和第三个对象的引用在栈区,对象的值也在栈区。
栈区是可以存放基本数据类型和字符值的,并且存在栈区的值是共享的
详见:http://blog.csdn.net/rzleilei/article/details/11670061
[解决办法]
首先 == 比较的是对象的地址,String s2 = s1+ "b";s1是"a"的一个string类型的对象引用,加上了"b"的对象地址,所以,此时s2的引用地址已经发生了转移,也就是说s2的地址可能由内存的第一块指向了第二块地址,地址不连续了。

而s3的"ab"地址跟"a"+"b"的地址是一样的。他们的地址还是在一块内存地址里,只是偏移了,都是一段连续的地址。

如果你用equals的话应该返回的都是true。  
[解决办法]
引用:
Quote: 引用:

Quote: 引用:

第一个和第三个应该是在栈区创建的对象,
第二个是在堆区创建的。
第三局
String s3 = "a" + "b"; 和


String s3 = "ab";
性质一样。 



对象不会在栈区,对象引用:
Quote: 引用:

第一个和第三个应该是在栈区创建的对象,
第二个是在堆区创建的。
第三局
String s3 = "a" + "b"; 和
String s3 = "ab";
性质一样。 
那s2是怎么获取它的内容的呢?


有可能我的表达有问题,应该是第一个和第三个对象的引用在栈区,对象的值也在栈区。
栈区是可以存放基本数据类型和字符值的,并且存在栈区的值是共享的
详见:http://blog.csdn.net/rzleilei/article/details/11670061

那个博客是纯粹胡扯的,从前有一个没有计算机基础的初学者,发明了栈中存字符串,栈数据共享的概念。转的人多了,然后很多人就当成真的了……
[解决办法]
可参考网站:http://blog.csdn.net/gaopeng0071/article/details/11741027
之前仅知道 == 比较的地址 equals比较的是内容。
也和你一起共同学习了。
详见代码中的注解
public static void main(String[] args) {
String s1 = "a";
String s2 = s1 + "b";
String s3 = "a" + "b";
/*
 * JVM对于字符串引用,由于在字符串的"+"连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,即s1 +
 * "b"无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给s2。所以下面程序的结果也就为false。
 */
System.out.println(s2 == "ab");
/*
 * "a" "b" 都是一个字符串常量,所以+后的s3也是常量,它们在编译期就被确定了,所以s3就是常量池的一个引用,所以s3 == "ab" 就为true
 */
System.out.println(s3 == "ab");
}

热点排行