Java 8 Nashorn 教程

Java 8 Nashorn 教程

原文:Java 8 Nashorn Tutorial

譯者:飛龍

協(xié)議:CC BY-NC-SA 4.0

這個(gè)教程中撵割,你會(huì)通過(guò)簡(jiǎn)單易懂的代碼示例,來(lái)了解Nashorn JavaScript引擎谤绳。Nashorn JavaScript引擎是Java SE 8 的一部分,并且和其它獨(dú)立的引擎例如Google V8(用于Google Chrome和Node.js的引擎)互相競(jìng)爭(zhēng)卓嫂。Nashorn通過(guò)在JVM上且预,以原生方式運(yùn)行動(dòng)態(tài)的JavaScript代碼來(lái)擴(kuò)展Java的功能。

在接下來(lái)的15分鐘內(nèi)掌呜,你會(huì)學(xué)到如何在JVM上在運(yùn)行時(shí)動(dòng)態(tài)執(zhí)行JavaScript。我會(huì)使用小段代碼示例來(lái)演示最新的Nashron語(yǔ)言特性坪哄。你會(huì)學(xué)到如何在Java代碼中調(diào)用JavaScript函數(shù)质蕉,或者相反势篡。最后你會(huì)準(zhǔn)備好將動(dòng)態(tài)腳本集成到你的Java日常業(yè)務(wù)中。

更新 - 我現(xiàn)在正在編寫用于瀏覽器的Java8數(shù)據(jù)流API的JavaScript實(shí)現(xiàn)模暗。如果你對(duì)此感興趣禁悠,請(qǐng)?jiān)贕ithub上訪問(wèn)Stream.js。非常期待你的反饋兑宇。

使用 Nashron

Nashorn JavaScript引擎可以在Java代碼中編程調(diào)用碍侦,也可以通過(guò)命令行工具jjs使用,它在$JAVA_HOME/bin中隶糕。如果打算使用jjs瓷产,你可能希望設(shè)置符號(hào)鏈接來(lái)簡(jiǎn)化訪問(wèn):

$ cd /usr/bin
$ ln -s $JAVA_HOME/bin/jjs jjs
$ jjs
jjs> print('Hello World');

這個(gè)教程專注于在Java代碼中調(diào)用Nashron,所以讓我們先跳過(guò)jjs枚驻。Java代碼中簡(jiǎn)單的HelloWorld如下所示:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval("print('Hello World!');");

為了在Java中執(zhí)行JavaScript濒旦,你首先要通過(guò)javax.script包創(chuàng)建腳本引擎。這個(gè)包已經(jīng)在Rhino(來(lái)源于Mozilla再登、Java中的遺留JS引擎)中使用了尔邓。

JavaScript代碼既可以通過(guò)傳遞JavaScript代碼字符串,也可以傳遞指向你的JS腳本文件的FileReader來(lái)執(zhí)行:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("script.js"));

Nashorn JavaScript基于ECMAScript 5.1锉矢,但是它的后續(xù)版本會(huì)對(duì)ES6提供支持:

Nashorn的當(dāng)前策略遵循ECMAScript規(guī)范梯嗽。當(dāng)我們?cè)贘DK8中發(fā)布它時(shí),它將基于ECMAScript 5.1沈撞。Nashorn未來(lái)的主要發(fā)布基于ECMAScript 6慷荔。

Nashorn定義了大量對(duì)ECMAScript標(biāo)準(zhǔn)的語(yǔ)言和API擴(kuò)展雕什。但是首先讓我們看一看Java和JavaScript代碼如何交互缠俺。

在Java中調(diào)用JavaScript函數(shù)

Nashorn 支持從Java代碼中直接調(diào)用定義在腳本文件中的JavaScript函數(shù)。你可以將Java對(duì)象傳遞為函數(shù)參數(shù)贷岸,并且從函數(shù)返回?cái)?shù)據(jù)來(lái)調(diào)用Java方法壹士。

下面的JavaScript函數(shù)稍后會(huì)在Java端調(diào)用:

var fun1 = function(name) {
    print('Hi there from Javascript, ' + name);
    return "greetings from javascript";
};

var fun2 = function (object) {
    print("JS Class Definition: " + Object.prototype.toString.call(object));
};

為了調(diào)用函數(shù),你首先需要將腳本引擎轉(zhuǎn)換為Invocable偿警。Invocable接口由NashornScriptEngine實(shí)現(xiàn)躏救,并且定義了invokeFunction方法來(lái)調(diào)用指定名稱的JavaScript函數(shù)。

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("script.js"));

Invocable invocable = (Invocable) engine;

Object result = invocable.invokeFunction("fun1", "Peter Parker");
System.out.println(result);
System.out.println(result.getClass());

// Hi there from Javascript, Peter Parker
// greetings from javascript
// class java.lang.String

執(zhí)行這段代碼會(huì)在控制臺(tái)產(chǎn)生三行結(jié)果螟蒸。調(diào)用函數(shù)print將結(jié)果輸出到System.out盒使,所以我們會(huì)首先看到JavaScript輸出。

現(xiàn)在讓我們通過(guò)傳入任意Java對(duì)象來(lái)調(diào)用第二個(gè)函數(shù):

invocable.invokeFunction("fun2", new Date());
// [object java.util.Date]

invocable.invokeFunction("fun2", LocalDateTime.now());
// [object java.time.LocalDateTime]

invocable.invokeFunction("fun2", new Person());
// [object com.winterbe.java8.Person]

Java對(duì)象在傳入時(shí)不會(huì)在JavaScript端損失任何類型信息七嫌。由于腳本在JVM上原生運(yùn)行少办,我們可以在Nashron上使用Java API或外部庫(kù)的全部功能。

在JavaScript中調(diào)用Java方法

在JavaScript中調(diào)用Java方法十分容易诵原。我們首先需要定義一個(gè)Java靜態(tài)方法英妓。

static String fun1(String name) {
    System.out.format("Hi there from Java, %s", name);
    return "greetings from java";
}

Java類可以通過(guò)Java.typeAPI擴(kuò)展在JavaScript中引用挽放。它就和Java代碼中的import類似。只要定義了Java類型蔓纠,我們就可以自然地調(diào)用靜態(tài)方法fun1()辑畦,然后像sout打印信息。由于方法是靜態(tài)的腿倚,我們不需要首先創(chuàng)建實(shí)例纯出。

var MyJavaClass = Java.type('my.package.MyJavaClass');

var result = MyJavaClass.fun1('John Doe');
print(result);

// Hi there from Java, John Doe
// greetings from java

在使用JavaScript原生類型調(diào)用Java方法時(shí),Nashorn 如何處理類型轉(zhuǎn)換猴誊?讓我們通過(guò)簡(jiǎn)單的例子來(lái)弄清楚潦刃。

下面的Java方法簡(jiǎn)單打印了方法參數(shù)的實(shí)際類型:

static void fun2(Object object) {
    System.out.println(object.getClass());
}

為了理解背后如何處理類型轉(zhuǎn)換,我們使用不同的JavaScript類型來(lái)調(diào)用這個(gè)方法:

MyJavaClass.fun2(123);
// class java.lang.Integer

MyJavaClass.fun2(49.99);
// class java.lang.Double

MyJavaClass.fun2(true);
// class java.lang.Boolean

MyJavaClass.fun2("hi there")
// class java.lang.String

MyJavaClass.fun2(new Number(23));
// class jdk.nashorn.internal.objects.NativeNumber

MyJavaClass.fun2(new Date());
// class jdk.nashorn.internal.objects.NativeDate

MyJavaClass.fun2(new RegExp());
// class jdk.nashorn.internal.objects.NativeRegExp

MyJavaClass.fun2({foo: 'bar'});
// class jdk.nashorn.internal.scripts.JO4

