【源码-JAVA】java.lang.String 源码学习

一、String的构造方法

可不只是 String a = "abc";String a = new String("abc");

阅读 String 源码,发现 String 提供了很多种构造方法,这里列出常用的几种:

public String(String original){}

public String(char value[]) {  
    this.value = Arrays.copyOf(value, value.length);  
}

public String(char value[], int offset, int count) {
    ...
    Arrays.copyOfRange(value, offset, offset + count);
}

// unicode数组构造
public String(int[] codePoints, int offset, int count) {};
String str_03 = new String(new int[]{0x61, 0x62, 0x63}, 0, 3);

// Constructs a new String by decoding the specified array of bytes using the platform's default charset. 
public String(byte bytes[]) {  
    this(bytes, 0, bytes.length);  
}
String str_04 = new String(new byte[]{0x61, 0x62, 0x63});

除了构造方法,还提供了很多静态工厂方法供用户直接将 char、int、long、float、double、boolean、char[]、Object 转化为 String 。

二、字符串常量池

对于语句 String s1 = new String("abc");

  • new String(“abc”) 明确要求在 堆内存 创建一个新的对象,即便 “abc” 已存在于常量池中。
  • 如果直接用字面值 “abc”,则引用的是 常量池中的对象
  • 常量池中的字符串和堆中的字符串是两个独立的对象,设计上是为了兼顾性能优化(常量池)和明确的实例化需求(new)。

所以不管常量池中有没有保存 “abc”,new String() 的语义都强制命令在堆中创建新的对象。
想要复用常量池中的对象,就必须依赖于 String xxx = "abc" 而不能 new String()
在该语句下,如果常量池中有 “abc” 的对象,就直接复用引用,创建了0次对象。

因此:对于创建了几次对象的问题:

String s1 = new String(“abc”);

  • 如果常量池中没有”abc”,创建两次对象(常量池”abc”字面量 + 堆内存对象);
  • 如果常量池中已经存在”abc”,创建一次对象 (堆内存);

String xxx = “abc”

  • 如果常量池中没有”abc”,创建一次对象(常量池”abc”字面量);
  • 如果常量池中已经存在”abc”,创建零次对象,直接指向常量池中的对象。

创建了几次对象?

String str_01 = "abc";
String str_02 = "abc" + "def";
String str_03 = str_01 + "def";

假设这句之前常量池中没有”abc” “def” 以及 “abcdef”

  1. 常量池中没有”abc”,在常量池创建一个对象;
  2. 表达式 “abc” + “def” 是一个常量表达式,得益于JVM编译器的优化(常量表达式会在编译器优化),直接将其计算为”abcdef”,在常量池中不存在,创建一个对象;
  3. str_01 是变量引用,虽然其值是常量 “abc”,但在编译期 无法确定 表达式的值。先创建字面量对象 “def” 在常量池中,创建 StringBuilder 对象,append 后 toString,直接存储在堆中。创建3个对象(一个在常量池,两个在堆内存)

三、intern()

/**  
 * Returns a canonical representation for the string object. * <p>  
 * A pool of strings, initially empty, is maintained privately by the * class {@code String}. * <p>  
 * When the intern method is invoked, if the pool already contains a * string equal to this {@code String} object as determined by * the {@link #equals(Object)} method, then the string from the pool is  
 * returned. Otherwise, this {@code String} object is added to the * pool and a reference to this {@code String} object is returned. * <p>  
 * It follows that for any two strings {@code s} and {@code t}, * {@code s.intern() == t.intern()} is {@code true} * if and only if {@code s.equals(t)} is {@code true}. * <p>  
 * All literal strings and string-valued constant expressions are * interned. String literals are defined in section 3.10.5 of the * <cite>The Java&trade; Language Specification</cite>.  
 * * @return  a string that has the same contents as this string, but is *          guaranteed to be from a pool of unique strings. */
public native String intern();

这是一个本地方法。通过C++实现。
作用是将堆中String的值直接推进常量池中,返回的是常量池中对应值的对象。

  • intern() 方法的功能 是将字符串的值(即其内容)尝试存入 字符串常量池,并返回 常量池中该字符串的引用
  • 如果 常量池 中已经有一个与当前字符串对象内容相同的字符串(通过 equals 比较),则直接返回常量池中的引用;
  • 如果 常量池 中还没有,则将当前字符串的内容加入常量池,并返回常量池中的引用。

四、String StringBuilder StringBuffer

阅读StringBuilder源码发现,StringBuilder实际上就是维护一个char[]数组。

append(String str)

append(String str) 的操作基于arraycopy(Object src, int srcPos, Object dest, int destPos, int length);,就是将str拼接到维护的char[]的尾部。

public AbstractStringBuilder append(String str) {  
    if (str == null)  
        return appendNull();  
    int len = str.length();  
    ensureCapacityInternal(count + len);  
    str.getChars(0, len, value, count);  
    count += len;  
    return this;  
}

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);  
}

StringBuilder的自动扩容

扩容操作和ArrayList的扩容原理一致,超过容量后,扩容至 原容量 * 2 + 2,另外用 Arrays.copyOf(value, newCapacity) 把原有元素拷贝到新数组中。

private void ensureCapacityInternal(int minimumCapacity) {  
    // overflow-conscious code  
    if (minimumCapacity - value.length > 0) {  
        value = Arrays.copyOf(value,  
                newCapacity(minimumCapacity));  
    }  
}

private int newCapacity(int minCapacity) {  
    // overflow-conscious code  
    int newCapacity = (value.length << 1) + 2;  
    if (newCapacity - minCapacity < 0) {  
        newCapacity = minCapacity;  
    }  
    // 确保不会超过最大容量或int的最大值
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)  
        ? hugeCapacity(minCapacity)  
        : newCapacity;  
}

StringBuffer

StringBuffer 的API和底层实现基本一致,不同之处在于StringBuffer的方法加了synchronized 锁,保证了线程安全性。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