2019-08-21

1.7 對象的創(chuàng)建和存在時間

1.7 對象的創(chuàng)建和存在時間

從技術(shù)角度說,OOP(面向?qū)ο蟪绦蛟O(shè)計)只是涉及抽象的數(shù)據(jù)類型淘正、繼承以及多形性绣硝,但另一些問題也可能顯得非常重要矩动。本節(jié)將就這些問題進(jìn)行探討。

最重要的問題之一是對象的創(chuàng)建及破壞方式。對象需要的數(shù)據(jù)位于哪兒芬膝,如何控制對象的“存在時間”呢望门?針對這個問題,解決的方案是各異其趣的锰霜。C++認(rèn)為程序的執(zhí)行效率是最重要的一個問題筹误,所以它允許程序員作出選擇。為獲得最快的運行速度癣缅,存儲以及存在時間可在編寫程序時決定厨剪,只需將對象放置在堆棧(有時也叫作自動或定域變量)或者靜態(tài)存儲區(qū)域即可。這樣便為存儲空間的分配和釋放提供了一個優(yōu)先級所灸。某些情況下丽惶,這種優(yōu)先級的控制是非常有價值的。然而爬立,我們同時也犧牲了靈活性钾唬,因為在編寫程序時,必須知道對象的準(zhǔn)確的數(shù)量侠驯、存在時間抡秆、以及類型。如果要解決的是一個較常規(guī)的問題吟策,如計算機輔助設(shè)計儒士、倉儲管理或者空中交通控制,這一方法就顯得太局限了檩坚。

第二個方法是在一個內(nèi)存池中動態(tài)創(chuàng)建對象着撩,該內(nèi)存池亦叫“堆”或者“內(nèi)存堆”。若采用這種方式匾委,除非進(jìn)入運行期拖叙,否則根本不知道到底需要多少個對象,也不知道它們的存在時間有多長赂乐,以及準(zhǔn)確的類型是什么薯鳍。這些參數(shù)都在程序正式運行時才決定的。若需一個新對象挨措,只需在需要它的時候在內(nèi)存堆里簡單地創(chuàng)建它即可挖滤。由于存儲空間的管理是運行期間動態(tài)進(jìn)行的,所以在內(nèi)存堆里分配存儲空間的時間比在堆棧里創(chuàng)建的時間長得多(在堆棧里創(chuàng)建存儲空間一般只需要一個簡單的指令浅役,將堆棧指針向下或向下移動即可)斩松。由于動態(tài)創(chuàng)建方法使對象本來就傾向于復(fù)雜,所以查找存儲空間以及釋放它所需的額外開銷不會為對象的創(chuàng)建造成明顯的影響觉既。除此以外砸民,更大的靈活性對于常規(guī)編程問題的解決是至關(guān)重要的。

C++允許我們決定是在寫程序時創(chuàng)建對象,還是在運行期間創(chuàng)建岭参,這種控制方法更加靈活反惕。大家或許認(rèn)為既然它如此靈活,那么無論如何都應(yīng)在內(nèi)存堆里創(chuàng)建對象演侯,而不是在堆棧中創(chuàng)建姿染。但還要考慮另外一個問題,亦即對象的“存在時間”或者“生存時間”(Lifetime)秒际。若在堆椥停或者靜態(tài)存儲空間里創(chuàng)建一個對象,編譯器會判斷對象的持續(xù)時間有多長娄徊,到時會自動“破壞”或者“清除”它闽颇。程序員可用兩種方法來破壞一個對象:用程序化的方式?jīng)Q定何時破壞對象,或者利用由運行環(huán)境提供的一種“垃圾收集器”特性寄锐,自動尋找那些不再使用的對象兵多,并將其清除。當(dāng)然橄仆,垃圾收集器顯得方便得多剩膘,但要求所有應(yīng)用程序都必須容忍垃圾收集器的存在,并能默許隨垃圾收集帶來的額外開銷盆顾。但這并不符合C++語言的設(shè)計宗旨怠褐,所以未能包括到C++里。但Java確實提供了一個垃圾收集器(Smalltalk也有這樣的設(shè)計您宪;盡管Delphi默認(rèn)為沒有垃圾收集器奈懒,但可選擇安裝;而C++亦可使用一些由其他公司開發(fā)的垃圾收集產(chǎn)品)宪巨。

