從jvm角度看懂類(lèi)初始化孕豹、方法重載、重寫(xiě)十气。

類(lèi)初始化

在講類(lèi)的初始化之前励背,我們先來(lái)大概了解一下類(lèi)的聲明周期。如下圖

類(lèi)的聲明周期可以分為7個(gè)階段砸西,但今天我們只講初始化階段叶眉。我們我覺(jué)得出來(lái)使用卸載階段外,初始化階段是最貼近我們平時(shí)學(xué)的芹枷,也是筆試做題過(guò)程中最容易遇到的衅疙,假如你想了解每一個(gè)階段的話(huà),可以看看深入理解Java虛擬機(jī)這本書(shū)鸳慈。

下面開(kāi)始講解初始化過(guò)程饱溢。

注意:

這里需要指出的是,在執(zhí)行類(lèi)的初始化之前蝶涩,其實(shí)在準(zhǔn)備階段就已經(jīng)為類(lèi)變量分配過(guò)內(nèi)存理朋,并且也已經(jīng)設(shè)置過(guò)類(lèi)變量的初始值了。例如像整數(shù)的初始值是0绿聘,對(duì)象的初始值是null之類(lèi)的嗽上。基本數(shù)據(jù)類(lèi)型的初始值如下:

數(shù)據(jù)類(lèi)型 初始值 數(shù)據(jù)類(lèi)型 初始值
int 0 boolean false
long 0L float 0.0f
short (short)0 double 0.0d
char '\u0000' reference null
byte (byte)0

大家先想一個(gè)問(wèn)題熄攘,當(dāng)我們?cè)谶\(yùn)行一個(gè)java程序時(shí)兽愤,每個(gè)類(lèi)都會(huì)被初始化嗎?假如并非每個(gè)類(lèi)都會(huì)執(zhí)行初始化過(guò)程挪圾,那什么時(shí)候一個(gè)類(lèi)會(huì)執(zhí)行初始化過(guò)程呢浅萧?

答案是并非每個(gè)類(lèi)都會(huì)執(zhí)行初始化過(guò)程,你想啊哲思,如果這個(gè)類(lèi)根本就不用用到洼畅,那初始化它干嘛,占用空間棚赔。

至于何時(shí)執(zhí)行初始化過(guò)程帝簇,虛擬機(jī)規(guī)范則是嚴(yán)格規(guī)定了有且只有5中情況會(huì)馬上對(duì)類(lèi)進(jìn)行初始化徘郭。

  1. 當(dāng)使用new這個(gè)關(guān)鍵字實(shí)例化對(duì)象、讀取或者設(shè)置一個(gè)類(lèi)的靜態(tài)字段丧肴,以及調(diào)用一個(gè)類(lèi)的靜態(tài)方法時(shí)會(huì)觸發(fā)類(lèi)的初始化(注意残揉,被final修飾的靜態(tài)字段除外)。
  2. 使用java.lang.reflect包的方法對(duì)類(lèi)進(jìn)行反射調(diào)用時(shí)芋浮,如果這個(gè)類(lèi)還沒(méi)有進(jìn)行過(guò)初始化抱环,則會(huì)觸發(fā)該類(lèi)的初始化。
  3. 當(dāng)初始化一個(gè)類(lèi)時(shí)纸巷,如果其父類(lèi)還沒(méi)有進(jìn)行過(guò)初始化镇草,則會(huì)先觸發(fā)其父類(lèi)。
  4. 當(dāng)虛擬機(jī)啟動(dòng)時(shí)何暇,用戶(hù)需要指定一個(gè)要執(zhí)行的主類(lèi)(包含main()方法的那個(gè)類(lèi))陶夜,虛擬機(jī)會(huì)先初始化這個(gè)主類(lèi)。
  5. 當(dāng)使用JDK 1.7的動(dòng)態(tài)語(yǔ)言支持時(shí)裆站,如果一個(gè).....(省略条辟,說(shuō)了也看不懂,哈哈)宏胯。

注意是有且只有羽嫡。這5種行為我們稱(chēng)為對(duì)一個(gè)類(lèi)的主動(dòng)引用

初始化過(guò)程

類(lèi)的初始化過(guò)程都干了些什么呢肩袍?

在類(lèi)的初始化過(guò)程中杭棵,說(shuō)白了就是執(zhí)行了一個(gè)類(lèi)構(gòu)造器<clinit>()方法過(guò)程。注意氛赐,這個(gè)clinit并非類(lèi)的構(gòu)造函數(shù)(init())魂爪。

