02_JVM學(xué)習(xí)筆記_類(lèi)加載機(jī)制詳解二

編譯期常量與運(yùn)行期常量的區(qū)別

如下代碼執(zhí)行后會(huì)輸出什么結(jié)果规哲?

public class MyTest3 {
    public static void main(String[] args) {
        System.out.println(MyParent3.str);
    }
}

class MyParent3{

    public static final String str = "hello";

    static {
        System.out.println("MyParent3 static code");
    }
}

輸出

hello

修改后的代碼執(zhí)行后會(huì)輸出什么結(jié)果?

public class MyTest3 {
    public static void main(String[] args) {
        System.out.println(MyParent3.str);
    }
}

class MyParent3{

    public static final String str = UUID.randomUUID().toString();

    static {
        System.out.println("MyParent3 static code");
    }
}

輸出

MyParent3 static code
fa328c0d-a230-4126-a720-c04d101f3dc2

小結(jié)

當(dāng)一個(gè)常量的值并非編譯期間可以確定的诽表,那么其值就不會(huì)被放到調(diào)用類(lèi)的常量池中,這時(shí)在運(yùn)行時(shí)唉锌,會(huì)導(dǎo)致主動(dòng)使用這個(gè)常量所在的類(lèi)隅肥,顯然會(huì)導(dǎo)致這個(gè)類(lèi)被初始化。

數(shù)組創(chuàng)建本質(zhì)分析

如下代碼執(zhí)行后會(huì)輸出什么呢袄简?靜態(tài)代碼塊是否會(huì)執(zhí)行腥放?

public class MyTest4 {
    public static void main(String[] args) {
        MyParent4 myParent4 = new MyParent4();//首次主動(dòng)使用
    }
}

class MyParent4 {

    static {
        System.out.println("MyParent4 static block");
    }
}

輸出:

MyParent4 static block

上述代碼是對(duì)類(lèi)主動(dòng)使用情況之一:創(chuàng)建類(lèi)的實(shí)例(首次主動(dòng)使用)

我們?cè)趧?chuàng)建一個(gè)類(lèi)的實(shí)例看下執(zhí)行結(jié)果,靜態(tài)代碼塊會(huì)執(zhí)行幾次痘番?

public class MyTest4 {
    public static void main(String[] args) {
        MyParent4 myParent4 = new MyParent4();//首次主動(dòng)使用
        System.out.println("============");
        MyParent4 myParent41 = new MyParent4();
    }
}

class MyParent4 {

    static {
        System.out.println("MyParent4 static block");
    }
}

輸出

MyParent4 static block
============

非首次對(duì)類(lèi)的主動(dòng)使用不會(huì)導(dǎo)致類(lèi)的初始化捉片。

如下示例代碼會(huì)輸出什么結(jié)果?靜態(tài)代碼塊是否會(huì)執(zhí)行汞舱?數(shù)組類(lèi)型是什么伍纫?

public class MyTest4 {
    public static void main(String[] args) {
        MyParent4[] myParent4s = new MyParent4[1];
        System.out.println(myParent4s.getClass());

        MyParent4[][] myParent4s1 = new MyParent4[1][1];
        System.out.println(myParent4s1.getClass());

        System.out.println(myParent4s.getClass().getSuperclass());
        System.out.println(myParent4s1.getClass().getSuperclass());
    }
}

class MyParent4 {

    static {
        System.out.println("MyParent4 static block");
    }
}

輸出