本節(jié)剩下的部分將討論操縱對象時要考慮的另一些因素筐赔。

1.7.1 集合與繼承器

針對一個特定問題的解決,如果事先不知道需要多少個對象揖铜,或者它們的持續(xù)時間有多長,那么也不知道如何保存那些對象达皿。既然如此天吓,怎樣才能知道那些對象要求多少空間呢?事先上根本無法提前知道峦椰,除非進(jìn)入運行期龄寞。

在面向?qū)ο蟮脑O(shè)計中,大多數(shù)問題的解決辦法似乎都有些輕率——只是簡單地創(chuàng)建另一種類型的對象汤功。用于解決特定問題的新型對象容納了指向其他對象的句柄物邑。當(dāng)然,也可以用數(shù)組來做同樣的事情,那是大多數(shù)語言都具有的一種功能色解。但不能只看到這一點茂嗓。這種新對象通常叫作“集合”(亦叫作一個“容器”,但AWT在不同的場合應(yīng)用了這個術(shù)語科阎,所以本書將一直沿用“集合”的稱呼述吸。在需要的時候,集合會自動擴充自己锣笨,以便適應(yīng)我們在其中置入的任何東西蝌矛。所以我們事先不必知道要在一個集合里容下多少東西。只需創(chuàng)建一個集合错英,以后的工作讓它自己負(fù)責(zé)好了入撒。

幸運的是,設(shè)計優(yōu)良的OOP語言都配套提供了一系列集合椭岩。在C++中茅逮,它們是以“標(biāo)準(zhǔn)模板庫”(STL)的形式提供的旺嬉。Object Pascal用自己的“可視組件庫”(VCL)提供集合合陵。Smalltalk提供了一套非常完整的集合。而Java也用自己的標(biāo)準(zhǔn)庫提供了集合良风。在某些庫中姨伟,一個常規(guī)集合便可滿足人們的大多數(shù)要求惩琉;而在另一些庫中(特別是C++的庫),則面向不同的需求提供了不同類型的集合夺荒。例如瞒渠,可以用一個矢量統(tǒng)一對所有元素的訪問方式;一個鏈接列表則用于保證所有元素的插入統(tǒng)一技扼。所以我們能根據(jù)自己的需要選擇適當(dāng)?shù)念愋臀榫痢F渲邪㈥犃薪宋恰⑸⒘斜砬瞎俊洹⒍褩5鹊取?/p>

所有集合都提供了相應(yīng)的讀寫功能丽旅。將某樣?xùn)|西置入集合時椰棘,采用的方式是十分明顯的。有一個叫作“推”(Push)榄笙、“添加”(Add)或其他類似名字的函數(shù)用于做這件事情邪狞。但將數(shù)據(jù)從集合中取出的時候,方式卻并不總是那么明顯茅撞。如果是一個數(shù)組形式的實體帆卓,比如一個矢量(Vector)巨朦,那么也許能用索引運算符或函數(shù)。但在許多情況下剑令,這樣做往往會無功而返糊啡。此外,單選定函數(shù)的功能是非常有限的尚洽。如果想對集合中的一系列元素進(jìn)行操縱或比較悔橄,而不是僅僅面向一個,這時又該怎么辦呢腺毫?

