最近温习java的一些基础知识,发现以往对String对象认识上的一些不足。特汇总如下,主要是帮助记忆,如能对其他朋友有些启发,不胜欣喜。
String在JVM中内存驻留问题
JVM的常量区(Constant Pool)中维持了大部分创建的string (Interned Strings)。举例,
Sring a="ABC";String b="ABC";
当JVM为a赋值时会在常量区生成一个String Constant,当b也赋值为“ABC”时,那么会在常量池中查看是否存在值为“ABC”的常量,存在的话,则把b的指针也指向“ABC”的地址,而不是新生成一个String Constant。
JDK1.6中Interned Strings存储在Permanent Space的常量池中;
JDK1.7中Interned Strings已经不再存储在Permanent Space中,而是放到了Heap中;
JDK8中PermanentSpace已经被完全移除,InternedStrings也被放到了MetaSpace中。
String.substring()方法
返回新的String对象,JAVA6返回的新对象与原有对象底层共享存储空间char[]数组,通过偏移和长度构造了一个"新"的String,导致substring对象被引用时,原对象即使没有被引用也不能被销毁;JAVA7之后返回的新对象会新建底层的存储空间
+与concat()的区别
1. concat是String方法,String重载了“+”操作符(提醒下:Java不支持其他操作符的重载)
2. concat方法在参数为空时返回原字符串,不为空时返回新的String对象;而+在两个操作数都是常量时可能返回内存中已有的Interned String引用,操作数存在变量时必定新建String对象
对于敏感信息,为何使用char[]要比String更好?
String是不可变的。这意味着一旦创建了字符串,如果另一个进程可以进行内存转储,在GC发生前,(除了反射)没有方法可以清除字符串数据。
使用数组操作完之后,可以显式地清除数据:可以给数组赋任何值,密码也不会存在系统中,甚至垃圾回收之前也是如此。
所以,是的,这是一个安全问题 – 但是即使使用了char数组,仅仅缩小了了攻击者有机会获得密码的窗口,它值针对制定的攻击类型。
如何通过空白字符拆分字符串
String 的 split()方法接收的字符串会被当做正则表达式解析,
"\s"代表空白字符,如空格" ",tab制表符"\t", 换行"\n",回车"\r".
而编译器在对源代码解析时,也会进行一次字面量转码,所以需要"\\s".
String[] strArray = aString.split("\\s+");
String vs StringBuilder vs StringBuffer
StringBuilder 是可变的,因此可以在创建以后修改内部的值
StringBuffer 是同步的,因此是线程安全的,但效率相对更低