mutable string vs. immutable string

1、若是String是mutable的,如C++的std::string
看下面的例子:

void foo1(string s) {
    s[0] = 'b';
}

void foo2(string &s) {
    s[0] = 'b';
}

int main(void) {
    string s1 = "hello";
    string s2 = "hello";
    
    foo1(s1);
    foo2(s2);
    
    // hello
    cout << s1 << endl;
    // bello,s2變量的值被修改了
    cout << s2 << endl;
}
mutable字符串的特色是:
① 單線程下對字符串的更改速度快。但多線程修改時爲了保證正確性,須要加鎖處理,影響性能。
② 佔用內存空間小。
③ 若是按引用隨意傳遞的話,將會難以追蹤其變化。最好的方式是若是函數不修改它,就傳遞常引用。
 
2、若是String是immutable,如jdk的java.lang.String
看下面的例子:
static void foo(String s) {
    s = "java";    
}

public static void main(String[] args) {
    String s = "hello";
    foo(s);
    // hello
    System.out.println(s);
}
immutable字符串的特色是:
① 不存在多線程併發修改問題,由於每次修改都是建立新對象,沒有共享就沒有「傷害」。
② 按引用傳遞也不用擔憂其內容在其餘地方被修改。
③ 佔用空間較大,由於每次修改都要建立新對象(能夠採用享元模式來解決)。
 
3、享元模式
immutable String有個缺點就是每次修改都要建立新對象,這樣佔用內存空間較多,並且頻繁建立對象時間開銷也多。
一個很好的解決辦法就是使用享元模式。既然對象是不可變的,那麼它就能夠被緩存下來,之後若是須要一樣的對象,就直接從緩存池裏複用該對象,而不是又建立一個新對象。
 
例如java jdk中的Integer類:
public class Integer {
    public static Integer valueOf(int i) {
        // 若是i的範圍在[low, high],則從緩存池裏獲取
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
}
private static class IntegerCache {
    // 最小值不能被改變
    static final int low = -128;
    // 最大值能夠經過-Djava.lang.Integer.IntegerCache.high來設置
    // 默認值是127
    static final int high;
    static final Integer cache[];
    
    static {
       ...
       // 初始化high的值
       ...
       // 初始化緩存池
       cache = new Integer[(high - low) + 1];
       int j = low;
       for(int k = 0; k < cache.length; k++)
           cache[k] = new Integer(j++);
       }
       ...
   }
}

不可變對象(immutable object)在函數式編程和併發領域都會常常遇到,經過上面的對比,咱們應該就能清楚地體會到它的特色了。java

相關文章
相關標籤/搜索