前言
明白什么是引用,什么是该引用指向的真正对象。
==对于基本数据类型比较的是值,对于引用数据类型比较的是指向的对象的地址,即两者指向的是否是同一个对象。
String s = "gzc";
上述代码中s为变量引用,它存在于栈中,而“gzc”则是该变量引用所指向的真正数据,它存在于字符串常量池中。
言归正传
字符串拼接主要有2种情况:
1、常量与常量拼接
String s1 = "g"+"zc";//常量“g”与常量“zc”拼接
常量与常量拼接的原理:
字符串常量与常量之间的拼接操作其实在未加载到JVM内存之前就已经完成了,即在编译期间就会对字符串常量之间的拼接操作进行优化
如下图,进行反编译后,我们不难发现在编译完之后,s4已经被直接拼接好了。而且此时s3和s4指向的是字符串常量池中的同一个对象,即两者存储的对象地址是相同的。所以s3==s4其结果为true。
2、涉及到变量的字符串拼接
2.1 变量与常量拼接
String s1 = "g";
String s2 = s1+"zc";//变量s1与常量“zc”拼接
2.2 变量与变量拼接
String s1 = "g";
String s2 = "zc";
String s3 = s1+s2;//变量s1与变量s2拼接
涉及到变量的字符串拼接原理:
只要字符串拼接其中涉及到变量,不管是几个变量,那么其拼接原理都如下:
当涉及到变量时,字符串用+进行字符串拼接的本质,其实就是利用StringBuilder类里的append()方法,将每一个字符串都一一添加进去,然后返回一个StringBuilder对象,所以可以不用新创建一个对象去接收返回值,直接链式编程得到最终添加的结果,最后再调用toString()方法将其转换为我们想要的字符串String类型。
如下图:
特别注意:
StringBuilder的toString()方法调用的是String重载的构造器方法,是以字符数组为字符串实际内容进行创建的,并未直接以字面量方式创建String对象,即:
所以如果我们上述代码没有定义s3和s4两个变量,只定义了String s5 = s1+s2;
的话,那么其实字符串常量池中是不存在“gzc”这个字符串的,而是只有“g”和“zc”。因为只有通过字面量定义一个字符串以及调用String的intern()方法,这两种方式才会在字符串常量池中生成对应的对象。
而StringBuilder调用toString()方法创建的String对象则会直接在堆中为其分配内存,常量池中不会存在对应的对象。所以如果判断s3==s5
,则结果为false
,因为s3指向的是字符串常量池中的“gzc”,而s5指向的是堆中的“gzc”对象,二者指向的对象地址不同,则比较结果自然为false。特殊情况:若变量被声明为final类型,即为常量,则就遵循字符串常量拼接的规则了。如下图: