java基礎(chǔ):String — 源碼分析(一)

其他更多java基礎(chǔ)文章:
java基礎(chǔ)學(xué)習(xí)(目錄)


距離上次寫(xiě)文章已經(jīng)好一段時(shí)間了挺举,主要是工作忙起來(lái)创橄,看書(shū)的時(shí)間就少了,看String的進(jìn)度就斷斷續(xù)續(xù)近忙,在讀源碼的過(guò)程中,我搜了幾篇很有學(xué)習(xí)價(jià)值的文章鸦泳,放在下面银锻,可以在閱讀完本文之后閱讀一下,有些地方我可能講的不夠清楚做鹰,下面文章里的大神講的更仔細(xì)击纬。

學(xué)習(xí)資料:
String類(lèi)API中文
深入解析String#intern
Java 中new String("字面量") 中 "字面量" 是何時(shí)進(jìn)入字符串常量池的?
new一個(gè)String對(duì)象的時(shí)候,如果常量池沒(méi)有相應(yīng)的字面量真的會(huì)去它那里創(chuàng)建一個(gè)嗎钾麸?我表示懷疑更振。

String的方法

String的底層是由char數(shù)組構(gòu)成的

private final char value[];

由于底層char數(shù)組是final的,所以String對(duì)象是不可變的饭尝。

String的構(gòu)造方法

我們先講一下主要的幾種構(gòu)造方法:
1. 參數(shù)為String類(lèi)型

public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

這里將直接將源 String 中的 value 和 hash 兩個(gè)屬性直接賦值給目標(biāo) String肯腕。因?yàn)?String 一旦定義之后是不可以改變的,所以也就不用擔(dān)心改變?cè)?String 的值會(huì)影響到目標(biāo) String 的值钥平。

2. 參數(shù)為字符數(shù)組

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

這里值得注意的是:當(dāng)我們使用字符數(shù)組創(chuàng)建 String 的時(shí)候实撒,會(huì)用到 Arrays.copyOf 方法或 Arrays.copyOfRange 方法。這兩個(gè)方法是將原有的字符數(shù)組中的內(nèi)容逐一的復(fù)制到 String 中的字符數(shù)組中。會(huì)創(chuàng)建一個(gè)新的字符串對(duì)象知态,隨后修改的字符數(shù)組不影響新創(chuàng)建的字符串捷兰。

3.參數(shù)為字節(jié)數(shù)組
在 Java 中,String 實(shí)例中保存有一個(gè) char[] 字符數(shù)組负敏,char[] 字符數(shù)組是以 unicode 碼來(lái)存儲(chǔ)的贡茅,String 和 char 為內(nèi)存形式。

byte 是網(wǎng)絡(luò)傳輸或存儲(chǔ)的序列化形式其做,所以在很多傳輸和存儲(chǔ)的過(guò)程中需要將 byte[] 數(shù)組和 String 進(jìn)行相互轉(zhuǎn)化顶考。所以 String 提供了一系列重載的構(gòu)造方法來(lái)將一個(gè)字符數(shù)組轉(zhuǎn)化成 String,提到 byte[] 和 String 之間的相互轉(zhuǎn)換就不得不關(guān)注編碼問(wèn)題妖泄。

String(byte[] bytes, Charset charset)

該構(gòu)造方法是指通過(guò) charset 來(lái)解碼指定的 byte 數(shù)組驹沿,將其解碼成 unicode 的 char[] 數(shù)組,構(gòu)造成新的 String浮庐。

這里的 bytes 字節(jié)流是使用 charset 進(jìn)行編碼的甚负,想要將他轉(zhuǎn)換成 unicode 的 char[] 數(shù)組柬焕,而又保證不出現(xiàn)亂碼审残,那就要指定其解碼方式

同樣的,使用字節(jié)數(shù)組來(lái)構(gòu)造 String 也有很多種形式斑举,按照是否指定解碼方式分的話可以分為兩種:

public String(byte bytes[]){
  this(bytes, 0, bytes.length);
}
public String(byte bytes[], int offset, int length){
    checkBounds(bytes, offset, length);
    this.value = StringCoding.decode(bytes, offset, length);
}

如果我們?cè)谑褂?byte[] 構(gòu)造 String 的時(shí)候搅轿,使用的是下面這四種構(gòu)造方法(帶有 charsetName 或者 charset 參數(shù))的一種的話,那么就會(huì)使用 StringCoding.decode 方法進(jìn)行解碼富玷,使用的解碼的字符集就是我們指定的 charsetName 或者 charset璧坟。