至于clinit()方法都包含了哪些內(nèi)容?

實(shí)際上艰管,clinit()方法是由編譯器自動(dòng)收集類(lèi)中的所有類(lèi)變量的賦值動(dòng)作和靜態(tài)語(yǔ)句塊(static{}塊)中的語(yǔ)句合并產(chǎn)生的滓侍,編譯器收集的順序則是由語(yǔ)句在源文件中出現(xiàn)的順序來(lái)決定的。并且靜態(tài)語(yǔ)句塊中只能訪問(wèn)到定義在靜態(tài)語(yǔ)句塊之前的變量牲芋,定義在它之后的變量撩笆,在前面的靜態(tài)語(yǔ)句塊可以賦值,但不能訪問(wèn)缸浦。如下面的程序夕冲。

public class Test1 {
    static {
        t = 10;//編譯可以正常通過(guò)
        System.out.println(t);//提示illegal forward reference錯(cuò)誤
    }
    static int t = 0;
}

給大家拋個(gè)練習(xí)

public class Father {
    public static int t1 = 10;
    static {
        t1 = 20;
    }
}
class Son extends Father{
    public static int t2 = t1;
}
//測(cè)試調(diào)用
class Test2{
    public static void main(String[] args){
        System.out.println(Son.t2);
    }
}

輸出結(jié)果是什么呢?

答案是20裂逐。我相信大家都知道為啥歹鱼。因?yàn)闀?huì)先初始化父類(lèi)啊。

不過(guò)這里需要注意的是卜高,對(duì)于類(lèi)來(lái)說(shuō)醉冤,執(zhí)行該類(lèi)的clinit()方法時(shí)秩霍,會(huì)先執(zhí)行父類(lèi)的clinit()方法,但對(duì)于接口來(lái)說(shuō)蚁阳,執(zhí)行接口的clinit()方法并不會(huì)執(zhí)行父接口的clinit()方法。只有當(dāng)用到父類(lèi)接口中定義的變量時(shí)鸽照,才會(huì)執(zhí)行父接口的clinit()方法螺捐。

被動(dòng)引用

上面說(shuō)了類(lèi)初始化的五種情況,我們稱(chēng)之為稱(chēng)之為主動(dòng)引用矮燎。居然存在主動(dòng)定血,也意味著存在所謂的被動(dòng)引用。這里需要提出的是诞外,被動(dòng)引用并不會(huì)觸發(fā)類(lèi)的初始化澜沟。下面,我們舉例幾個(gè)被動(dòng)引用的例子:

  1. 通過(guò)子類(lèi)引用父類(lèi)的靜態(tài)字段峡谊,不會(huì)觸發(fā)子類(lèi)的初始化
/**
 * 1.通過(guò)子類(lèi)引用父類(lèi)的靜態(tài)字段茫虽,不會(huì)觸發(fā)子類(lèi)的初始化
 */
public class FatherClass {
    //靜態(tài)塊
    static {
        System.out.println("FatherClass init");
    }
    public static int value = 10;
}

class SonClass extends FatherClass {
    static {
        System.out.println("SonClass init");
    }
}
 class Test3{
    public static void main(String[] args){
        System.out.println(SonClass.value);
    }
}

輸出結(jié)果

FatherClass init

說(shuō)明并沒(méi)有觸發(fā)子類(lèi)的初始化

  1. 通過(guò)數(shù)組定義來(lái)引用類(lèi),不會(huì)觸發(fā)此類(lèi)的初始化既们。
 class Test3{
    public static void main(String[] args){
        SonClass[] sonClass = new SonClass[10];//引用上面的SonClass類(lèi)濒析。
    }      
 }

輸出結(jié)果是啥也沒(méi)輸出。

  1. 引用其他類(lèi)的常量并不會(huì)觸發(fā)那個(gè)類(lèi)的初始化
public class FatherClass {
    //靜態(tài)塊
    static {
        System.out.println("FatherClass init");
    }
    public static final String value = "hello";//常量
}

class Test3{
    public static void main(String[] args){
        System.out.println(FatherClass.value);
    }
}

輸出結(jié)果:hello

