Java--類加載機(jī)制與類加載器

Java的核心是 JVM 版述,了解并熟悉JVM對(duì)于我們理解Java語言非常重要。

一寞冯、類加載機(jī)制

當(dāng)程序主動(dòng)使用某個(gè)類時(shí)渴析,如果該類還未被加載到內(nèi)存中,則系統(tǒng)會(huì)通過加載吮龄、連接俭茧、初始化三個(gè)步驟來對(duì)該類進(jìn)行初始化。

JVM把描述類的數(shù)據(jù)從class文件加載到內(nèi)存漓帚,并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn)母债,轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機(jī)直接使用的Java類型尝抖,這就是JVM的類加載機(jī)制毡们。

1、JVM和類

當(dāng)調(diào)用Java命令運(yùn)行某個(gè)Java程序時(shí)昧辽,該命令將會(huì)啟動(dòng)一個(gè)Java虛擬機(jī)進(jìn)程衙熔,不管該Java程序有多么復(fù)雜,該程序啟動(dòng)了多少個(gè)線程搅荞,它們都處于該Java虛擬機(jī)進(jìn)程里红氯。

同一個(gè)JVM的所有線程、所有變量都處于同一個(gè)進(jìn)程里咕痛,它們都使用該JVM進(jìn)程的內(nèi)存區(qū)痢甘。

當(dāng)系統(tǒng)出現(xiàn)以下幾種情況時(shí),JVM進(jìn)程將被終止:

  • 程序運(yùn)行到最后正常結(jié)束暇检。
  • 程序運(yùn)行到使用System.exit()Runtime.getRuntime().exit() 處程序結(jié)束产阱。
  • 程序執(zhí)行過程中遇到未捕獲的異常或錯(cuò)誤而結(jié)束块仆。
  • 程序所在平臺(tái)強(qiáng)制結(jié)束了JVM進(jìn)程构蹬。

從上面介紹可以知道,當(dāng)Java程序運(yùn)行結(jié)束時(shí)悔据,JVM進(jìn)程結(jié)束庄敛,該進(jìn)程在內(nèi)存中的狀態(tài)將會(huì)丟失。

2科汗、類的加載

類加載:將類的class文件讀入內(nèi)存藻烤,并為之創(chuàng)建一個(gè)java.lang.Class 對(duì)象,也就是說,當(dāng)程序中使用任何類時(shí)怖亭,系統(tǒng)都會(huì)為之建立一個(gè)java.lang.Class對(duì)象涎显。

類的加載由類加載器完成,類加載器通常由JVM提供兴猩,這些類加載器也是前面所有程序運(yùn)行的基礎(chǔ)期吓,JVM提供的這些類加載器通常被稱為系統(tǒng)類加載器。除此之外倾芝,開發(fā)者可以通過繼承 ClassLoader 基類來創(chuàng)建自己的類加載器讨勤。

通過使用不同的類加載器,可以從不同來源加載類的二進(jìn)制數(shù)據(jù)晨另,通常有如下幾種來源:

  • 從本地文件系統(tǒng)加載class文件潭千。
  • 從 JAR 包加載class文件。
  • 通過網(wǎng)絡(luò)加載class文件借尿。
  • 把一個(gè) java 源文件動(dòng)態(tài)編譯刨晴,并進(jìn)行加載。

在加載階段虛擬機(jī)需要完成以下三件事

  1. 通過一個(gè)類的全限定名稱來獲取此類的二進(jìn)制字節(jié)流垛玻,并加載到內(nèi)存中(需要使用類加載器)
  2. 將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)
  3. 在堆中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象割捅,作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的訪問入口
3、類的鏈接

將Java類的二進(jìn)制數(shù)據(jù)合并到 JVM 的運(yùn)行狀態(tài)之中帚桩。

