源码解读全文
String
压缩算法
- jdk9及之后,Stirng底层使用
byte数组存储,那么当面对中文时,如果将原先的char数组转化为byte数组呢 - 以下以
String s = new String(char数组为例)
- String底层有个压缩算法策略,由
COMPACT_STRINGS控制,默认开启
static final boolean COMPACT_STRINGS;
static {
COMPACT_STRINGS = true;
}
- 源构造器
String(char[] value, int off, int len, Void sig) {
if (len == 0) {
this.value = "".value;
this.coder = "".coder;
return;
}
if (COMPACT_STRINGS) { //先尝试压缩
byte[] val = StringUTF16.compress(value, off, len);
//val==null 压缩失败
if (val != null) {
this.value = val;
this.coder = LATIN1; //压缩成功,则记录为LATIN1的编码
return;
}
}
this.coder = UTF16; //压缩失败,则记录为UTF16的编码
//并将char数组,直接转换成byte数组
this.value = StringUTF16.toBytes(value, off, len);
}
- 压缩
public static byte[] compress(char[] val, int off, int len) {
byte[] ret = new byte[len];
//调用下面的函数,返回len==0,表明压缩失败直接弹出
if (compress(val, off, ret, 0, len) == len) {
return ret;
}
return null;
}
//如果char数组中的16进制值超过一个字节,表示压缩失败,返回len=0
public static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) {
for (int i = 0; i < len; i++) {
char c = src[srcOff];
if (c > 0xFF) {
len = 0;
break;
}
dst[dstOff] = (byte)c;
srcOff++;
dstOff++;
}
return len;
}
- char数组转换为byte数组
public static byte[] toBytes(char[] value, int off, int len) {
//具体处理len,
byte[] val = newBytesFor(len);
for (int i = 0; i < len; i++) {
//传入字节数组 每一位 char字符
putChar(val, i, value[off]);
off++;
}
return val;
}
//处理len
public static byte[] newBytesFor(int len) {
//负数
if (len < 0) {
throw new NegativeArraySizeException();
}
//超出 Integer.MAX_VALUE >> 1; *0.5
if (len > MAX_LENGTH) {
throw new OutOfMemoryError("UTF16 String size is " + len +
", should be less than " + MAX_LENGTH);
}
// *2
return new byte[len << 1];
}
//放字符
static void putChar(byte[] val, int index, int c) {
//边界检查,下标小于长度
assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
//因为要将char的每一位,两个字节,拆成两位一个字节的byte
//传入的位要*2,举例 i = 0 1 2 那么对应到byte的index为 0 1 2 3 4 5
index <<= 1;
//存高位
val[index++] = (byte)(c >> HI_BYTE_SHIFT);
//存低位
val[index] = (byte)(c >> LO_BYTE_SHIFT);
}
拼接字符串
- 对于下面这类拼接操作,调用
stringBuilder进行拼接 JDK1.8的处理
String str = new String("hello") + new String("java");
0 new #2 <java/lang/StringBuilder>
3 dup
4 invokespecial #3 <java/lang/StringBuilder.<init> : ()V>
7 new #4 <java/lang/String>
10 dup
11 ldc #5 <hello>
13 invokespecial #6 <java/lang/String.<init> : (Ljava/lang/String;)V>
16 invokevirtual #7 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
19 new #4 <java/lang/String>
22 dup
23 ldc #8 <java>
25 invokespecial #6 <java/lang/String.<init> : (Ljava/lang/String;)V>
28 invokevirtual #7 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
31 invokevirtual #9 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>
34 astore_1
StringBuilder调用了AbstractStringBuilder的方法
public StringBuilder append(String str) {
super.append(str);
return this;
}
AbstractStringBuilder
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
//扩大容量
ensureCapacityInternal(count + len);
//jkd9之后有变化
str.getChars(0, len, value, count);
count += len;
return this;
}
ensureCapacityInternal
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
getChars
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
//异常判断
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
//复制
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
- jdk9之后处理有了变化,
putStringAt(count, str);调用这个来处理新的字符串
private void putStringAt(int index, String str) {
putStringAt(index, str, 0, str.length());
}
//底层调用了getBytes
private void putStringAt(int index, String str, int off, int end) {
if (getCoder() != str.coder()) {
inflate();
}
// 目标数组,str的偏移,在这个数组的起点,编码方式 8/16,长度
str.getBytes(value, off, index, coder, end - off);
}
void getBytes(byte[] dst, int srcPos, int dstBegin, byte coder, int length) {
if (coder() == coder) { //同一个字符编码,直接复制
System.arraycopy(value, srcPos << coder, dst, dstBegin << coder, length << coder);
} else { // this.coder == LATIN && coder == UTF16 不同,需要将新加字符串另外处理
StringLatin1.inflate(value, srcPos, dst, dstBegin, length);
}
}
Integer
装箱
- 针对下面两句简单代码,底层同样进行了不同的处理
Integer x = 5;
Integer i3 = 128;
- 装箱时调用了
valueOf
Integer x = 5;
0 iconst_5
1 invokestatic #2 <java/lang/Integer.valueOf : (I)Ljava/lang/Integer;>
4 astore_1
valueOf方法,中间有一个IntegerCache.cache[]数组,并且范围是low~high
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
IntegerCache为Integer的静态内部类,Integer常量池,并进行了初始化
private static class IntegerCache {
//low
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
//如果修改了 integerCacheHighPropValue,另外处理
String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
//high取大的那个
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
// 数组的最大范围不能超过 Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
//给常量池赋值
cache = new Integer[(high - low) + 1]; // 1 0 -1 三个数
int j = low;
//从-128开始赋值
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
- 设置
integerCacheHighPropValue,java -Djava.lang.Integer.IntegerCache.high = xxxx Aclass.class- 那么可以看出,如果值在-128和127直接,直接返回静态常量池中的值,如果不在这个范围之内需要new对象
public Integer(int value) {
this.value = value;
}
拆箱
int m = x + 1;
调用了
intValue
26 aload_1
27 invokevirtual #4 <java/lang/Integer.intValue : ()I>
30 iconst_1
31 iadd
32 istore_3
intvalue
public int intValue() {
return value;
}