jdk 源码阅读有感(一)String
闲暇之余阅读 jdk 源码。
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
(一)核心属性
/** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0
String的核心结构,char型数组与 int 型 hash值。
(二)构造器
构造器方面,由于上述两个值是不可更改的,所以直接 对 String 构造,其实是没有用的,只不过是加上了一个引用。
public String(String original) { this.value = original.value; this.hash = original.hash; }
对 char 类型数组使用构造方法时,则会借用调用相关的复制数组的操作,对String的底层抽象,字符数组进行赋值。
public String(char value[]) { this.value = Arrays.copyOf(value, value.length); }
//System.arraycopy(original, 0, copy, 0, len); //一个native方法,用于复制数组。
(三)方法内常用边界判断
if ((ooffset < 0) || (toffset < 0) || (toffset > (long)value.length - len) || (ooffset > (long)other.value.length - len)) { return false; }
连续的 ‘或’ 判断,采用逆向思维对边界判断。
即判断当前字符串长度的长度减去开始位置后,与参数字符串的长度进行比较,判断边界条件。
(四)Continue 或 break 的少用用法
startSearchForLastChar: while (true) { while (i >= min && source[i] != strLastChar) { i--; } if (i < min) { return -1; } int j = i - 1; int start = j - (targetCount - 1); int k = strLastIndex - 1; while (j > start) { if (source[j--] != target[k--]) { i--; continue startSearchForLastChar; } } return start - sourceOffset + 1; }
设置好需要跳转的点,条件符合后进行跳转。
(五)代码性能提升————减少getField操作。
public String trim() { int len = value.length; int st = 0; char[] val = value; /* avoid getfield opcode */ while ((st < len) && (val[st] <= ' ')) { st++; } while ((st < len) && (val[len - 1] <= ' ')) { len--; } return ((st > 0) || (len < value.length)) ? substring(st, len) : this; }
}
value是String中的全局字符数组,在方法内部使用局部变量,得到字符数组的引用,可以有效地减少getField操作。从而提高代码运行效率。
参考:https://blog.csdn.net/gaopu12345/article/details/52084218
(六)intern()方法
A pool of strings, initially empty, is maintained privately by the class String.
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned.
Otherwise, this String object is added to the pool and a reference to this code String object is returned.
intern方法用于减少String对象引用,实质上是减少String池中的引用数量。
参考:https://www.cnblogs.com/paddix/p/5326863.html
http://blog.csdn.net/seu_calvin/article/details/52291082
由于jvm在1.7后将常量池放到堆空间中进行统一管理,直接对此方法产生本质上的变化。即堆中的对象可见字符串常量池中的常量。
接下来用简单易懂的话说明intern方法在1.7之后是如何工作的。
例子在参考链接中说明十分详细,此处只对具体情况和具体过程进行总结。
首先要说明的是。
1.字符串的存储分为两个地方,分别为常量池与堆中的字符串对象。在1.7之前,常量池放在方法区,而字符串对象放在堆中,要想两个区域内有表示相同的字符串需要对两个区域分别赋值。1.7后由于常量池放在了堆中,导致了在new 一个字符串常量的时候,会直接生成字符串对象与字符串常量,此时的地址肯定是不同的。
2.final关键字修饰的字符串,在编译后将变量直接用常量表示。与在代码中直接写常量没有差别。
3.字符串的拼接实际上是使用的StringBuilder的append方法产生的新对象。与直接字符串常量拼接并不相同。
目前总结为以上三点。
intern方法具体如下:
当字符串使用intern方法时,字符串会去字符串常量池中寻找此字符串常量,如果找到就返回字符串常量的引用。如果没找到,就将字符串常量池中存放当前字符串对象的引用。
这种情况主要见于多个字符串对象拼接,拼接时就不会在字符串常量池中对新拼接的字符串值赋值到常量池,如下:
String str2 = new String("Jun")+new String("pb"); str2.intern(); String str1 = "Junpb"; System.out.println(str2==str1);
返回true,这是由于在intern时,常量池中没有Junpb这个字符串常量,就直接在常量中放入了str2的引用,即str1获取的是str2的引用。即为true。
耶!!! 上述都是自己的理解,如有错误,希望指正。本博文主要用于记录计算机之路的脚印。