String(byte bytes[])
String(byte bytes[], int offset, int length)
String(byte bytes[], Charset charset)
String(byte bytes[], String charsetName)
String(byte bytes[], int offset, int length, Charset charset)
String(byte bytes[], int offset, int length, String charsetName)

我們?cè)谑褂?byte[] 構(gòu)造 String 的時(shí)候,如果沒(méi)有指明解碼使用的字符集的話赎懦,那么 StringCoding 的 decode 方法首先調(diào)用系統(tǒng)的默認(rèn)編碼格式雀鹃,如果沒(méi)有指定編碼格式則默認(rèn)使用 ISO-8859-1 編碼格式進(jìn)行編碼操作。主要體現(xiàn)代碼如下:

static char[] decode(byte[] ba, int off, int len){
    String csn = Charset.defaultCharset().name();
    try{ //use char set name decode() variant which provide scaching.
         return decode(csn, ba, off, len);
    } catch(UnsupportedEncodingException x){
        warnUnsupportedCharset(csn);
    }

    try{
       return decode("ISO-8859-1", ba, off, len);  } 
    catch(UnsupportedEncodingException x){
       //If this code is hit during VM initiali zation, MessageUtils is the only way we will be able to get any kind of error message.
       MessageUtils.err("ISO-8859-1 char set not available: " + x.toString());
       // If we can not find ISO-8859-1 (are quired encoding) then things are seriously wrong with the installation.
       System.exit(1);
       return null;
    }
}

4.參數(shù)為StringBuilder或StringBuffer

public String(StringBuffer buffer) {
        synchronized(buffer) {
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
        }
    }

public String(StringBuilder builder) {
        this.value = Arrays.copyOf(builder.getValue(), builder.length());
    }

基本不用励两,用StringBuffer.toString方法黎茎。

4. 特殊的protected構(gòu)造方法

    String(char[] value, boolean share) {
        // assert share : "unshared not supported";
        this.value = value;
    }

從代碼中我們可以看出,該方法和 String(char[] value) 有兩點(diǎn)區(qū)別:

  • 第一個(gè)區(qū)別:該方法多了一個(gè)參數(shù):boolean share当悔,其實(shí)這個(gè)參數(shù)在方法體中根本沒(méi)被使用傅瞻。注釋說(shuō)目前不支持 false,只使用 true盲憎。那可以斷定嗅骄,加入這個(gè) share 的只是為了區(qū)分于 String(char[] value) 方法,不加這個(gè)參數(shù)就沒(méi)辦法定義這個(gè)函數(shù)饼疙,只有參數(shù)是不同才能進(jìn)行重載溺森。

  • 第二個(gè)區(qū)別:具體的方法實(shí)現(xiàn)不同。我們前面提到過(guò) String(char[] value) 方法在創(chuàng)建 String 的時(shí)候會(huì)用到 Arrays 的 copyOf 方法將 value 中的內(nèi)容逐一復(fù)制到 String 當(dāng)中,而這個(gè) String(char[] value, boolean share) 方法則是直接將 value 的引用賦值給 String 的 value屏积。那么也就是說(shuō)澡罚,這個(gè)方法構(gòu)造出來(lái)的 String 和參數(shù)傳過(guò)來(lái)的 char[] value 共享同一個(gè)數(shù)組。

為什么 Java 會(huì)提供這樣一個(gè)方法呢肾请?

  • 性能好:這個(gè)很簡(jiǎn)單留搔,一個(gè)是直接給數(shù)組賦值(相當(dāng)于直接將 String 的 value 的指針指向char[]數(shù)組),一個(gè)是逐一拷貝铛铁,當(dāng)然是直接賦值快了隔显。

  • 節(jié)約內(nèi)存:該方法之所以設(shè)置為 protected,是因?yàn)橐坏┰摲椒ㄔO(shè)置為公有饵逐,在外面可以訪問(wèn)的話括眠,如果構(gòu)造方法沒(méi)有對(duì) arr 進(jìn)行拷貝,那么其他人就可以在字符串外部修改該數(shù)組倍权,由于它們引用的是同一個(gè)數(shù)組掷豺,因此對(duì) arr 的修改就相當(dāng)于修改了字符串,那就破壞了字符串的不可變性薄声。

  • 安全的:對(duì)于調(diào)用他的方法來(lái)說(shuō)当船,由于無(wú)論是原字符串還是新字符串,其 value 數(shù)組本身都是 String 對(duì)象的私有屬性默辨,從外部是無(wú)法訪問(wèn)的德频,因此對(duì)兩個(gè)字符串來(lái)說(shuō)都很安全。

