String字符串的一些理解

 
 

例子:

String str1 = "a" + "b" + "c";  //内存地址1(常量池:编译时已转换为"abc")
String str2 = "abc";            //内存地址1(常量池)
String str3 = "ab";//(常量池)
final String str4 = "ab"; //(常量池)
String str5 = str3 + "c";       //内存地址3(堆内存:由于编译的时候不能确定str3的值,所以利用StringBuffer拼接字符串)
String str6 = str4 + "c";       //内存地址1(常量池:由于str4用final定义,则不可以修改,因此编译时直接拼接为"abc")
String str7 = new String("abc");    //内存地址4(堆内存)
String str8 = new String(str2);            //内存地址5(堆内存)

Log.i(TAG, "str1 == str2  " + (str1 == str2)); //true
Log.i(TAG, "str1.equals(str2)  " + str1.equals(str2) + "\n"); //true

Log.i(TAG, "str1 == str5  " + (str1 == str5)); //false
Log.i(TAG, "str1.equals(str5)  " + str1.equals(str5) + "\n"); //true
Log.i(TAG, "str1 == str6  " + (str1 == str6)); //true
Log.i(TAG, "str1.equals(str6)  " + str1.equals(str6) + "\n"); //true

Log.i(TAG, "str1 == str7  " + (str1 == str7)); //false
Log.i(TAG, "str1.equals(str7)  " + str1.equals(str7) + "\n"); //true
Log.i(TAG, "str1 == str8  " + (str1 == str8)); //false
Log.i(TAG, "str1.equals(str8)  " + str1.equals(str8) + "\n"); //true
Log.i(TAG, "str7 == str8  " + (str7 == str8)); //false
Log.i(TAG, "str7.equals(str8)  " + str7.equals(str8) + "\n"); //true

打印结果:

05-30 17:48:44.051 3057-3057/ str1 == str2  true
05-30 17:48:44.051 3057-3057/ str1.equals(str2)  true
05-30 17:48:44.051 3057-3057/ str1 == str5  false
05-30 17:48:44.051 3057-3057/ str1.equals(str5)  true
05-30 17:48:44.051 3057-3057/ str1 == str6  true
05-30 17:48:44.051 3057-3057/ str1.equals(str6)  true
05-30 17:48:44.051 3057-3057/ str1 == str7  false
05-30 17:48:44.051 3057-3057/ str1.equals(str7)  true
05-30 17:48:44.051 3057-3057/ str1 == str8  false
05-30 17:48:44.051 3057-3057/ str1.equals(str8)  true
05-30 17:48:44.051 3057-3057/ str7 == str8  false
05-30 17:48:44.051 3057-3057/ str7.equals(str8)  true

分析:

个人理解:

常量池:常量存放区域,方便对象重复利用。

栈:定义的属性存放区域

堆:new出来的对象存放的区域

方法区:存放静态变量,静态代码块等

1.str1分析:

String str1 = "a" + "b" + "c";

"a" + "b" + "c"在编译的时候,会被编译器优化为"abc",存在于常量池。

内存关系:栈内存的变量str1的指针指向于常量池的字符串"abc"。

2.str2分析:

String str2 = "abc";

"abc",存在于常量池,str2存在于栈内存

内存关系:栈内存的变量str2的指针指向于常量池的字符串"abc"。

3.str5分析:

String str3 = "ab";

String str5 = str3 + "c";

由于str3是一个变量,所以在编译期间jvm,并不能将直接转换为字符串"abc",而是首先创建一个StringBuilder类,再

用StringBuilder类的append方法将str3和字符串"c"拼接,最后通过StringBuilder的toString()方法返回一个

String赋值给str5,因为字符串"abc"是new出来的所以存在于堆内存。

内存关系:栈内存的变量str5的指针指向于堆内存的String对象,堆内存的String对象指针指向于常量池的字符串对象"abc"。

4.str6分析:

final String str4 = "ab";

String str6 = str4 + "c";

由于变量str4被final修饰,意味着不能修改,因此编译器在编译阶段就会将str4 + "c"简化为字符串"abc",]存在于常

量池。

内存关系:栈内存变量str6的指针指向常量池的字符串"abc"。

5.str7分析:

String str7 = new String("abc");

首先编译器会在常量池当中寻找是否有字符串"abc",假如没有,则会在常量池当中创建字符串"abc",new String("abc")

调用了String类的参数为String的构造方法,这个方法最主要做的事情就是创建一个String对象,并且将"abc"的值浅拷贝

一份给String对象,接着将String对象赋值给str7。

内存关系:栈内存变量str7的指针指向堆内存的String对象,堆内存的String对象指向常量池的"abc"对象。

6.str8分析:

String str2 = "abc";            //内存地址1(常量池)

String str8 = new String(str2);

由于String str2 = "abc";在前面已经确认了字符串"abc"已经在常量池创建了,因此当代码运行到String = str8这句代

码的时候,会创建一个String对象,并且String对象的指针指向于常量池的字符串"abc"。

内存关系:栈内存变量str8的指针指向堆内存的String对象,对内存的String对象指向于常量池的"abc"对象。


由以上分析可知:str1的内存地址 == str2的内存地址 == str6的内存地址。

str1 != str5 != str7 != str8

str5,str7,str8的内存地址各不同。但是str1,str2,str6,str7,str8的值的内存地址一致都是为常量池当中的"abc",

只有str5的值的内存地址在堆内存 。


注:如有不对,请指出,谢谢。

猜你喜欢

转载自blog.csdn.net/u013386606/article/details/80513273