實(shí)際上啥纸,之所以沒(méi)有輸出"FatherClass init",是因?yàn)樵诰幾g階段就已經(jīng)對(duì)這個(gè)常量進(jìn)行了一些優(yōu)化處理号杏,例如,由于Test3這個(gè)類(lèi)用到了這個(gè)常量"hello"斯棒,在編譯階段就已經(jīng)將"hello"這個(gè)常量?jī)?chǔ)存到了Test3類(lèi)的常量池中了盾致,以后對(duì)FatherClass.value的引用實(shí)際上都被轉(zhuǎn)化為T(mén)est3類(lèi)對(duì)自身常量池的引用了。也就是說(shuō)荣暮,在編譯成class文件之后庭惜,兩個(gè)class已經(jīng)沒(méi)啥毛關(guān)系了。


重載

對(duì)于重載渠驼,我想學(xué)過(guò)java的都懂蜈块,但是今天我們中虛擬機(jī)的角度來(lái)看看重載是怎么回事。

首先我們先來(lái)看一段代碼:

//定義幾個(gè)類(lèi)
public abstract class Animal {
}
class Dog extends Animal{
}
class Lion extends Animal{
}

class Test4{
    public void run(Animal animal){
        System.out.println("動(dòng)物跑啊跑");
    }
    public void run(Dog dog){
        System.out.println("小狗跑啊跑");
    }
    public void run(Lion lion){
        System.out.println("獅子跑啊跑");
    }
    //測(cè)試
    public static void main(String[] args){
        Animal dog = new Dog();
        Animal lion = new Lion();;
        Test4 test4 = new Test4();
        test4.run(dog);
        test4.run(lion);
    }
}

運(yùn)行結(jié)果:

動(dòng)物跑啊跑

動(dòng)物跑啊跑

相信大家學(xué)過(guò)重載的都能猜到是這個(gè)結(jié)果迷扇。但是百揭,為什么會(huì)選擇這個(gè)方法進(jìn)行重載呢?虛擬機(jī)是如何選擇的呢蜓席?

在此之前我們先來(lái)了解兩個(gè)概念器一。

先來(lái)看一行代碼:

Animal dog = new Dog();

對(duì)于這一行代碼,我們把Animal稱(chēng)之為變量dog的靜態(tài)類(lèi)型厨内,而后面的Dog稱(chēng)為變量dog的實(shí)際類(lèi)型祈秕。

所謂靜態(tài)類(lèi)型也就是說(shuō)渺贤,在代碼的編譯期就可以判斷出來(lái)了,也就是說(shuō)在編譯期就可以判斷dog的靜態(tài)類(lèi)型是啥了请毛。但在編譯期無(wú)法知道變量dog的實(shí)際類(lèi)型是什么志鞍。

現(xiàn)在我們?cè)賮?lái)看看虛擬機(jī)是根據(jù)什么來(lái)重載選擇哪個(gè)方法的。

對(duì)于靜態(tài)類(lèi)型相同方仿,但實(shí)際類(lèi)型不同的變量固棚,虛擬機(jī)在重載的時(shí)候是根據(jù)參數(shù)的靜態(tài)類(lèi)型而不是實(shí)際類(lèi)型作為判斷選擇的。并且靜態(tài)類(lèi)型在編譯器就是已知的了仙蚜,這也代表在編譯階段此洲,就已經(jīng)決定好了選擇哪一個(gè)重載方法。

由于dog和lion的靜態(tài)類(lèi)型都是Animal,所以選擇了run(Animal animal)這個(gè)方法委粉。

不過(guò)需要注意的是呜师,有時(shí)候是可以有多個(gè)重載版本的,也就是說(shuō)贾节,重載版本并非是唯一的汁汗。我們不妨來(lái)看下面的代碼。

public class Test {
    public static void sayHello(Object arg){
        System.out.println("hello Object");
    }
    public static void sayHello(int arg){
        System.out.println("hello int");
    }
    public static void sayHello(long arg){
        System.out.println("hello long");
    }
    public static void sayHello(Character arg){
        System.out.println("hello Character");
    }
    public static void sayHello(char arg){
        System.out.println("hello char");
    }
    public static void sayHello(char... arg){
        System.out.println("hello char...");
    }
    public static void sayHello(Serializable arg){
        System.out.println("hello Serializable");
    }

    //測(cè)試
    public static void main(String[] args){
        char a = 'a';
        sayHello('a');
    }
}

運(yùn)行下代碼氮双。
相信大家都知道輸出結(jié)果是

hello char

因?yàn)閍的靜態(tài)類(lèi)型是char,隨意會(huì)匹配到sayHello(char arg);