辦法就是使用一個“繼續(xù)器”(Iterator)癣疟,它屬于一種對象,負(fù)責(zé)選擇集合內(nèi)的元素潮酒,并把它們提供給繼承器的用戶睛挚。作為一個類,它也提供了一級抽象急黎。利用這一級抽象扎狱,可將集合細(xì)節(jié)與用于訪問那個集合的代碼隔離開。通過繼承器的作用勃教,集合被抽象成一個簡單的序列淤击。繼承器允許我們遍歷那個序列,同時毋需關(guān)心基礎(chǔ)結(jié)構(gòu)是什么——換言之故源,不管它是一個矢量污抬、一個鏈接列表、一個堆棧绳军,還是其他什么東西印机。這樣一來,我們就可以靈活地改變基礎(chǔ)數(shù)據(jù)门驾,不會對程序里的代碼造成干擾射赛。Java最開始(在1.0和1.1版中)提供的是一個標(biāo)準(zhǔn)繼承器,名為Enumeration(枚舉)奶是,為它的所有集合類提供服務(wù)楣责。Java 1.2新增一個更復(fù)雜的集合庫,其中包含了一個名為Iterator的繼承器聂沙,可以做比老式的Enumeration更多的事情秆麸。

從設(shè)計角度出發(fā),我們需要的是一個全功能的序列逐纬。通過對它的操縱,應(yīng)該能解決自己的問題削樊。如果一種類型的序列即可滿足我們的所有要求豁生,那么完全沒有必要再換用不同的類型兔毒。有兩方面的原因促使我們需要對集合作出選擇。首先甸箱,集合提供了不同的接口類型以及外部行為育叁。堆棧的接口與行為與隊列的不同,而隊列的接口與行為又與一個集(Set)或列表的不同芍殖。利用這個特征豪嗽,我們解決問題時便有更大的靈活性。

其次豌骏,不同的集合在進(jìn)行特定操作時往往有不同的效率龟梦。最好的例子便是矢量(Vector)和列表(List)的區(qū)別。它們都屬于簡單的序列窃躲,擁有完全一致的接口和外部行為计贰。但在執(zhí)行一些特定的任務(wù)時,需要的開銷卻是完全不同的蒂窒。對矢量內(nèi)的元素進(jìn)行的隨機訪問(存仍甑埂)是一種常時操作;無論我們選擇的選擇是什么洒琢,需要的時間量都是相同的秧秉。但在一個鏈接列表中,若想到處移動衰抑,并隨機挑選一個元素象迎,就需付出“慘重”的代價。而且假設(shè)某個元素位于列表較遠(yuǎn)的地方停士,找到它所需的時間也會長許多挖帘。但在另一方面,如果想在序列中部插入一個元素恋技,用列表就比用矢量劃算得多拇舀。這些以及其他操作都有不同的執(zhí)行效率,具體取決于序列的基礎(chǔ)結(jié)構(gòu)是什么蜻底。在設(shè)計階段骄崩,我們可以先從一個列表開始。最后調(diào)整性能的時候薄辅,再根據(jù)情況把它換成矢量要拂。由于抽象是通過繼承器進(jìn)行的,所以能在兩者方便地切換站楚,對代碼的影響則顯得微不足道脱惰。

最后,記住集合只是一個用來放置對象的儲藏所窿春。如果那個儲藏所能滿足我們的所有需要拉一,就完全沒必要關(guān)心它具體是如何實現(xiàn)的(這是大多數(shù)類型對象的一個基本概念)采盒。如果在一個編程環(huán)境中工作,它由于其他因素(比如在Windows下運行蔚润,或者由垃圾收集器帶來了開銷)產(chǎn)生了內(nèi)在的開銷磅氨,那么矢量和鏈接列表之間在系統(tǒng)開銷上的差異就或許不是一個大問題。我們可能只需要一種類型的序列嫡纠。甚至可以想象有一個“完美”的集合抽象烦租,它能根據(jù)自己的使用方式自動改變基層的實現(xiàn)方式。

1.7.2 單根結(jié)構(gòu)

