再重复一遍,无论是修改字符串的方法还是对字符串赋值,都和普通的对象不同。赋值是让字符串指向一个新的字符串,方法传参是copy一份值,传入进去。
再比如说:String str=”kv”+”ill”+” “+”ans”; 就是有4个字符串常量,首先”kv”和”ill”生成了”kvill”存在内存中,然后”kvill”又和” ” 生成 “kvill “存在内存中,最后又和生成了”kvill ans”;并把这个字符串的地址赋给了str
所以 + 会产生很多临时变量。下文中会说到StringBuilder 来避免这种情况。不过有一种特殊情况。 "ab"+"cd" 在JVM编译后和"abcd"一样
String str1 = "ab" + "cd"; //1个对象 String str11 = "abcd"; System.out.println("str1 = str11 : "+ (str1 == str11));
2.2.2 Java是怎样做到String的不可变的在String源码中 ,使用private final char value[]来实现字符串的存储,就是因为final,才说String类型是不可变
/** The value is used for character storage. */ private final char value[];
2.3 String的保存位置深入一点,我们了解一下String保存的位置(可以参考Java+内存分配及变量存储位置的区别,Java中的String类常量池详解)
String常量是保存在常量池中。JVM中的常量池在内存当中是以表的形式存在的, 对于String类型,有一张固定长度的CONSTANT_String_info表用来存储文字字符串值,注意:该表只存储文字字符串值,不存储符号引用。说到这里,对常量池中的字符串值的存储位置应该有一个比较明了的理解了。在程序执行的时候,常量池会储存在Method Area,而不是堆中。常量池中保存着很多String对象; 并且可以被共享使用,因此它提高了效率
什么是常量池常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。
除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值(final)还包含一些以文本形式出现的符号引用。
2.4主要的方法s.length() 返回s字符串长度
s.charAt(2) 返回s字符串中下标为2的字符
s.substring(0, 4) 返回s字符串中下标0到4的子字符串
s.indexOf("Hello") 返回子字符串"Hello"的下标
s.startsWith(" ") 判断s是否以空格开始
s.endsWith("oo") 判断s是否以"oo"结束
s.equals("Good World!") 判断s是否等于"Good World!" ==只能判断字符串是否保存在同一位置。需要使用equals()判断字符串的内容是否相同。
s.compareTo("Hello Nerd!") 比较s字符串与"Hello Nerd!"在词典中的顺序, 返回一个整数,如果<0,说明s在"Hello Nerd!"之前 如果>0,说明s在"Hello Nerd!"之后 如果==0,说明s与"Hello Nerd!"相等。
s.trim() 去掉s前后的空格字符串,并返回新的字符串
s.toUpperCase() 将s转换为大写字母,并返回新的字符串
s.toLowerCase() 将s转换为小写,并返回新的字符串
s.replace("World", "Universe") 将"World"替换为"Universe",并返回新的字符串
2.5:简单概括总结String中的细节点总体来说,如果你还是对String感到困惑,不如把握住一点就是“ 创建时间” 如果编译期就知道是啥,会丢到常量池.
单独使用""引号创建的字符串都是常量,编译期就已经确定存储到String Pool中;
使用new String("")创建的对象会存储到heap中,是运行期新创建的;
使用只包含常量的字符串连接符如"aa" + "aa"创建的也是常量,编译期就能确定,已经确定存储到String Pool中;
使用包含变量的字符串连接符如"aa" + s1创建的对象是运行期才创建的,存储在heap中;