JavaScript原始類型轉(zhuǎn)換為合適的Java包裝類懈叹,而JavaScript原生對(duì)象會(huì)使用內(nèi)部的適配器類來(lái)表示乖杠。要記住jdk.nashorn.internal中的類可能會(huì)有所變化,所以不應(yīng)該在客戶端面向這些類來(lái)編程澄成。

任何標(biāo)記為“內(nèi)部”的東西都可能會(huì)從你那里發(fā)生改變胧洒。

ScriptObjectMirror

在向Java傳遞原生JavaScript對(duì)象時(shí),你可以使用ScriptObjectMirror類墨状,它實(shí)際上是底層JavaScript對(duì)象的Java表示卫漫。ScriptObjectMirror實(shí)現(xiàn)了Map接口,位于jdk.nashorn.api中肾砂。這個(gè)包中的類可以用于客戶端代碼列赎。

下面的例子將參數(shù)類型從Object改為ScriptObjectMirror,所以我們可以從傳入的JavaScript對(duì)象中獲得一些信息镐确。

static void fun3(ScriptObjectMirror mirror) {
    System.out.println(mirror.getClassName() + ": " +
        Arrays.toString(mirror.getOwnKeys(true)));
}

當(dāng)向這個(gè)方法傳遞對(duì)象(哈希表)時(shí)包吝,在Java端可以訪問(wèn)其屬性:

MyJavaClass.fun3({
    foo: 'bar',
    bar: 'foo'
});

// Object: [foo, bar]

我們也可以在Java中調(diào)用JavaScript的成員函數(shù)。讓我們首先定義JavaScript Person類型源葫,帶有屬性firstNamelastName诗越,以及方法getFullName

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.getFullName = function() {
        return this.firstName + " " + this.lastName;
    }
}

JavaScript方法getFullName可以通過(guò)callMember()ScriptObjectMirror上調(diào)用息堂。

static void fun4(ScriptObjectMirror person) {
    System.out.println("Full Name is: " + person.callMember("getFullName"));
}

當(dāng)向Java方法傳遞新的Person時(shí)嚷狞,我們會(huì)在控制臺(tái)看到預(yù)期的結(jié)果:

var person1 = new Person("Peter", "Parker");
MyJavaClass.fun4(person1);

// Full Name is: Peter Parker

語(yǔ)言擴(kuò)展

Nashorn定義了多種對(duì)ECMAScript標(biāo)準(zhǔn)的語(yǔ)言和API擴(kuò)展。讓我們看一看最新的特性:

類型數(shù)組

JavaScript的原生數(shù)組是無(wú)類型的荣堰。Nashron允許你在JavaScript中使用Java的類型數(shù)組:

var IntArray = Java.type("int[]");

var array = new IntArray(5);
array[0] = 5;
array[1] = 4;
array[2] = 3;
array[3] = 2;
array[4] = 1;

try {
    array[5] = 23;
} catch (e) {
    print(e.message);  // Array index out of range: 5
}

array[0] = "17";
print(array[0]);  // 17

array[0] = "wrong type";
print(array[0]);  // 0

array[0] = "17.3";
print(array[0]);  // 17

int[]數(shù)組就像真實(shí)的Java整數(shù)數(shù)組那樣床未。但是此外,在我們?cè)噲D向數(shù)組添加非整數(shù)時(shí)振坚,Nashron在背后執(zhí)行了一些隱式的轉(zhuǎn)換薇搁。字符串會(huì)自動(dòng)轉(zhuǎn)換為整數(shù),這十分便利屡拨。

集合和范圍遍歷

我們可以使用任何Java集合只酥,而避免使用數(shù)組瞎折騰褥实。首先需要通過(guò)Java.type定義Java類型,之后創(chuàng)建新的實(shí)例裂允。

var ArrayList = Java.type('java.util.ArrayList');
var list = new ArrayList();
list.add('a');
list.add('b');
list.add('c');

for each (var el in list) print(el);  // a, b, c

為了迭代集合和數(shù)組损离,Nashron引入了for each語(yǔ)句。它就像Java的范圍遍歷那樣工作绝编。

下面是另一個(gè)集合的范圍遍歷示例僻澎,使用HashMap