class [Lcom.leofight.jvm.classloader.MyParent4;
class [[Lcom.leofight.jvm.classloader.MyParent4;
class java.lang.Object
class java.lang.Object

小結(jié)

對(duì)于數(shù)組實(shí)例來(lái)說(shuō),其類(lèi)型是由JVM在運(yùn)行期動(dòng)態(tài)生成的(類(lèi)似動(dòng)態(tài)代理)昂芜,表示為[Lcom.leofight.jvm.classloader.MyParent4這種形式莹规。動(dòng)態(tài)生成的類(lèi)型,其父類(lèi)型就是Object泌神。

對(duì)于數(shù)組來(lái)說(shuō)良漱,JavaDoc經(jīng)常將構(gòu)成數(shù)組的元素為Component,實(shí)際上就是將數(shù)組降低一個(gè)維度后的類(lèi)型欢际。

原生數(shù)據(jù)類(lèi)型數(shù)組對(duì)應(yīng)的數(shù)組類(lèi)型母市,示例代碼

public class MyTest4 {
    public static void main(String[] args) {
        int[] ints = new int[1];
        System.out.println(ints.getClass());
        System.out.println(ints.getClass().getSuperclass());

        char[] chars = new char[1];
        System.out.println(chars.getClass());

        boolean[] booleans = new boolean[1];
        System.out.println(booleans.getClass());

        short[] shorts = new short[1];
        System.out.println(shorts.getClass());

        byte[] bytes = new byte[1];
        System.out.println(bytes.getClass());
    }
}

輸出:

class [I
class java.lang.Object
class [C
class [Z
class [S
class [B

助記符補(bǔ)充

anewarray:表示創(chuàng)建一個(gè)引用類(lèi)型的(如類(lèi)、接口损趋、數(shù)組)數(shù)組患久,并將其引用值壓入棧頂。
newarray:表示創(chuàng)建一個(gè)指定的原始類(lèi)型(如int浑槽、float蒋失、char等)的數(shù)組,并將其引用值壓入棧頂

接口初始化規(guī)則

public class MyTest5 {

    public static void main(String[] args) {
        System.out.println(MyChild5.b);
    }
}

interface MyParent5 {
    public static final int a = 5;
}

interface MyChild5 extends MyParent5 {
    public static final int b = 6;
}

編譯后刪除MyParent5和MyChild5的class文件桐玻,執(zhí)行輸出

6

修改代碼如下:

public class MyTest5 {

    public static void main(String[] args) {
        System.out.println(MyChild5.b);
    }
}

interface MyParent5 {

    public static final int a = 5;

}

interface MyChild5 extends MyParent5 {

    public static final int b = new Random().nextInt(2);
}

編譯后刪除MyParent5和MyChild5的class文件篙挽,執(zhí)行輸出

Exception in thread "main" java.lang.NoClassDefFoundError: com/leofight/jvm/classloader/MyChild5
Exception in thread "main" java.lang.NoClassDefFoundError: com/leofight/jvm/classloader/MyParent5

小結(jié)

當(dāng)一個(gè)接口在初始化時(shí),并不要求父接口都完成了初始化

只有在真正使用到父類(lèi)接口的時(shí)候(如引用接口中所定義的常量時(shí))镊靴,才會(huì)初始化

類(lèi)加載器準(zhǔn)備階段與初始化階段的重要意義分析

示例

public class MyTest6 {
    public static void main(String[] args) {
        Singleton singleton = Singleton.getSingleton();
        System.out.println("counter1: " + Singleton.counter1);
        System.out.println("counter2: " + Singleton.counter2);
    }
}

class Singleton {

    public static int counter1;

    public static int counter2 = 0;

    private static Singleton singleton = new Singleton();

    private Singleton() {
        counter1++;
        counter2++;
    }

    public static Singleton getSingleton() {
        return singleton;
    }
}

輸出結(jié)果會(huì)是什么呢铣卡?

counter1: 1
counter2: 1

分析:
執(zhí)行Singleton.getSingleton()會(huì)調(diào)用public static Singleton getSingleton() { return singleton; }獲取Singleton的實(shí)例,會(huì)調(diào)用代碼private static Singleton singleton = new Singleton();接下來(lái)就會(huì)調(diào)用private Singleton() {counter1++; counter2++; },在調(diào)用構(gòu)造方法之前會(huì)給靜態(tài)變量賦值counter1=0偏竟,counter2=0算行;所以執(zhí)行為都為1。

調(diào)整上述代碼的順序苫耸,修改后代碼如下:

package com.leofight.jvm.classloader;

public class MyTest6 {
    public static void main(String[] args) {
        Singleton singleton = Singleton.getSingleton();
        System.out.println("counter1: " + Singleton.counter1);
        System.out.println("counter2: " + Singleton.counter2);
    }
}

class Singleton {

    public static int counter1;

    private static Singleton singleton = new Singleton();

    private Singleton() {
        counter1++;
        counter2++;//準(zhǔn)備階段的重要意義
    }

    public static int counter2 = 0;

    public static Singleton getSingleton() {
        return singleton;
    }
}

輸出結(jié)果

counter1: 1
counter2: 0

分析:
靜態(tài)變量初始化是按照聲明的順序初始化的,public static int counter1 counter1初始化的初值為0(準(zhǔn)備階段給的默認(rèn)值)儡陨,然后private static Singleton singleton = new Singleton();初始化會(huì)調(diào)用構(gòu)造方法private Singleton() { counter1++; counter2++; }這里引用到了counter2褪子,counter2在準(zhǔn)備階段賦了默認(rèn)值0量淌,所以在這個(gè)階段,counter1嫌褪,counter2 都為1呀枢,繼續(xù)初始化public static int counter2 = 0;顯式的給counter2賦初值為0,所以counter1 =1笼痛,counter=0.

類(lèi)加載器深入解析及重要特性剖析

加載:就是把二進(jìn)制形式的java類(lèi)型讀入java虛擬機(jī)中

驗(yàn)證:類(lèi)文件的結(jié)構(gòu)檢查裙秋、語(yǔ)義檢查、字節(jié)碼驗(yàn)證缨伊、二進(jìn)制兼容性的驗(yàn)證
準(zhǔn)備:為類(lèi)變量分配內(nèi)存摘刑,設(shè)置默認(rèn)值。但是在到達(dá)初始化之前刻坊,類(lèi)變量沒(méi)有初始化為真正的初始化值
解析:解析過(guò)程就是類(lèi)型的常理池中尋找類(lèi)枷恕、接口、字段和方法的符號(hào)引用谭胚,把這些符號(hào)引用替換成直接引用的過(guò)程

初始化:為類(lèi)變量賦予正確的初始值

類(lèi)實(shí)例化
為新的對(duì)象分配內(nèi)存
為實(shí)例變量賦默認(rèn)值
為實(shí)例變量賦正確的初始值
java編譯器為它編譯的每一個(gè)類(lèi)都至少生成一個(gè)實(shí)例初始化方法徐块,在java的class文件中,這個(gè)實(shí)例初始化方法被稱(chēng)為“<init>"灾而。針對(duì)源代碼中每一個(gè)類(lèi)的構(gòu)造方法胡控,java編譯器都產(chǎn)生一個(gè)<init>方法。

類(lèi)的加載的最終產(chǎn)品是位于內(nèi)存中的Class對(duì)象
Class對(duì)象封裝了類(lèi)的方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)旁趟,并且向Java程序員提供了訪問(wèn)方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)的接口昼激。

有兩種類(lèi)型的類(lèi)加載器

  1. Java虛擬機(jī)自帶的加載器
    ①根類(lèi)加載器(Bootstrap)
    ②擴(kuò)展類(lèi)加載器(Extension)
    ③系統(tǒng)(應(yīng)用)類(lèi)加載器(System)
  2. 用戶(hù)自定義的類(lèi)加載器
    ①java.lang.ClassLoader的子類(lèi)
    ② 用戶(hù)可以定制類(lèi)的加載方式

類(lèi)加載器并不需要等到某個(gè)類(lèi)被“首次主動(dòng)使用”時(shí)再加載它

JVM規(guī)范允許類(lèi)加載器在預(yù)料某個(gè)類(lèi)將要被使用時(shí)就預(yù)先加載它,如果在預(yù)先加載的過(guò)程中遇到了.class文件缺失或者存在錯(cuò)誤轻庆,類(lèi)加載器必須在程序首次主動(dòng)使用該類(lèi)時(shí)才報(bào)告錯(cuò)誤(LinkageError錯(cuò)誤)

如果這個(gè)類(lèi)一直沒(méi)有被程序主動(dòng)使用癣猾,那么類(lèi)加載器就不會(huì)報(bào)告錯(cuò)誤。

類(lèi)的驗(yàn)證

類(lèi)被加載后余爆,就進(jìn)入連接階段纷宇,連接就是將已經(jīng)讀入到內(nèi)存的類(lèi)的二進(jìn)制數(shù)據(jù)合并到虛擬機(jī)的允許時(shí)環(huán)境中去。

類(lèi)的驗(yàn)證的內(nèi)容
①類(lèi)文件的結(jié)構(gòu)檢查
②語(yǔ)義檢查
③字節(jié)碼驗(yàn)證
④二進(jìn)制兼容性的驗(yàn)證

在準(zhǔn)備階段蛾方,Java虛擬機(jī)為類(lèi)的靜態(tài)變量分配內(nèi)存像捶,并設(shè)置默認(rèn)的初始值。例如對(duì)于以下Sample類(lèi)桩砰,在準(zhǔn)備階段拓春,將為int類(lèi)型的靜態(tài)變量a分配4個(gè)字節(jié)的內(nèi)存空間,并且賦予默認(rèn)值0亚隅,為long類(lèi)型的靜態(tài)變量b分配8個(gè)字節(jié)的內(nèi)存空間硼莽,并且賦予默認(rèn)值0.

public class Sample {
    private static int a = 1;
    public static long b;

    static {
        b = 2;
    }
  ...
}

在初始化階段,Java虛擬機(jī)執(zhí)行類(lèi)的初始化語(yǔ)句煮纵,為類(lèi)的靜態(tài)變量賦予初始值懂鸵。在程序中偏螺,靜態(tài)變量的初始化有兩種途徑:(1)在靜態(tài)變量的聲明處進(jìn)行初始化;(2)在靜態(tài)代碼塊中進(jìn)行初始化匆光。例如在以下代碼中套像,靜態(tài)變量a和b都被顯式初始化,而靜態(tài)變量c沒(méi)有被顯式初始化终息,它將保持默認(rèn)值0夺巩。

public class Sample {
    private static int a = 1;//在靜態(tài)變量的聲明處進(jìn)行初始化
    public static long b;
    public static long c;

    static {
        b = 2;//在靜態(tài)代碼塊中進(jìn)行初始化
    }

  ...
}

靜態(tài)變量的聲明語(yǔ)句,以及靜態(tài)代碼塊都被看做類(lèi)的初始化語(yǔ)句,Java虛擬機(jī)會(huì)按照初始化語(yǔ)句的類(lèi)文件中的先后順序來(lái)依次執(zhí)行它們。例如一下Sample類(lèi)初始化后倒戏,它的靜態(tài)變量a的取值為4.

 package com.leofight.jvm.classloader;

public class Sample {
    static int a = 1;

    static {
        a = 2;
    }

    static {
        a = 4;
    }

    public static void main(String args[]) {
        System.out.println("a=" + a);//打印a=4
    }
}

類(lèi)的初始化

類(lèi)的初始化步驟

  • 假如這個(gè)類(lèi)還沒(méi)有被加載和連接然磷,那就先進(jìn)行加載和連接
  • 假如類(lèi)存在直接父類(lèi),并且這個(gè)父類(lèi)還沒(méi)有被初始化,那就先初始化直接父類(lèi)。
  • 假如類(lèi)中存在初始化語(yǔ)句,那就依次執(zhí)行這些初始化語(yǔ)句人柿。

類(lèi)的初始化時(shí)機(jī)

  • 主動(dòng)使用
  • 被動(dòng)使用
    詳細(xì)內(nèi)容見(jiàn)上一篇文章

當(dāng)Java虛擬機(jī)初始化一個(gè)類(lèi)時(shí),要求它的所有父類(lèi)都已經(jīng)被初始化忙厌,但是這條規(guī)則并不使用于接口凫岖。

  • 在初始化一個(gè)類(lèi)時(shí),并不會(huì)先初始化它所實(shí)現(xiàn)的接口逢净。
  • 在初始化一個(gè)接口時(shí)哥放,并不會(huì)先初始化它的父接口。

因此爹土,一個(gè)父接口并不會(huì)因?yàn)樗淖咏涌诨蛘邔?shí)現(xiàn)類(lèi)的初始化而初始化甥雕。只有當(dāng)程序首次使用特點(diǎn)接口的靜態(tài)變量時(shí),才會(huì)導(dǎo)致該接口的初始化胀茵。

只有當(dāng)程序訪問(wèn)的靜態(tài)變量或者靜態(tài)方法確實(shí)在當(dāng)前類(lèi)或者當(dāng)前接口中定義時(shí)社露,才可以認(rèn)為是對(duì)類(lèi)或者接口的主動(dòng)使用。

調(diào)用ClassLoader類(lèi)的loadClass方法加載一個(gè)類(lèi)琼娘,并不是對(duì)類(lèi)的主動(dòng)使用峭弟,不會(huì)導(dǎo)致類(lèi)的初始化。

類(lèi)加載器用來(lái)把類(lèi)加載到Java虛擬機(jī)中脱拼。從JDK1.2版本開(kāi)始瞒瘸,類(lèi)的加載過(guò)程采用父親委托機(jī)制,這種機(jī)制能更好地保證Java平臺(tái)的安全熄浓。在此委托機(jī)制中情臭,除了Java虛擬機(jī)自帶的根類(lèi)加載器以外,其余的類(lèi)加載器都有且只有一個(gè)父加載器。當(dāng)Java程序請(qǐng)求加載器loader1加載Sample類(lèi)時(shí)俯在,loader1首先委托自己的父類(lèi)加載器去加載Sample類(lèi)丁侄,若父加載器能加載,則由父加載器完成加載任務(wù)朝巫,否則才由加載器loader1本身加載Sample類(lèi)。

Java虛擬機(jī)自帶了以下幾種加載器石景。

  • 根(Bootstrap)類(lèi)加載器:該加載器沒(méi)有父加載器劈猿。它負(fù)責(zé)加載虛擬機(jī)的核心庫(kù),如java.lang.*等潮孽。例如從例程(Sample.java)可以看出揪荣,java.lang.Object就是由根類(lèi)加載器加載的。根類(lèi)加載器從系統(tǒng)屬性sun.boot.class.path所指定的目錄中加載類(lèi)庫(kù)往史。根類(lèi)加載器的實(shí)現(xiàn)依賴(lài)于底層操作系統(tǒng)仗颈,屬性虛擬機(jī)的實(shí)現(xiàn)的一部分,它并沒(méi)有繼承java.lang.ClassLoader類(lèi)椎例。

  • 擴(kuò)展(Extension)類(lèi)加載器:它的父類(lèi)加載器就是根類(lèi)加載器挨决。它從java.ext.dirs系統(tǒng)屬性所指定的目錄中加載類(lèi)庫(kù),或者從JDK的安裝目錄的jre\lib\ext子目錄(擴(kuò)展目錄)下加載類(lèi)庫(kù)订歪,如果把用戶(hù)創(chuàng)建的JAR文件放在這個(gè)目錄下脖祈,也會(huì)自動(dòng)有擴(kuò)展類(lèi)加載器加載。擴(kuò)展類(lèi)加載器是純Java類(lèi)刷晋,是java.lang.ClassLoader類(lèi)的子類(lèi)盖高。

  • 系統(tǒng)(System)類(lèi)加載器:也稱(chēng)為應(yīng)用類(lèi)加載器,它的父加載器為擴(kuò)展類(lèi)加載器眼虱。它從環(huán)境變量classpath或者系統(tǒng)屬性java.class.path所指定的目錄中加載類(lèi)喻奥,它是用戶(hù)自定義的類(lèi)加載器的默認(rèn)父加載器。系統(tǒng)類(lèi)加載器是純Java類(lèi)捏悬,是java.lang.ClassLoader類(lèi)的子類(lèi)撞蚕。

除了以上虛擬機(jī)自帶的加載器外,用戶(hù)還可以定制自己的類(lèi)加載器邮破。Java提供了抽象類(lèi)java.lang.ClassLoader,所有用戶(hù)自定義類(lèi)的加載器都應(yīng)該繼承ClassLoader類(lèi)诈豌。


類(lèi)加載器雙親委派模型
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市抒和,隨后出現(xiàn)的幾起案子矫渔,更是在濱河造成了極大的恐慌,老刑警劉巖摧莽,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件庙洼,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)油够,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)蚁袭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人石咬,你說(shuō)我怎么就攤上這事揩悄。” “怎么了鬼悠?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵删性,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我焕窝,道長(zhǎng)蹬挺,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任它掂,我火速辦了婚禮巴帮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘虐秋。我一直安慰自己榕茧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布熟妓。 她就那樣靜靜地躺著雪猪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪起愈。 梳的紋絲不亂的頭發(fā)上只恨,一...
    開(kāi)封第一講書(shū)人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音抬虽,去河邊找鬼官觅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛阐污,可吹牛的內(nèi)容都是我干的休涤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼笛辟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼功氨!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起手幢,我...
    開(kāi)封第一講書(shū)人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤捷凄,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后围来,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體跺涤,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匈睁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了桶错。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片航唆。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖院刁,靈堂內(nèi)的尸體忽然破棺而出糯钙,到底是詐尸還是另有隱情,我是刑警寧澤退腥,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布超营,位于F島的核電站,受9級(jí)特大地震影響阅虫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜不跟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一颓帝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窝革,春花似錦购城、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至漆诽,卻和暖如春侮攀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厢拭。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工兰英, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人供鸠。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓畦贸,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親楞捂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子薄坏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

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