類的連接分為三個(gè)階段:

  1. 驗(yàn)證:驗(yàn)證被加載后的類是否有正確的結(jié)構(gòu)亿驾,類數(shù)據(jù)是否符合虛擬機(jī)的要求,確保不會(huì)危害虛擬機(jī)安全账嚎。
    包含四個(gè)階段的校驗(yàn)動(dòng)作:a.文件格式驗(yàn)證莫瞬;b.原數(shù)據(jù)信息進(jìn)行語義校驗(yàn);c.字節(jié)碼驗(yàn)證郭蕉;d.符號(hào)引用驗(yàn)證疼邀。

  2. 準(zhǔn)備:為類的靜態(tài)變量(static filed)在方法區(qū)分配內(nèi)存,并設(shè)置默認(rèn)初始值(0值或null值)召锈,這些內(nèi)存都將在方法區(qū)分配旁振。對(duì)于一般的成員變量是在類實(shí)例化時(shí)候,隨對(duì)象一起分配在堆內(nèi)存中涨岁。
    另外拐袜,靜態(tài)常量(static final filed)會(huì)在準(zhǔn)備階段賦程序設(shè)定的初值,對(duì)于靜態(tài)變量梢薪,這個(gè)操作是在初始化階段進(jìn)行的蹬铺。

  3. 解析:將類的二進(jìn)制數(shù)據(jù)內(nèi)的符號(hào)引用替換為直接引用。

4秉撇、類的初始化

在該階段甜攀,虛擬機(jī)負(fù)責(zé)對(duì)類進(jìn)行初始化秋泄,主要是對(duì)類變量進(jìn)行初始化。

在Java類中规阀,對(duì)類變量指定初始值有兩種方式:
(1)在聲明類變量時(shí)指定初始值恒序。
(2)在使用靜態(tài)初始化塊時(shí),為類變量指定初始值谁撼。

JVM會(huì)按照這些語句在程序中的排列順序依次執(zhí)行他們奸焙。

JVM初始化一個(gè)類的步驟

  1. 假如這個(gè)類還沒有被加載和連接,則程序先加載并連接該類彤敛。
  2. 假如該類的直接父類還沒有被初始化,則先初始化其直接父類了赌。若該直接父類又有直接父類墨榄,依次類推。所以JVM最先初始化的總是 java.lang.Object 類勿她。
    當(dāng)程序主動(dòng)使用任何一個(gè)類時(shí)袄秩,系統(tǒng)會(huì)保證該類以及所有父類(包括直接父類和間接父類)都會(huì)被初始化。
  3. 假如類中有初始化語句逢并,則系統(tǒng)依次執(zhí)行這些初始化語句之剧。
5、類初始化的時(shí)機(jī)

當(dāng)Java程序首次通過下面的 6種 方式來使用某個(gè)類或接口時(shí)砍聊,系統(tǒng)就會(huì)初始化該類或接口背稼,也稱為主動(dòng)初始化

觸發(fā)類加載的條件

  1. 創(chuàng)建類的實(shí)例玻蝌。
  • 使用 new 來創(chuàng)建實(shí)例蟹肘。
  • 通過反射創(chuàng)建實(shí)例。
  • 通過反序列化來創(chuàng)建實(shí)例俯树。
  1. 調(diào)用類的類變量(靜態(tài)屬性)帘腹,或?yàn)樵擃愖兞抠x值。
  2. 調(diào)用類的靜態(tài)方法许饿。
  3. 通過class文件反射創(chuàng)建對(duì)象阳欲。
    例如:Class.forName("Person");
  4. 初始化一個(gè)子類的時(shí)候,該子類的所有父類都會(huì)被初始化陋率。
  5. java虛擬機(jī)啟動(dòng)時(shí)被標(biāo)記為啟動(dòng)類的類球化,就是 main 方法所在的類。