在面向?qū)ο蟮某绦蛟O(shè)計中除盏,由于C++的引入而顯得尤為突出的一個問題是:所有類最終是否都應(yīng)從單獨一個基礎(chǔ)類繼承叉橱。在Java中(與其他幾乎所有OOP語言一樣),對這個問題的答案都是肯定的痴颊,而且這個終級基礎(chǔ)類的名字很簡單赏迟,就是一個“Object”。這種“單根結(jié)構(gòu)”具有許多方面的優(yōu)點蠢棱。

單根結(jié)構(gòu)中的所有對象都有一個通用接口锌杀,所以它們最終都屬于相同的類型。另一種方案(就象C++那樣)是我們不能保證所有東西都屬于相同的基本類型泻仙。從向后兼容的角度看糕再,這一方案可與C模型更好地配合,而且可以認(rèn)為它的限制更少一些玉转。但假期我們想進(jìn)行純粹的面向?qū)ο缶幊掏幌耄敲幢仨殬?gòu)建自己的結(jié)構(gòu),以期獲得與內(nèi)建到其他OOP語言里的同樣的便利究抓。需添加我們要用到的各種新類庫猾担,還要使用另一些不兼容的接口。理所當(dāng)然地刺下,這也需要付出額外的精力使新接口與自己的設(shè)計方案配合(可能還需要多重繼承)绑嘹。為得到C++額外的“靈活性”,付出這樣的代價值得嗎橘茉?當(dāng)然工腋,如果真的需要——如果早已是C專家,如果對C有難舍的情結(jié)——那么就真的很值得畅卓。但假如你是一名新手擅腰,首次接觸這類設(shè)計,象Java那樣的替換方案也許會更省事一些翁潘。

單根結(jié)構(gòu)中的所有對象(比如所有Java對象)都可以保證擁有一些特定的功能趁冈。在自己的系統(tǒng)中,我們知道對每個對象都能進(jìn)行一些基本操作拜马。一個單根結(jié)構(gòu)渗勘,加上所有對象都在內(nèi)存堆中創(chuàng)建矾飞,可以極大簡化參數(shù)的傳遞(這在C++里是一個復(fù)雜的概念)。
利用單根結(jié)構(gòu)呀邢,我們可以更方便地實現(xiàn)一個垃圾收集器。與此有關(guān)的必要支持可安裝于基礎(chǔ)類中豹绪,而垃圾收集器可將適當(dāng)?shù)南l(fā)給系統(tǒng)內(nèi)的任何對象价淌。如果沒有這種單根結(jié)構(gòu),而且系統(tǒng)通過一個句柄來操縱對象瞒津,那么實現(xiàn)垃圾收集器的途徑會有很大的不同蝉衣,而且會面臨許多障礙。

由于運行期的類型信息肯定存在于所有對象中巷蚪,所以永遠(yuǎn)不會遇到判斷不出一個對象的類型的情況病毡。這對系統(tǒng)級的操作來說顯得特別重要,比如違例控制屁柏;而且也能在程序設(shè)計時獲得更大的靈活性啦膜。

但大家也可能產(chǎn)生疑問,既然你把好處說得這么天花亂墜淌喻,為什么C++沒有采用單根結(jié)構(gòu)呢僧家?事實上,這是早期在效率與控制上權(quán)衡的一種結(jié)果裸删。單根結(jié)構(gòu)會帶來程序設(shè)計上的一些限制八拱。而且更重要的是,它加大了新程序與原有C代碼兼容的難度涯塔。盡管這些限制僅在特定的場合會真的造成問題肌稻,但為了獲得最大的靈活程度,C++最終決定放棄采用單根結(jié)構(gòu)這一做法匕荸。而Java不存在上述的問題爹谭,它是全新設(shè)計的一種語言,不必與現(xiàn)有的語言保持所謂的“向后兼容”每聪。所以很自然地旦棉,與其他大多數(shù)面向?qū)ο蟮某绦蛟O(shè)計語言一樣,單根結(jié)構(gòu)在Java的設(shè)計方案中很快就落實下來药薯。

1.7.3 集合庫與方便使用集合