在 Java 7 之前有很多 String 里面的方法都使用上面說(shuō)的那種“性能好的缩幸、節(jié)約內(nèi)存的壹置、安全”的構(gòu)造函數(shù)。
比如:substring replace concat valueOf 等方法表谊,實(shí)際上它們使用的是 public String(char[], ture) 方法來(lái)實(shí)現(xiàn)钞护。

但是在 Java 7 中,substring 已經(jīng)不再使用這種“優(yōu)秀”的方法了

public String substring(int beginIndex, int endIndex){
  if(beginIndex < 0){
    throw new StringIndexOutOfBoundsException(beginIndex);
  }
  if(endIndex > value.length){
    throw new StringIndexOutOfBoundsException(endIndex);
  }
  intsubLen = endIndex-beginIndex;
  if(subLen < 0){
    throw new StringIndexOutOfBoundsException(subLen);
  }
  return ((beginIndex == 0) && (endIndex == value.length)) ? this  : newString(value, beginIndex, subLen);
}

為什么呢爆办?
雖然這種方法有很多優(yōu)點(diǎn)难咕,但是他有一個(gè)致命的缺點(diǎn),對(duì)于 sun 公司的程序員來(lái)說(shuō)是一個(gè)零容忍的 bug押逼,那就是他很有可能造成內(nèi)存泄露步藕。

看一個(gè)例子,假設(shè)一個(gè)方法從某個(gè)地方(文件挑格、數(shù)據(jù)庫(kù)或網(wǎng)絡(luò))取得了一個(gè)很長(zhǎng)的字符串咙冗,然后對(duì)其進(jìn)行解析并提取其中的一小段內(nèi)容,這種情況經(jīng)常發(fā)生在網(wǎng)頁(yè)抓取或進(jìn)行日志分析的時(shí)候漂彤。

下面是示例代碼:

String aLongString = "...averylongstring...";
String aPart = data.substring(20, 40);
return aPart;

在這里 aLongString 只是臨時(shí)的雾消,真正有用的是 aPart灾搏,其長(zhǎng)度只有 20 個(gè)字符,但是它的內(nèi)部數(shù)組卻是從 aLongString 那里共享的立润,因此雖然 aLongString 本身可以被回收狂窑,但它的內(nèi)部數(shù)組卻不能釋放。這就導(dǎo)致了內(nèi)存泄漏桑腮。如果一個(gè)程序中這種情況經(jīng)常發(fā)生有可能會(huì)導(dǎo)致嚴(yán)重的后果泉哈,如內(nèi)存溢出,或性能下降破讨。

新的實(shí)現(xiàn)雖然損失了性能丛晦,而且浪費(fèi)了一些存儲(chǔ)空間,但卻保證了字符串的內(nèi)部數(shù)組可以和字符串對(duì)象一起被回收提陶,從而防止發(fā)生內(nèi)存泄漏烫沙,因此新的 substring 比原來(lái)的更健壯。

其他方法

length() 返回字符串長(zhǎng)度
isEmpty() 返回字符串是否為空
charAt(int index) 返回字符串中第(index+1)個(gè)字符(數(shù)組索引)
char[] toCharArray() 轉(zhuǎn)化成字符數(shù)組
trim()去掉兩端空格
toUpperCase()轉(zhuǎn)化為大寫(xiě)
toLowerCase()轉(zhuǎn)化為小寫(xiě)
boolean matches(String regex) 判斷字符串是否匹配給定的regex正則表達(dá)式
boolean contains(CharSequence s) 判斷字符串是否包含字符序列 s
String[] split(String regex, int limit) 按照字符 regex將字符串分成 limit 份
String[] split(String regex) 按照字符 regex 將字符串分段

詳細(xì)可查看String類(lèi)API中文翻譯

需要注意

String concat(String str) 拼接字符串
String replace(char oldChar, char newChar) 將字符串中的
oldChar 字符換成 newChar 字符