var map = new java.util.HashMap();
map.put('foo', 'val1');
map.put('bar', 'val2');

for each (var e in map.keySet()) print(e);  // foo, bar

for each (var e in map.values()) print(e);  // val1, val2

Lambda表達(dá)式和數(shù)據(jù)流

每個(gè)人都熱愛lambda和數(shù)據(jù)流 -- Nashron也一樣!雖然ECMAScript 5.1沒有Java8 lmbda表達(dá)式的簡(jiǎn)化箭頭語(yǔ)法十饥,我們可以在任何接受lambda表達(dá)式的地方使用函數(shù)字面值窟勃。

var list2 = new java.util.ArrayList();
list2.add("ddd2");
list2.add("aaa2");
list2.add("bbb1");
list2.add("aaa1");
list2.add("bbb3");
list2.add("ccc");
list2.add("bbb2");
list2.add("ddd1");

list2
    .stream()
    .filter(function(el) {
        return el.startsWith("aaa");
    })
    .sorted()
    .forEach(function(el) {
        print(el);
    });
    // aaa1, aaa2

類的繼承

Java類型可以由Java.extend輕易擴(kuò)展。就像你在下面的例子中看到的那樣逗堵,你甚至可以在你的腳本中創(chuàng)建多線程的代碼:

var Runnable = Java.type('java.lang.Runnable');
var Printer = Java.extend(Runnable, {
    run: function() {
        print('printed from a separate thread');
    }
});

var Thread = Java.type('java.lang.Thread');
new Thread(new Printer()).start();

new Thread(function() {
    print('printed from another thread');
}).start();

// printed from a separate thread
// printed from another thread

參數(shù)重載

方法和函數(shù)可以通過(guò)點(diǎn)運(yùn)算符或方括號(hào)運(yùn)算符來(lái)調(diào)用:

var System = Java.type('java.lang.System');
System.out.println(10);              // 10
System.out["println"](11.0);         // 11.0
System.out["println(double)"](12);   // 12.0

當(dāng)使用重載參數(shù)調(diào)用方法時(shí)秉氧,傳遞可選參數(shù)類型println(double)會(huì)指定所調(diào)用的具體方法。

Java Beans

你可以簡(jiǎn)單地使用屬性名稱來(lái)向Java Beans獲取或設(shè)置值蜒秤,不需要顯式調(diào)用讀寫器:

var Date = Java.type('java.util.Date');
var date = new Date();
date.year += 1900;
print(date.year);  // 2014

函數(shù)字面值

對(duì)于簡(jiǎn)單的單行函數(shù)汁咏,我們可以去掉花括號(hào):

function sqr(x) x * x;
print(sqr(3));    // 9

屬性綁定

兩個(gè)不同對(duì)象的屬性可以綁定到一起:

var o1 = {};
var o2 = { foo: 'bar'};

Object.bindProperties(o1, o2);

print(o1.foo);    // bar
o1.foo = 'BAM';
print(o2.foo);    // BAM

字符串去空白

我喜歡去掉空白的字符串:

print("   hehe".trimLeft());            // hehe
print("hehe    ".trimRight() + "he");   // hehehe

位置

以防你忘了自己在哪里:

print(__FILE__, __LINE__, __DIR__);

導(dǎo)入作用域

有時(shí)一次導(dǎo)入多個(gè)Java包會(huì)很方便。我們可以使用JavaImporter類作媚,和with語(yǔ)句一起使用攘滩。所有被導(dǎo)入包的類文件都可以在with語(yǔ)句的局部域中訪問(wèn)到。

var imports = new JavaImporter(java.io, java.lang);
with (imports) {
    var file = new File(__FILE__);
    System.out.println(file.getAbsolutePath());
    // /path/to/my/script.js
}

數(shù)組轉(zhuǎn)換

一些類似java.util的包可以不使用java.typeJavaImporter直接訪問(wèn):

var list = new java.util.ArrayList();
list.add("s1");
list.add("s2");
list.add("s3");