由于集合是我們經(jīng)常都要用到的一種工具绑洛,所以一個集合庫是十分必要的,它應(yīng)該可以方便地重復(fù)使用童本。這樣一來真屯,我們就可以方便地取用各種集合,將其插入自己的程序穷娱。Java提供了這樣的一個庫绑蔫,盡管它在Java 1.0和1.1中都顯得非常有限(Java 1.2的集合庫則無疑是一個杰作)运沦。

1.下溯造型與模板/通用性

為了使這些集合能夠重復(fù)使用,或者“再生”配深,Java提供了一種通用類型携添,以前曾把它叫作“Object”。單根結(jié)構(gòu)意味著篓叶、所有東西歸根結(jié)底都是一個對象”烈掠!所以容納了Object的一個集合實際可以容納任何東西。這使我們對它的重復(fù)使用變得非常簡便缸托。
為使用這樣的一個集合左敌,只需添加指向它的對象句柄即可,以后可以通過句柄重新使用對象俐镐。但由于集合只能容納Object矫限,所以在我們向集合里添加對象句柄時,它會上溯造型成Object佩抹,這樣便丟失了它的身份或者標(biāo)識信息叼风。再次使用它的時候,會得到一個Object句柄棍苹,而非指向我們早先置入的那個類型的句柄咬扇。所以怎樣才能歸還它的本來面貌,調(diào)用早先置入集合的那個對象的有用接口呢廊勃?

在這里懈贺,我們再次用到了造型(Cast)。但這一次不是在分級結(jié)構(gòu)中上溯造型成一種更“通用”的類型坡垫。而是下溯造型成一種更“特殊”的類型梭灿。這種造型方法叫作“下溯造型”(Downcasting)。舉個例子來說冰悠,我們知道在上溯造型的時候堡妒,Circle(圓)屬于Shape(幾何形狀)的一種類型,所以上溯造型是安全的溉卓。但我們不知道一個Object到底是Circle還是Shape皮迟,所以很難保證下溯造型的安全進(jìn)行,除非確切地知道自己要操作的是什么桑寨。

但這也不是絕對危險的伏尼,因為假如下溯造型成錯誤的東西,會得到我們稱為“違例”(Exception)的一種運行期錯誤尉尾。我們稍后即會對此進(jìn)行解釋爆阶。但在從一個集合提取對象句柄時,必須用某種方式準(zhǔn)確地記住它們是什么,以保證下溯造型的正確進(jìn)行辨图。
下溯造型和運行期檢查都要求花額外的時間來運行程序班套,而且程序員必須付出額外的精力。既然如此故河,我們能不能創(chuàng)建一個“智能”集合吱韭,令其知道自己容納的類型呢?這樣做可消除下溯造型的必要以及潛在的錯誤鱼的。答案是肯定的杉女,我們可以采用“參數(shù)化類型”,它們是編譯器能自動定制的類鸳吸,可與特定的類型配合。例如速勇,通過使用一個參數(shù)化集合晌砾,編譯器可對那個集合進(jìn)行定制,使其只接受Shape烦磁,而且只提取Shape养匈。

參數(shù)化類型是C++一個重要的組成部分,這部分是C++沒有單根結(jié)構(gòu)的緣故都伪。在C++中呕乎,用于實現(xiàn)參數(shù)化類型的關(guān)鍵字是template(模板)。Java目前尚未提供參數(shù)化類型陨晶,因為由于使用的是單根結(jié)構(gòu)猬仁,所以使用它顯得有些笨拙。但這并不能保證以后的版本不會實現(xiàn)先誉,因為“generic”這個詞已被Java“保留到將來實現(xiàn)”(在Ada語言中湿刽,“generic”被用來實現(xiàn)它的模板)。Java采取的這種關(guān)鍵字保留機制其實經(jīng)常讓人摸不著頭腦褐耳,很難斷定以后會發(fā)生什么事情诈闺。

1.7.4 清除時的困境:由誰負(fù)責(zé)清除?