以上兩個(gè)方法都使用了 String(char[] value, boolean share) concat 方法和 replace 方法隙笆,他們不會(huì)導(dǎo)致元數(shù)組中有大量空間不被使用锌蓄,因?yàn)樗麄円粋€(gè)是拼接字符串,一個(gè)是替換字符串內(nèi)容撑柔,不會(huì)將字符數(shù)組的長(zhǎng)度變得很短瘸爽,所以使用了共享的 char[] 字符數(shù)組來(lái)優(yōu)化。

getBytes

在創(chuàng)建 String 的時(shí)候乏冀,可以使用 byte[] 數(shù)組蝶糯,將一個(gè)字節(jié)數(shù)組轉(zhuǎn)換成字符串,同樣辆沦,我們可以將一個(gè)字符串轉(zhuǎn)換成字節(jié)數(shù)組,那么 String 提供了很多重載的 getBytes 方法识虚。

public byte[] getBytes(){
  return StringCoding.encode(value, 0, value.length);
}

但是肢扯,值得注意的是,在使用這些方法的時(shí)候一定要注意編碼問(wèn)題担锤。比如:
String s = "你好蔚晨,世界!"; byte[] bytes = s.getBytes();
這段代碼在不同的平臺(tái)上運(yùn)行得到結(jié)果是不一樣的肛循。由于沒(méi)有指定編碼方式铭腕,所以在該方法對(duì)字符串進(jìn)行編碼的時(shí)候就會(huì)使用系統(tǒng)的默認(rèn)編碼方式。

在中文操作系統(tǒng)中可能會(huì)使用 GBK 或者 GB2312 進(jìn)行編碼多糠,在英文操作系統(tǒng)中有可能使用 iso-8859-1 進(jìn)行編碼累舷。這樣寫(xiě)出來(lái)的代碼就和機(jī)器環(huán)境有很強(qiáng)的關(guān)聯(lián)性了,為了避免不必要的麻煩夹孔,要指定編碼方式被盈。

public byte[] getBytes(String charsetName) throws UnsupportedEncodingException{
  if (charsetName == null) throw new NullPointerException();
  return StringCoding.encode(charsetName, value, 0, value.length);
}

比較方法

boolean equals(Object anObject)析孽; 比較對(duì)象
boolean contentEquals(String Buffersb); 與字符串比較內(nèi)容
boolean contentEquals(Char Sequencecs)只怎; 與字符比較內(nèi)容
boolean equalsIgnoreCase(String anotherString)袜瞬;忽略大小寫(xiě)比較字符串對(duì)象
int compareTo(String anotherString); 比較字符串
int compareToIgnoreCase(String str)身堡; 忽略大小寫(xiě)比較字符串
boolean regionMatches(int toffset, String other, int ooffset, int len)局部匹配
boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) 可忽略大小寫(xiě)局部匹配

字符串有一系列方法用于比較兩個(gè)字符串的關(guān)系邓尤。 前四個(gè)返回 boolean 的方法很容易理解,前三個(gè)比較就是比較 String 和要比較的目標(biāo)對(duì)象的字符數(shù)組的內(nèi)容贴谎,一樣就返回 true, 不一樣就返回false裁赠,核心代碼如下:

int n = value.length; 
while (n-- ! = 0) {
  if (v1[i] != v2[i])
    return false;
    i++;
}

v1 v2 分別代表 String 的字符數(shù)組和目標(biāo)對(duì)象的字符數(shù)組。 第四個(gè)和前三個(gè)唯一的區(qū)別就是他會(huì)將兩個(gè)字符數(shù)組的內(nèi)容都使用 toUpperCase 方法轉(zhuǎn)換成大寫(xiě)再進(jìn)行比較赴精,以此來(lái)忽略大小寫(xiě)進(jìn)行比較佩捞。相同則返回 true,不想同則返回 false

equals方法:

public boolean equals(Object anObject) {
     if (this == anObject) {
         return true;
     } 
    if (anObject instanceof String) {
       String anotherString = (String) anObject;
       int n = value.length;
       if (n == anotherString.value.length) {
           char v1[] = value;
           char v2[] = anotherString.value;
           int i = 0;
           while (n-- != 0) {
             if (v1[i] != v2[i])
             return false;
             i++;
           }
           return true;
       }
   } 
   return false;
}

通過(guò)源碼的代碼蕾哟,我們可以了解它比較的流程:字符串相同:地址相同一忱;地址不同,但是內(nèi)容相同
這是一種提高效率的方法谭确,也就是將比較快速的部分(地址帘营,比較對(duì)象類(lèi)型)放在前面比較,速度慢的部分(比較字符數(shù)組)放在后面執(zhí)行逐哈。