但是碰酝,如果我們把sayHello(char arg)這個(gè)方法注釋掉,再運(yùn)行下戴差。

結(jié)果輸出:

hello int

實(shí)際上這個(gè)時(shí)候由于方法中并沒(méi)有靜態(tài)類(lèi)型為char的方法送爸,它就會(huì)自動(dòng)進(jìn)行類(lèi)型轉(zhuǎn)換∨停‘a(chǎn)'除了可以是字符袭厂,還可以代表數(shù)字97。因此會(huì)選擇int類(lèi)型的進(jìn)行重載球匕。

我們繼續(xù)注釋掉sayHello(int arg)這個(gè)方法纹磺。結(jié)果會(huì)輸出:

hello long。

這個(gè)時(shí)候'a'進(jìn)行兩次類(lèi)型轉(zhuǎn)換亮曹,即 'a' -> 97 -> 97L橄杨。所以匹配到了sayHell(long arg)方法。

實(shí)際上照卦,'a'會(huì)按照char ->int -> long -> float ->double的順序來(lái)轉(zhuǎn)換式矫。但并不會(huì)轉(zhuǎn)換成byte或者short,因?yàn)閺腸har到byte或者short的轉(zhuǎn)換是不安全的役耕。(為什么不安全采转?留給你思考下)

繼續(xù)注釋掉long類(lèi)型的方法。輸出結(jié)果是:

hello Character

這時(shí)發(fā)生了一次自動(dòng)裝箱瞬痘,'a'被封裝為Character類(lèi)型故慈。

繼續(xù)注釋掉Character類(lèi)型的方法板熊。輸出

hello Serializable

為什么?

一個(gè)字符或者數(shù)字與序列化有什么關(guān)系察绷?實(shí)際上干签,這是因?yàn)镾erializable是Character類(lèi)實(shí)現(xiàn)的一個(gè)接口,當(dāng)自動(dòng)裝箱之后發(fā)現(xiàn)找不到裝箱類(lèi)克婶,但是找到了裝箱類(lèi)實(shí)現(xiàn)了的接口類(lèi)型筒严,所以在一次發(fā)生了自動(dòng)轉(zhuǎn)型。

我們繼續(xù)注釋掉Serialiable情萤,這個(gè)時(shí)候的輸出結(jié)果是:

hello Object

這時(shí)是'a'裝箱后轉(zhuǎn)型為父類(lèi)了,如果有多個(gè)父類(lèi)摹恨,那將從繼承關(guān)系中從下往上開(kāi)始搜索筋岛,即越接近上層的優(yōu)先級(jí)越低。

繼續(xù)注釋掉Object方法晒哄,這時(shí)候輸出:

hello char...

這個(gè)時(shí)候'a'被轉(zhuǎn)換為了一個(gè)數(shù)組元素睁宰。

從上面的例子中,我們可以看出寝凌,元素的靜態(tài)類(lèi)型并非就是一定是固定的柒傻,它在編譯期根根據(jù)優(yōu)先級(jí)原則來(lái)進(jìn)行轉(zhuǎn)換。其實(shí)這也是java語(yǔ)言實(shí)現(xiàn)重載的本質(zhì)

重寫(xiě)

我們先來(lái)看一段代碼

//定義幾個(gè)類(lèi)
public abstract class Animal {
    public abstract void run();
}
class Dog extends Animal{
    @Override
    public void run() {
        System.out.println("小狗跑啊跑");
    }
}
class Lion extends Animal{
    @Override
    public void run() {
        System.out.println("獅子跑啊跑");
    }
}
class Test4{
    //測(cè)試
    public static void main(String[] args){
        Animal dog = new Dog();
        Animal lion = new Lion();;
        dog.run();
        lion.run();
    }
}

運(yùn)行結(jié)果:

小狗跑啊跑
獅子跑啊跑

我相信大家對(duì)這個(gè)結(jié)果是毫無(wú)疑問(wèn)的较木。他們的靜態(tài)類(lèi)型是一樣的红符,虛擬機(jī)是怎么知道要執(zhí)行哪個(gè)方法呢?

顯然伐债,虛擬機(jī)是根據(jù)實(shí)際類(lèi)型來(lái)執(zhí)行方法的预侯。我們來(lái)看看main()方法中的一部分字節(jié)碼