每個對象都要求資源才能“生存”铃芦,其中最令人注目的資源是內(nèi)存雅镊。如果不再需要使用一個對象,就必須將其清除刃滓,以便釋放這些資源仁烹,以便其他對象使用。如果要解決的是非常簡單的問題咧虎,如何清除對象這個問題并不顯得很突出:我們創(chuàng)建對象晃危,在需要的時候調(diào)用它,然后將其清除或者“破壞”。但在另一方面僚饭,我們平時遇到的問題往往要比這復(fù)雜得多震叮。
舉個例子來說,假設(shè)我們要設(shè)計一套系統(tǒng)鳍鸵,用它管理一個機場的空中交通(同樣的模型也可能適于管理一個倉庫的貨柜苇瓣、或者一套影帶出租系統(tǒng)、或者寵物店的寵物房偿乖。這初看似乎十分簡單:構(gòu)造一個集合用來容納飛機,然后創(chuàng)建一架新飛機贪薪,將其置入集合媳禁。對進(jìn)入空中交通管制區(qū)的所有飛機都如此處理。至于清除画切,在一架飛機離開這個區(qū)域的時候把它簡單地刪去即可竣稽。
但事情并沒有這么簡單,可能還需要另一套系統(tǒng)來記錄與飛機有關(guān)的數(shù)據(jù)霍弹。當(dāng)然毫别,和控制器的主要功能不同,這些數(shù)據(jù)的重要性可能一開始并不顯露出來典格。例如岛宦,這條記錄反映的可能是離開機場的所有小飛機的飛行計劃。所以我們得到了由小飛機組成的另一個集合耍缴。一旦創(chuàng)建了一個飛機對象砾肺,如果它是一架小飛機,那么也必須把它置入這個集合防嗡。然后在系統(tǒng)空閑時期债沮,需對這個集合中的對象進(jìn)行一些后臺處理。

問題現(xiàn)在顯得更復(fù)雜了:如何才能知道什么時間刪除對象呢本鸣?用完對象后疫衩,系統(tǒng)的其他某些部分可能仍然要發(fā)揮作用。同樣的問題也會在其他大量場合出現(xiàn)荣德,而且在程序設(shè)計系統(tǒng)中(如C++)闷煤,在用完一個對象之后必須明確地將其刪除,所以問題會變得異常復(fù)雜(注釋⑥)涮瞻。

⑥:注意這一點只對內(nèi)存堆里創(chuàng)建的對象成立(用new命令創(chuàng)建的)鲤拿。但在另一方面,對這兒描述的問題以及其他所有常見的編程問題來說署咽,都要求對象在內(nèi)存堆里創(chuàng)建近顷。

在Java中生音,垃圾收集器在設(shè)計時已考慮到了內(nèi)存的釋放問題(盡管這并不包括清除一個對象涉及到的其他方面)。垃圾收集器“知道”一個對象在什么時候不再使用窒升,然后會自動釋放那個對象占據(jù)的內(nèi)存空間缀遍。采用這種方式,另外加上所有對象都從單個根類Object繼承的事實饱须,而且由于我們只能在內(nèi)存堆中以一種方式創(chuàng)建對象域醇,所以Java的編程要比C++的編程簡單得多。我們只需要作出少量的抉擇蓉媳,即可克服原先存在的大量障礙譬挚。

2.垃圾收集器對效率及靈活性的影響

既然這是如此好的一種手段,為什么在C++里沒有得到充分的發(fā)揮呢酪呻?我們當(dāng)然要為這種編程的方便性付出一定的代價减宣,代價就是運行期的開銷。正如早先提到的那樣玩荠,在C++中漆腌,我們可在堆棧中創(chuàng)建對象。在這種情況下姨蟋,對象會得以自動清除(但不具有在運行期間隨心所欲創(chuàng)建對象的靈活性)。在堆棧中創(chuàng)建對象是為對象分配存儲空間最有效的一種方式立帖,也是釋放那些空間最有效的一種方式眼溶。在內(nèi)存堆(Heap)中創(chuàng)建對象可能要付出昂貴得多的代價。如果總是從同一個基礎(chǔ)類繼承晓勇,并使所有函數(shù)調(diào)用都具有“同質(zhì)多形”特征堂飞,那么也不可避免地需要付出一定的代價。但垃圾收集器是一種特殊的問題绑咱,因為我們永遠(yuǎn)不能確定它什么時候啟動或者要花多長的時間绰筛。這意味著在Java程序執(zhí)行期間,存在著一種不連貫的因素描融。所以在某些特殊的場合铝噩,我們必須避免用它——比如在一個程序的執(zhí)行必須保持穩(wěn)定、連貫的時候(通常把它們叫作“實時程序”窿克,盡管并不是所有實時編程問題都要這方面的要求——注釋⑦)骏庸。

⑦:根據(jù)本書一些技術(shù)性讀者的反饋,有一個現(xiàn)成的實時Java系統(tǒng)(www.newmonics.com)確實能夠保證垃圾收集器的效能年叮。

C++語言的設(shè)計者曾經(jīng)向C程序員發(fā)出請求(而且做得非常成功)具被,不要希望在可以使用C的任何地方,向語言里加入可能對C++的速度或使用造成影響的任何特性只损。這個目的達(dá)到了一姿,但代價就是C++的編程不可避免地復(fù)雜起來。Java比C++簡單,但付出的代價是效率以及一定程度的靈活性叮叹。但對大多數(shù)程序設(shè)計問題來說艾栋,Java無疑都應(yīng)是我們的首選。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衬横,一起剝皮案震驚了整個濱河市裹粤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蜂林,老刑警劉巖遥诉,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異噪叙,居然都是意外死亡矮锈,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進(jìn)店門睁蕾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苞笨,“玉大人,你說我怎么就攤上這事子眶∑倌” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵臭杰,是天一觀的道長粤咪。 經(jīng)常有香客問我,道長渴杆,這世上最難降的妖魔是什么寥枝? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮磁奖,結(jié)果婚禮上囊拜,老公的妹妹穿的比我還像新娘。我一直安慰自己比搭,他們只是感情好冠跷,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著身诺,像睡著了一般蔽莱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上戚长,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天盗冷,我揣著相機與錄音,去河邊找鬼同廉。 笑死仪糖,一個胖子當(dāng)著我的面吹牛柑司,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播锅劝,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼攒驰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了故爵?” 一聲冷哼從身側(cè)響起玻粪,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎诬垂,沒想到半個月后劲室,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡结窘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年很洋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片隧枫。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡喉磁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出官脓,到底是詐尸還是另有隱情协怒,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布卑笨,位于F島的核電站孕暇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏湾趾。R本人自食惡果不足惜芭商,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一派草、第九天 我趴在偏房一處隱蔽的房頂上張望搀缠。 院中可真熱鬧,春花似錦近迁、人聲如沸艺普。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽歧譬。三九已至,卻和暖如春搏存,著一層夾襖步出監(jiān)牢的瞬間瑰步,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工璧眠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缩焦,地道東北人读虏。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像袁滥,于是被迫代替她去往敵國和親盖桥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,111評論 1 32
  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡(luò)上收集的一些資料的整理题翻,因此不免有一些不準(zhǔn)確的地方揩徊,同時不同JDK版本的...
    高廣超閱讀 15,628評論 3 83
  • 五、Java 虛擬機 一嵌赠、什么是Java虛擬機Java虛擬機是一個想象中的機器,在實際的計算機上通過軟件模擬來實現(xiàn)...
    壹點零閱讀 740評論 0 0
  • 《深入理解Java虛擬機》筆記_第一遍 先取看完這本書(JVM)后必須掌握的部分塑荒。 第一部分 走近 Java 從傳...
    xiaogmail閱讀 5,108評論 1 34
  • Lua 5.1 參考手冊 by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,835評論 0 38