StringBuffer 需要考慮線程安全問(wèn)題芬迄,加鎖之后再調(diào)用

contentEquals()方法

public boolean contentEquals(CharSequence cs) {
        // Argument is a StringBuffer, StringBuilder
        if (cs instanceof AbstractStringBuilder) {
            if (cs instanceof StringBuffer) {
                synchronized(cs) {
                   return nonSyncContentEquals((AbstractStringBuilder)cs);
                }
            } else {
                return nonSyncContentEquals((AbstractStringBuilder)cs);
            }
        }
        // Argument is a String
        if (cs instanceof String) {
            return equals(cs);
        }
        // Argument is a generic CharSequence
        char v1[] = value;
        int n = v1.length;
        if (n != cs.length()) {
            return false;
        }
        for (int i = 0; i < n; i++) {
            if (v1[i] != cs.charAt(i)) {
                return false;
            }
        }
        return true;
    }

public boolean contentEquals(StringBuffer sb);實(shí)際調(diào)用了contentEquals(CharSequence cs)方法;
AbstractStringBuilder和String都是接口CharSequence的實(shí)現(xiàn)昂秃,通過(guò)判斷輸入是AbstractStringBuilder還是String的實(shí)例禀梳,執(zhí)行不同的方法;

下面這個(gè)是 equalsIgnoreCase 代碼的實(shí)現(xiàn):

 public boolean equalsIgnoreCase(String anotherString) {
 return (this == anotherString) ? true : (anotherString != null) && (anotherString.value.length == value.length) && regionMatches(true, 0, anotherString, 0, value.length);
 }

看到這段代碼肠骆,眼前為之一亮算途。使用一個(gè)三目運(yùn)算符和 && 操作代替了多個(gè) if 語(yǔ)句。

Hashcode()方法

public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

hashCode 的實(shí)現(xiàn)其實(shí)就是使用數(shù)學(xué)公式:

[圖片上傳失敗...(image-e09e8e-1544065735387)]

為什么要使用這個(gè)公式蚀腿,就是在存儲(chǔ)數(shù)據(jù)計(jì)算 hash 地址的時(shí)候嘴瓤,我們希望盡量減少有同樣的 hash 地址。如果使用相同 hash 地址的數(shù)據(jù)過(guò)多莉钙,那么這些數(shù)據(jù)所組成的 hash 鏈就更長(zhǎng)廓脆,從而降低了查詢(xún)效率。
所以在選擇系數(shù)的時(shí)候要選擇盡量長(zhǎng)的系數(shù)并且讓乘法盡量不要溢出的系數(shù)磁玉,因?yàn)槿绻?jì)算出來(lái)的 hash 地址越大停忿,所謂的“沖突”就越少,查找起來(lái)效率也會(huì)提高蜀涨。

選擇31作為因子的原因: 為什么 String hashCode 方法選擇數(shù)字31作為乘子

substring
前面我們介紹過(guò)瞎嬉,java 7 中的 substring 方法使用
String(value, beginIndex, subLen) 方法創(chuàng)建一個(gè)新的 String 并返回蝎毡,這個(gè)方法會(huì)將原來(lái)的 char[] 中的值逐一復(fù)制到新的 String 中,兩個(gè)數(shù)組并不是共享的氧枣,雖然這樣做損失一些性能沐兵,但是有效地避免了內(nèi)存泄露。

replaceFirst便监、replaceAll扎谎、replace區(qū)別

String replaceFirst(String regex, String replacement)
String replaceAll(String regex, String replacement)
String replace(Char Sequencetarget, Char Sequencereplacement)

public String replace(char oldChar, char newChar){
  if(oldChar != newChar){
    int len = value.length;
    int i = -1;
    char[] val = value; /*avoid get field opcode*/
    while (++i < len){
      if (val[i] == oldChar){
        break;
      }
    }
    if( i < len ){
      char buf[] = new char[len];
      for (intj=0; j<i; j++){
        buf[j] = val[j];
      }
      while (i < len){
        char c = val[i];
        buf[i] = (c == oldChar) ? newChar : c;
        i++;
      }
      return new String(buf,true);
    }
   }
  return this;
}

replace 的參數(shù)可以是 char 或者 CharSequence,即可以支持字符的替換, 也支持字符串的替換烧董。當(dāng)參數(shù)為CharSequence時(shí)毁靶,實(shí)際調(diào)用的是replaceAll方法,所以replace方法是全部替換逊移。
replaceAll 和 replaceFirst 的參數(shù)是 regex预吆,即基于規(guī)則表達(dá)式的替換。區(qū)別是一個(gè)全部替換胳泉,一個(gè)只替換第一個(gè)拐叉。