同時(shí)還需要注意幾點(diǎn)

  1. 在同一個(gè)類加載器下面只能初始化類一次翘贮,如果已近初始化了就不要初始化了赊窥。
    因?yàn)槔奂虞d的最終結(jié)果就是在堆中存有唯一的一個(gè)Class對(duì)象,這樣通過Class對(duì)象就能找到類的相關(guān)信息狸页。
  2. 在編譯時(shí)能夠確定下來的 final修飾的靜態(tài)變量(編譯常量)不會(huì)對(duì)類進(jìn)行初始化锨能。
  3. 在編譯時(shí)無法確定下來的 final修飾的靜態(tài)變量(運(yùn)行時(shí)常量)會(huì)對(duì)類進(jìn)行初始化扯再。
  4. 如果這個(gè)類沒有被加載和連接,那就需要進(jìn)行加載和連接址遇。
  5. 如果這個(gè)類有父類并且這個(gè)父類沒有被初始化熄阻,則先初始化父類。
  6. 如果類中存在初始化語句倔约,依次執(zhí)行初始化語句秃殉。

一個(gè)有關(guān)的小例子:

public class Single {
    private static Single single = new Single();
    public static int counter1;
    public static int counter2 = 0;
    
    private Single () {
        counter1++;
        counter2++;
    }
    
    public static Single getSingle() {
        return single;
    }
    
}
public class SingleTest {
    public static void main(String[] args) {
        Single single = Single.getSingle();
        System.out.println("counter1=" + single.counter1);
        System.out.println("counter2=" + single.counter2);
    }
}

輸出是:
counter1=1
counter2=0

例子分析:

  1. 在執(zhí)行SIngleTest第一句的時(shí)候,還沒有對(duì)Single類進(jìn)行加載和連接浸剩,所以首先需要對(duì)它進(jìn)行加載和連接钾军。
    在連接——準(zhǔn)備階段,要給靜態(tài)變量賦默認(rèn)的初始值绢要。
singel=null
counter1=0
counter2=0
  1. 加載和連接完畢之后吏恭,再進(jìn)行初始化工作。這時(shí)會(huì)依次執(zhí)行重罪。
    首先第一個(gè)靜態(tài)屬性single = new Single();會(huì)執(zhí)行構(gòu)造方法內(nèi)部的邏輯操作樱哼,此時(shí)
counter1=1
counter2=1

接下來第二個(gè)靜態(tài)屬性counter1,程序并沒有對(duì)它進(jìn)行初始化賦值剿配,所以它沒辦法進(jìn)行初始化搅幅。
第三個(gè)屬性counter2我們初始化復(fù)制為0,因此可以初始化為 counter2=1呼胚。

  1. 初始化完畢之后茄唐,就調(diào)用了靜態(tài)方法Single.getSingle(); 放回的 single 已經(jīng)初始化了。

輸出的內(nèi)容也理所當(dāng)然就是counter1=1蝇更,counter2=0

二琢融、類加載器

類加載器負(fù)責(zé)將 .class 文件加載到內(nèi)存中,并為之生成對(duì)應(yīng)的 Class 對(duì)象簿寂。

在JVM中漾抬,一個(gè)類用其全限定類名和其類加載器作為唯一的標(biāo)識(shí)。這樣保證同一個(gè)類不會(huì)再次被載入常遂。

1纳令、類加載器的層級(jí)結(jié)構(gòu)
引導(dǎo)類加載器(Bootstrap ClassLoader)
  • 它用來加載Java的核心庫(JAVA_HOME/jre/lib/rt.jar或sun.boot.class.Path路徑下的內(nèi)容),是用C++代碼來實(shí)現(xiàn)的克胳,并不繼承自java.lang.Classloader平绩。

  • 加載擴(kuò)展類和應(yīng)用程序類加載器,并指定他們的父類加載器漠另。

  • 啟動(dòng)類加載器無法被Java程序直接引用