下面的代碼將Java列表轉(zhuǎn)換為JavaScript原生數(shù)組:

var jsArray = Java.from(list);
print(jsArray);                                  // s1,s2,s3
print(Object.prototype.toString.call(jsArray));  // [object Array]

下面的代碼執(zhí)行相反操作:

var javaArray = Java.to([3, 5, 7, 11], "int[]");

訪問(wèn)超類

在JavaScript中訪問(wèn)被覆蓋的成員通常比較困難纸泡,因?yàn)镴ava的super關(guān)鍵字在ECMAScript中并不存在漂问。幸運(yùn)的是,Nashron有一套補(bǔ)救措施女揭。

首先我們需要在Java代碼中定義超類:

class SuperRunner implements Runnable {
    @Override
    public void run() {
        System.out.println("super run");
    }
}

下面我在JavaScript中覆蓋了SuperRunner蚤假。要注意創(chuàng)建新的Runner實(shí)例時(shí)的Nashron語(yǔ)法:覆蓋成員的語(yǔ)法取自Java的匿名對(duì)象。

var SuperRunner = Java.type('com.winterbe.java8.SuperRunner');
var Runner = Java.extend(SuperRunner);

var runner = new Runner() {
    run: function() {
        Java.super(runner).run();
        print('on my run');
    }
}
runner.run();

// super run
// on my run

我們通過(guò)Java.super()擴(kuò)展調(diào)用了被覆蓋的SuperRunner.run()方法田绑。

加載腳本

在JavaScript中加載額外的腳本文件非常方便勤哗。我們可以使用load函數(shù)加載本地或遠(yuǎn)程腳本抡爹。

我在我的Web前端中大量使用Underscore.js掩驱,所以讓我們?cè)贜ashron中復(fù)用它:

load('http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js');

var odds = _.filter([1, 2, 3, 4, 5, 6], function (num) {
    return num % 2 == 1;
});

print(odds);  // 1, 3, 5

外部腳本會(huì)在相同JavaScript上下文中被執(zhí)行,所以我們可以直接訪問(wèn)underscore 的對(duì)象冬竟。要記住當(dāng)變量名稱互相沖突時(shí)欧穴,腳本的加載可能會(huì)使你的代碼崩潰。

這一問(wèn)題可以通過(guò)把腳本文件加載到新的全局上下文來(lái)繞過(guò):

loadWithNewGlobal('script.js');

命令行腳本

如果你對(duì)編寫命令行(shell)腳本感興趣泵殴,來(lái)試一試Nake吧涮帘。Nake是一個(gè)Java 8 Nashron的簡(jiǎn)化構(gòu)建工具。你只需要在項(xiàng)目特定的Nakefile中定義任務(wù)笑诅,之后通過(guò)在命令行鍵入nake -- myTask來(lái)執(zhí)行這些任務(wù)调缨。任務(wù)編寫為JavaScript疮鲫,并且在Nashron的腳本模式下運(yùn)行,所以你可以使用你的終端弦叶、JDK8 API和任意Java庫(kù)的全部功能俊犯。

對(duì)Java開發(fā)者來(lái)說(shuō),編寫命令行腳本是前所未有的簡(jiǎn)單...

到此為止

我希望這個(gè)教程對(duì)你有所幫助伤哺,并且你能夠享受Nashron JavaScript引擎之旅燕侠。有關(guān)Nashron的更多信息,請(qǐng)見這里立莉、這里這里绢彤。使用Nashron編寫shell腳本的教程請(qǐng)見這里

我最近發(fā)布了一篇后續(xù)文章蜓耻,關(guān)于如何在Nashron中使用Backbone.js模型茫舶。如果你想要進(jìn)一步學(xué)習(xí)Java8,請(qǐng)閱讀我的Java8教程刹淌,和我的Java8數(shù)據(jù)流教程奇适。

這篇Nashron教程中的可運(yùn)行的源代碼托管在Github上。請(qǐng)隨意fork我的倉(cāng)庫(kù)芦鳍,或者在Twitter上向我反饋嚷往。