intern()方法

public native String intern(); 

intern方法是Native調(diào)用,它的作用是在方法區(qū)中的常量池里尋找等值的對(duì)象扇商,如果沒(méi)有找到則在常量池中存放當(dāng)前字符串的引用并返回該引用凤瘦,否則直接返回常量池中已存在的String對(duì)象引用。

這個(gè)方法將會(huì)在下一章專(zhuān)門(mén)講
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末案铺,一起剝皮案震驚了整個(gè)濱河市蔬芥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌控汉,老刑警劉巖笔诵,帶你破解...
    沈念sama閱讀 211,561評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異暇番,居然都是意外死亡嗤放,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)壁酬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人恨课,你說(shuō)我怎么就攤上這事舆乔。” “怎么了剂公?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,162評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵希俩,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我纲辽,道長(zhǎng)颜武,這世上最難降的妖魔是什么璃搜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,470評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮鳞上,結(jié)果婚禮上这吻,老公的妹妹穿的比我還像新娘。我一直安慰自己篙议,他們只是感情好唾糯,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著鬼贱,像睡著了一般移怯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上这难,一...
    開(kāi)封第一講書(shū)人閱讀 49,806評(píng)論 1 290
  • 那天舟误,我揣著相機(jī)與錄音,去河邊找鬼姻乓。 笑死嵌溢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的糖权。 我是一名探鬼主播堵腹,決...
    沈念sama閱讀 38,951評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼星澳!你這毒婦竟也來(lái)了疚顷?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,712評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤禁偎,失蹤者是張志新(化名)和其女友劉穎腿堤,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體如暖,經(jīng)...
    沈念sama閱讀 44,166評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡笆檀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盒至。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酗洒。...
    茶點(diǎn)故事閱讀 38,643評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖枷遂,靈堂內(nèi)的尸體忽然破棺而出樱衷,到底是詐尸還是另有隱情,我是刑警寧澤酒唉,帶...
    沈念sama閱讀 34,306評(píng)論 4 330
  • 正文 年R本政府宣布矩桂,位于F島的核電站,受9級(jí)特大地震影響痪伦,放射性物質(zhì)發(fā)生泄漏侄榴。R本人自食惡果不足惜雹锣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望癞蚕。 院中可真熱鬧蕊爵,春花似錦、人聲如沸涣达。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,745評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)度苔。三九已至匆篓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寇窑,已是汗流浹背鸦概。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,983評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留甩骏,地道東北人窗市。 一個(gè)月前我還...
    沈念sama閱讀 46,351評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像饮笛,于是被迫代替她去往敵國(guó)和親咨察。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 一福青、Java 簡(jiǎn)介 Java是由Sun Microsystems公司于1995年5月推出的Java面向?qū)ο蟪绦蛟O(shè)計(jì)...
    子非魚(yú)_t_閱讀 4,160評(píng)論 1 44
  • 前言 最先接觸編程的知識(shí)是在大學(xué)里面无午,大學(xué)里面學(xué)了一些基礎(chǔ)的知識(shí)媒役,c語(yǔ)言,java語(yǔ)言宪迟,單片機(jī)的匯編語(yǔ)言等酣衷;大學(xué)畢...
    oceanfive閱讀 3,048評(píng)論 0 7
  • Tip:筆者馬上畢業(yè)了,準(zhǔn)備開(kāi)始 Java 的進(jìn)階學(xué)習(xí)計(jì)劃次泽。于是打算先從 String 類(lèi)的源碼分析入手穿仪,作為后面...
    石先閱讀 12,000評(píng)論 16 58
  • 作為哥哥 如何成為一個(gè)好哥哥這種事情是不需要去教導(dǎo)的。 如果是陽(yáng)光燦爛的早上的話——醒后端杯水給她放在床頭意荤,盯著她...
    INBonn閱讀 846評(píng)論 0 0
  • 最早發(fā)布的習(xí)醫(yī)日記1牡借、2呢,有讀者反映廢話略多袭异。我在這里澄清一下:本人首先是以“日記”為標(biāo)題,這已經(jīng)確定了我所寫(xiě)的...
    中醫(yī)學(xué)徒劉志恒閱讀 370評(píng)論 0 0