擴(kuò)展類加載器(Extension ClassLoader)
  • 用來加載Java的擴(kuò)展庫(JAVA_HOME/jre/ext/*.jar或java.ext.dirs路徑下的內(nèi)容)捏雌。 Java虛擬機(jī)的實(shí)現(xiàn)會(huì)提供一個(gè)擴(kuò)展庫目錄。該類加載器在此目錄里面查找并加載Java類笆搓。
  • 由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn)性湿。
應(yīng)用程序類加載器(Application ClassLoader)
  • 它根據(jù)Java應(yīng)用的類路徑(classpath纬傲,java.class.path類。 一般來說肤频,Java應(yīng)用的類都是由它來完成加載的叹括。
  • 由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn)。
自定義類加載器

開發(fā)人員可以用過繼承java.lang.ClassLoader類的方式實(shí)現(xiàn)自己的類加載器宵荒,以滿足一些特殊的要求

2汁雷、類加載機(jī)制——雙親委派模式

幾個(gè)類加載器實(shí)現(xiàn)類加載過程時(shí)相互配合協(xié)作的流程。

從JDK1.2開始报咳,java虛擬機(jī)規(guī)范就推薦開發(fā)者使用雙親委派模式(ParentsDelegation Model)進(jìn)行類加載侠讯,其加載過程如下

  1. 如果一個(gè)類加載器收到了類加載請(qǐng)求,它首先不會(huì)自己去嘗試加載這個(gè)類暑刃,而是把類加載請(qǐng)求委派給父類加載器去完成继低。
  2. 每一層的類加載器都把類加載請(qǐng)求委派給父類加載器,依次向上稍走,直到所有的類加載請(qǐng)求都傳遞給頂層的啟動(dòng)類加載器。
  3. 如果頂層的啟動(dòng)類加載器無法完成加載請(qǐng)求柴底,子類加載器才會(huì)嘗試自己去加載該類婿脸,如果連最初發(fā)起類加載請(qǐng)求的類加載器也無法完成加載請(qǐng)求時(shí),將會(huì)拋出ClassNotFoundException柄驻,而不再調(diào)用其子類加載器去進(jìn)行類加載狐树。

雙親委派模式的類加載機(jī)制的優(yōu)點(diǎn)
不同層次的類加載器具有不同優(yōu)先級(jí),比如所有Java對(duì)象的超級(jí)父類java.lang.Object鸿脓,位于rt.jar抑钟,無論哪個(gè)類加載器加載該類,最終都是由啟動(dòng)類加載器進(jìn)行加載野哭,保證安全在塔。即使用戶自己編寫一個(gè)java.lang.Object類并放入程序中,雖能正常編譯拨黔,但不會(huì)被加載運(yùn)行蛔溃,保證不會(huì)出現(xiàn)混亂。

注意:

  • 并不是所有的類加載器都采用雙親委托機(jī)制篱蝇。
  • tomcat服務(wù)器類加載器也是用代理模式贺待,所不同的是它首先嘗試去加載某個(gè)類,如果找不到再找代理給父類加載器零截。這與一般類加載器的順序是相反的麸塞。
雙親委派模型的代碼實(shí)現(xiàn)

ClassLoader中l(wèi)oadClass方法實(shí)現(xiàn)了雙親委派模型

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        //檢查該類是否已經(jīng)加載過
        Class c = findLoadedClass(name);
        if (c == null) {
            //如果該類沒有加載,則進(jìn)入該分支
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                    //當(dāng)父類的加載器不為空涧衙,則通過父類的loadClass來加載該類
                    c = parent.loadClass(name, false);
                } else {
                    //當(dāng)父類的加載器為空哪工,則調(diào)用啟動(dòng)類加載器來加載該類
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                //非空父類的類加載器無法找到相應(yīng)的類奥此,則拋出異常
            }

            if (c == null) {
                //當(dāng)父類加載器無法加載時(shí),則調(diào)用findClass方法來加載該類
                long t1 = System.nanoTime();
                c = findClass(name); //用戶可通過覆寫該方法正勒,來自定義類加載器

                //用于統(tǒng)計(jì)類加載器相關(guān)的信息
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
            //對(duì)類進(jìn)行l(wèi)ink操作
            resolveClass(c);
        }
        return c;
    }
}

整個(gè)流程大致如下:

a.首先得院,檢查一下指定名稱的類是否已經(jīng)加載過,如果加載過了章贞,就不需要再加載祥绞,直接返回。

b.如果此類沒有加載過鸭限,那么蜕径,再判斷一下是否有父加載器;如果有父加載器败京,則由父加載器加載(即調(diào)用parent.loadClass(name, false);).或者是調(diào)用bootstrap類加載器來加載兜喻。

c.如果父加載器及bootstrap類加載器都沒有找到指定的類,那么調(diào)用當(dāng)前類加載器的findClass方法來完成類加載赡麦。

3朴皆、自定義類加載器

通過擴(kuò)展 ClassLoader 的子類,重寫 ClassLoader 所包含的方法來實(shí)現(xiàn)自定義的類加載器泛粹。

ClassLoader 類有如下兩個(gè)關(guān)鍵方法:

  • loadClass(String name, boolean resolve):該方法為ClassLoader的入口點(diǎn)遂铡,根據(jù)指定名稱來加載類,系統(tǒng)就是調(diào)用 ClassLoader 的該方法來獲取指定類對(duì)應(yīng)的 Class 對(duì)象晶姊。
  • findClass(String name):根據(jù)指定名稱來查找類扒接。

通常推薦重寫 findClass() 方法。

在 ClassLoader 類中還有一個(gè)核心方法:

  • Class defineClass(String name, byte[] b, int off, int len):該方法負(fù)責(zé)將指定類的字節(jié)碼文件(即Class文件们衙,如:Hello.class)讀入字節(jié)數(shù)組 byte[] b 內(nèi)钾怔,并把它轉(zhuǎn)換為 Class 對(duì)象。

無須重寫該方法蒙挑,因?yàn)樵摲椒ㄊ?final 的宗侦。

除此之外,ClassLoader 類還有一些普通方法:

  • findSystemClass(String name):從本地系統(tǒng)裝入文件忆蚀。
  • static getSystemClassLoader():用于返回系統(tǒng)類加載器凝垛。
  • getParent() :獲取該類加載器的父類加載器。
  • resolveClass(Class<?> c):鏈接指定的類蜓谋。
  • findLoadClass(String name):如果Java虛擬機(jī)已經(jīng)加載了名為 name 的類梦皮,則直接返回該類對(duì)應(yīng)的 Class 實(shí)例,否則返回 null 桃焕。該方法是 Java 類加載緩存機(jī)制的體現(xiàn)剑肯。

整個(gè)的函數(shù)調(diào)用流程:

我們可以簡單地自定義一個(gè)類加載器,用于加載某個(gè)class

public class FileSystemClassLoader extends ClassLoader {
    //文件的根目錄
    private String rootDir;

    public FileSystemClassLoader(String rootDir){
        this.rootDir=rootDir;
    }

    //重寫findClass方法
    @Override
    protected Class<?> findClass(String s) throws ClassNotFoundException {
        Class c=findLoadedClass(s);
        if (c!=null){
            return c;
        }else {
            ClassLoader parent=this.getParent();
            //parent獲取不到class時(shí)會(huì)拋出異常观堂,為了繼續(xù)執(zhí)行使用try catch包裹
            try{
                c=parent.loadClass(s);
            }catch (Exception e){

            }
            if (c!=null){
                return  c;
            }else {
                byte[] classData=getClassData(s);
                if (classData==null){
                    throw new ClassNotFoundException();
                }else {
                    //將字節(jié)數(shù)組轉(zhuǎn)為Class
                    c=defineClass(s,classData,0,classData.length);
                }
            }
        }
        return c;
    }

    //將文件轉(zhuǎn)為字節(jié)數(shù)組
    private byte[] getClassData(String className) {
        //改為文件地址
        String path=rootDir+"/"+className.replace(".","/")+".class";
        System.out.println(path);
        ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
        InputStream inputStream=null;
        try {
            inputStream=new FileInputStream(path);
            byte[] buffer=new byte[1024];
            int temp=0;
            while ((temp=inputStream.read(buffer))!=-1){
                byteArrayOutputStream.write(buffer,0,temp);
            }
            return byteArrayOutputStream.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (inputStream!=null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (byteArrayOutputStream!=null){
                try {
                    byteArrayOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}
public class UseCustomClassLoader {
    public static void main(String[]args){
        FileSystemClassLoader loader=new FileSystemClassLoader("/home/xjk");
        FileSystemClassLoader loader2=new FileSystemClassLoader("/home/xjk");
        try {
            Class clazz1=loader.findClass("com.jk.bean.Emp");//本項(xiàng)目自定義的類調(diào)用AppClassLoader
            System.out.println(clazz1.getClassLoader());
            Class clazz2=loader.findClass("java.lang.String");//rt.jar里的類調(diào)用BootstrapClassLoader
            System.out.println(clazz2.getClassLoader());
            Class clazz3=loader.findClass("com.company.Main");//項(xiàng)目外的類調(diào)用自定義的FileSystemClassLoader
            System.out.println(clazz3.getClassLoader());
            Class clazz4=loader2.findClass("com.company.Main");//使用不同類加載器让网,Class對(duì)象不一致
            System.out.println(clazz4.getClassLoader());
            System.out.println(clazz3==clazz4);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

輸出結(jié)果

sun.misc.Launcher$AppClassLoader@18b4aac2
null
com.jk.jvm.FileSystemClassLoader@1d44bcfa
com.jk.jvm.FileSystemClassLoader@6f94fa3e
false

因?yàn)锽ootstrapClassLoader無法被Java程序直接引用呀忧,所以顯示為空。

使用自定義的類加載器溃睹,可以實(shí)現(xiàn)如下常見的功能

  • 執(zhí)行代碼前自動(dòng)驗(yàn)證數(shù)字簽名而账。
  • 根據(jù)用戶提供的密碼解密代碼,從而可以實(shí)現(xiàn)代碼混淆器來避免反編譯 *.class 文件因篇。
  • 根據(jù)用戶需求來動(dòng)態(tài)的加載類泞辐。
  • 根據(jù)用戶需求把其他數(shù)據(jù)以字節(jié)碼的形式加載到應(yīng)用中。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末竞滓,一起剝皮案震驚了整個(gè)濱河市咐吼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌商佑,老刑警劉巖锯茄,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異茶没,居然都是意外死亡肌幽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門抓半,熙熙樓的掌柜王于貴愁眉苦臉地迎上來喂急,“玉大人,你說我怎么就攤上這事琅关。” “怎么了讥蔽?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵涣易,是天一觀的道長。 經(jīng)常有香客問我冶伞,道長新症,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任响禽,我火速辦了婚禮徒爹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘芋类。我一直安慰自己隆嗅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布侯繁。 她就那樣靜靜地躺著胖喳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪贮竟。 梳的紋絲不亂的頭發(fā)上丽焊,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天较剃,我揣著相機(jī)與錄音,去河邊找鬼技健。 笑死写穴,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的雌贱。 我是一名探鬼主播啊送,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼帽芽!你這毒婦竟也來了删掀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤导街,失蹤者是張志新(化名)和其女友劉穎披泪,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搬瑰,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡款票,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了泽论。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片艾少。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖翼悴,靈堂內(nèi)的尸體忽然破棺而出缚够,到底是詐尸還是另有隱情,我是刑警寧澤鹦赎,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布谍椅,位于F島的核電站,受9級(jí)特大地震影響古话,放射性物質(zhì)發(fā)生泄漏雏吭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一陪踩、第九天 我趴在偏房一處隱蔽的房頂上張望杖们。 院中可真熱鬧,春花似錦肩狂、人聲如沸摘完。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽描焰。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間荆秦,已是汗流浹背篱竭。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留步绸,地道東北人掺逼。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像瓤介,于是被迫代替她去往敵國和親吕喘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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