請(qǐng)堅(jiān)持編程!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末柠衅,一起剝皮案震驚了整個(gè)濱河市皮仁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌菲宴,老刑警劉巖贷祈,帶你破解...
    沈念sama閱讀 212,599評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異喝峦,居然都是意外死亡势誊,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門谣蠢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)粟耻,“玉大人,你說(shuō)我怎么就攤上這事眉踱〖访Γ” “怎么了?”我有些...
    開封第一講書人閱讀 158,084評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵谈喳,是天一觀的道長(zhǎng)册烈。 經(jīng)常有香客問(wèn)我,道長(zhǎng)婿禽,這世上最難降的妖魔是什么赏僧? 我笑而不...
    開封第一講書人閱讀 56,708評(píng)論 1 284
  • 正文 為了忘掉前任大猛,我火速辦了婚禮,結(jié)果婚禮上淀零,老公的妹妹穿的比我還像新娘胎署。我一直安慰自己,他們只是感情好窑滞,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評(píng)論 6 386
  • 文/花漫 我一把揭開白布琼牧。 她就那樣靜靜地躺著,像睡著了一般哀卫。 火紅的嫁衣襯著肌膚如雪巨坊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,021評(píng)論 1 291
  • 那天此改,我揣著相機(jī)與錄音趾撵,去河邊找鬼。 笑死共啃,一個(gè)胖子當(dāng)著我的面吹牛占调,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播移剪,決...
    沈念sama閱讀 39,120評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼究珊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了纵苛?” 一聲冷哼從身側(cè)響起剿涮,我...
    開封第一講書人閱讀 37,866評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎攻人,沒想到半個(gè)月后取试,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,308評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怀吻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評(píng)論 2 327
  • 正文 我和宋清朗相戀三年瞬浓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蓬坡。...
    茶點(diǎn)故事閱讀 38,768評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡猿棉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出渣窜,到底是詐尸還是另有隱情铺根,我是刑警寧澤宪躯,帶...
    沈念sama閱讀 34,461評(píng)論 4 333
  • 正文 年R本政府宣布乔宿,位于F島的核電站,受9級(jí)特大地震影響访雪,放射性物質(zhì)發(fā)生泄漏详瑞。R本人自食惡果不足惜掂林,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坝橡。 院中可真熱鬧泻帮,春花似錦、人聲如沸计寇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)番宁。三九已至元莫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蝶押,已是汗流浹背踱蠢。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棋电,地道東北人茎截。 一個(gè)月前我還...
    沈念sama閱讀 46,571評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像赶盔,于是被迫代替她去往敵國(guó)和親企锌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評(píng)論 2 350

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,851評(píng)論 25 707
  • 光譜調(diào)性的代表數(shù)字11于未,兩橫在下面霎俩,上面有一點(diǎn)。代表動(dòng)物是蛇沉眶。 光譜調(diào)性打却,想象一束光射來(lái),經(jīng)過(guò)三棱鏡的折射谎倔,最后分...
    星之奇旅的馮晶晶閱讀 3,351評(píng)論 0 16
  • 水果店的水果放置時(shí)間太久,很多都爛掉了老板問(wèn)伙計(jì):打算怎么處理爛掉的水果藕咏?伙計(jì)回答道:低價(jià)處理掉或者…..直接扔掉...
    王宇庭閱讀 970評(píng)論 3 10
  • 2016-11-2 大概因?yàn)楹ε鲁臭[,所以一直習(xí)慣了獨(dú)自旅行∥魃瑁荒唐的時(shí)候瓣铣,一旦想出發(fā),一個(gè)人背起書包就出發(fā)了贷揽,無(wú)論...
    我是離蘇閱讀 389評(píng)論 0 1
  • 有星星的夜晚 無(wú)人的街 一個(gè)人走著走著就笑了 自言自語(yǔ)棠笑,手舞足蹈 做個(gè)沒有人看的到的鬼臉
    書_路閱讀 226評(píng)論 10 4