//聲明:我只是挑出了一部分關(guān)鍵的字節(jié)碼
public static void (java.lang.String[]);
    Code:
    Stack=2, Locals=3, Args_size=1;//可以不用管這個(gè)
    //下面的是關(guān)鍵
    0:new #16;//即new Dog
    3: dup
    4: invokespecial #18; //調(diào)用初始化方法
    7: astore_1
    8: new #19 ;即new Lion
    11: dup
    12: invokespecial #21;//調(diào)用初始化方法
    15: astore_2
    
    16: aload_1; 壓入棧頂
    17: invokevirtual #22;//調(diào)用run()方法
    20: aload_2 ;壓入棧頂
    21: invokevirtual #22;//調(diào)用run()方法
    24: return

解釋一下這段字節(jié)碼:

0-15行的作用是創(chuàng)建Dog和Lion對(duì)象的內(nèi)存空間,調(diào)用Dog,Lion類(lèi)型的實(shí)例構(gòu)造器峰锁。對(duì)應(yīng)的代碼:

Animal dog = new Dog();

Animal lion = new Lion();

接下來(lái)的16-21句是關(guān)鍵部分萎馅,16、20兩句分分別把剛剛創(chuàng)建的兩個(gè)對(duì)象的引用壓到棧頂虹蒋。17和21是run()方法的調(diào)用指令糜芳。

從指令可以看出,這兩條方法的調(diào)用指令是完全一樣的魄衅∏涂ⅲ可是最終執(zhí)行的目標(biāo)方法卻并不相同。這是為啥徐绑?

實(shí)際上:

invokevirtual方法調(diào)用指令在執(zhí)行的時(shí)候是這樣的:

  1. 找到棧頂?shù)牡谝粋€(gè)元素所指向的對(duì)象的實(shí)際類(lèi)型邪驮,記作C.
  2. 如果類(lèi)型C中找到run()這個(gè)方法,則進(jìn)行訪問(wèn)權(quán)限的檢驗(yàn)傲茄,如果可以訪問(wèn)毅访,則方法這個(gè)方法的直接引用沮榜,查找結(jié)束;如果這個(gè)方法不可以訪問(wèn)喻粹,則拋出java.lang.IllegalAccessEror異常蟆融。
  3. 如果在該對(duì)象中沒(méi)有找到run()方法,則按照繼承關(guān)系從下往上對(duì)C的各個(gè)父類(lèi)進(jìn)行第二步的搜索和檢驗(yàn)守呜。
  4. 如果都沒(méi)有找到型酥,則拋出java.lang.AbstractMethodError異常。

所以雖然指令的調(diào)用是相同的查乒,但17行調(diào)用run方法時(shí)弥喉,此時(shí)棧頂存放的對(duì)象引用是Dog,21行則是Lion玛迄。

這由境,就是java語(yǔ)言中方法重寫(xiě)的本質(zhì)。

本次的講解到此結(jié)束蓖议,希望對(duì)你有所幫助虏杰。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市勒虾,隨后出現(xiàn)的幾起案子纺阔,更是在濱河造成了極大的恐慌,老刑警劉巖修然,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件笛钝,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡低零,警方通過(guò)查閱死者的電腦和手機(jī)婆翔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)掏婶,“玉大人啃奴,你說(shuō)我怎么就攤上這事⌒弁祝” “怎么了最蕾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)老厌。 經(jīng)常有香客問(wèn)我瘟则,道長(zhǎng),這世上最難降的妖魔是什么枝秤? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任醋拧,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘丹壕。我一直安慰自己庆械,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布菌赖。 她就那樣靜靜地躺著缭乘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪琉用。 梳的紋絲不亂的頭發(fā)上堕绩,一...
    開(kāi)封第一講書(shū)人閱讀 52,328評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音邑时,去河邊找鬼奴紧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛晶丘,可吹牛的內(nèi)容都是我干的绰寞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼铣口,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了觉壶?” 一聲冷哼從身側(cè)響起脑题,我...
    開(kāi)封第一講書(shū)人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎铜靶,沒(méi)想到半個(gè)月后叔遂,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡争剿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年已艰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚕苇。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡哩掺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涩笤,到底是詐尸還是另有隱情嚼吞,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布蹬碧,位于F島的核電站舱禽,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏恩沽。R本人自食惡果不足惜誊稚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧里伯,春花似錦城瞎、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至爷贫,卻和暖如春认然,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背漫萄。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工卷员, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腾务。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓毕骡,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親岩瘦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子未巫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

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