




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第3章Go語言面向?qū)ο缶幊堂嫦驅(qū)ο蟮母拍?1類與對象1.類2.對象類與對象1.類現(xiàn)實(shí)世界中的各種事物都可以分類,例如,星球、動物、房子、學(xué)生、汽車等。類包含屬性、方法和事件,通過屬性表示它的特征(數(shù)據(jù)),通過方法實(shí)現(xiàn)它的行為(功能),通過事件做出響應(yīng)。類可以派生出子類(派生類),派生子類的類稱為父類。對于一個(gè)系統(tǒng)來說,其最基本的類稱為基類,由基類派生出多個(gè)類,這些類還可以繼續(xù)派生出更多的子類,形成類的層次結(jié)構(gòu)。例如:基類——汽車子類:卡車、轎車、客車等汽車類屬性:車輪、方向盤、發(fā)動機(jī)、車門等汽車類方法:前進(jìn)、倒退、剎車、轉(zhuǎn)彎、聽音樂、導(dǎo)航等汽車類事件:車胎漏氣、油用到臨界、遇到碰撞等類與對象2.對象對象是類的具體化,是具有屬性和方法的實(shí)體(實(shí)例)。對象通過唯一的標(biāo)識名區(qū)別于其他對象。對象通常還有固定的對外接口,它是對象與外界通信的通道。例如,汽車類派生出的轎車子類的對象有:比亞迪F6、奧迪A6L等。02面向?qū)ο缶幊堂嫦驅(qū)ο缶幊堂嫦驅(qū)ο缶幊蹋∣bject-OrientedProgramming,簡稱OOP)是一種基于類和對象的程序設(shè)計(jì)方法。它將需要解決的問題抽象成一個(gè)個(gè)能以計(jì)算機(jī)邏輯形式表現(xiàn)的封裝實(shí)體,即對象,類是在對象之上的抽象,通過定義屬性和方法來描述其特征和職責(zé)。類為屬于它的全部對象提供了統(tǒng)一的抽象描述,可看作是一種抽象的數(shù)據(jù)類型,是對象的模板;對象則是類的具體化,是類的實(shí)例,用接口來描述對象的地位以及對象實(shí)例之間的關(guān)系。由此構(gòu)成面向?qū)ο蟮母拍钅P腿鐖D,它能更好地反映現(xiàn)實(shí)世界,對事物的描述更加自然,使問題的解決更容易。面向?qū)ο缶幊淘诿嫦驅(qū)ο蟪绦蛟O(shè)計(jì)中,數(shù)據(jù)結(jié)構(gòu)與作用于其上的算法被視為了一個(gè)整體,即為對象,而現(xiàn)實(shí)世界中任何類的對象都具有一定的屬性和方法,可以用數(shù)據(jù)結(jié)構(gòu)與算法二者分別加以描述,所以可用下面的等式來定義面向?qū)ο蟪绦颍簩ο?數(shù)據(jù)結(jié)構(gòu)+算法程序=對象+對象+…03面向?qū)ο笳Z言的特征1.封裝2.繼承3.多態(tài)面向?qū)ο笳Z言的特征1.封裝所謂“封裝”,也就是用一個(gè)框架把數(shù)據(jù)和代碼組合在一起,形成對象。封裝的對象之間通過一種稱為“消息傳遞”的機(jī)制進(jìn)行通信。消息是向?qū)ο蟀l(fā)出的服務(wù)請求,它包含要求接收對象(接收者)去執(zhí)行某些活動的信息,以及完成要求所需的其他信息(參數(shù))。發(fā)送消息的對象(發(fā)送者)不需要知道接收者如何對請求予以響應(yīng),接收者收到消息,它就承擔(dān)了執(zhí)行指定動作的責(zé)任,通過執(zhí)行自身內(nèi)部封裝的某個(gè)方法來滿足發(fā)送者的請求,并作出答復(fù)。面向?qū)ο笳Z言的特征2.繼承世界本質(zhì)是復(fù)雜的,但在大千世界中事物之間又有很多相似之處,而這種相似性正是人們理解紛繁事物的一個(gè)基礎(chǔ)。相似的事物之間往往具有某種“繼承”關(guān)系,比如,兒子長得像父親,是因?yàn)閮鹤拥幕蚶^承了父親的許多遺傳特性;卡車、轎車、客車存在相似性,是因?yàn)樗鼈兌紝儆谄?,繼承了汽車的一般特征。“繼承”是面向?qū)ο蠓椒ǖ囊粔K基石,通過它可以建立起具有等級層次的類的體系。例如,先創(chuàng)建一個(gè)通用的汽車類,定義汽車的一般屬性(車輪、方向盤、發(fā)動機(jī)、車門等)和操作方法(前進(jìn)、倒退、剎車、轉(zhuǎn)彎等),再從這個(gè)已有的類出發(fā),用繼承的方式派生出新的子類,如卡車、轎車、客車等,見圖。它們都是比汽車類更具體的類,每個(gè)具體的類都可以增加自己特有的一些屬性和方法。在面向?qū)ο笙到y(tǒng)設(shè)計(jì)中,繼承關(guān)系更一般的表示如圖。面向?qū)ο笳Z言的特征另外,繼承也是父類與子類之間共享數(shù)據(jù)和方法的一個(gè)重要途徑。如果一個(gè)類有兩個(gè)或以上的直接父類,這樣的繼承結(jié)構(gòu)稱為多重繼承或多繼承?,F(xiàn)實(shí)中這種模型也屢見不鮮,如一些類似于沙發(fā)床的組合功能產(chǎn)品,既有沙發(fā)的功能,又有床的功能,應(yīng)當(dāng)允許它同時(shí)繼承自沙發(fā)和床這兩個(gè)類,如圖。多繼承更一般的表示見圖。面向?qū)ο笳Z言的特征3.多態(tài)多態(tài)是指同一個(gè)消息或操作在作用于不同對象時(shí),可以有不同的反應(yīng),產(chǎn)生不同的行為和結(jié)果。舉個(gè)例子:春秋時(shí)期,孔子率眾弟子周游列國因其“仁”的主張得不到采納而被各國驅(qū)逐出境,有一次在荒野里餓得走不動了,于是問他的弟子為何會落到這步田地“匪兕匪虎,率彼曠野。吾道非耶,吾何為于此?”子路以為“是不是由于我們沒有仁德和智謀,所以人們不采納我們的主張?”子貢認(rèn)為“先生的道(理想)大到了極點(diǎn)以致天下人所不容,倒不如降低自己的理想以求安身?!鳖伝貏t堅(jiān)持“即使天下人都不容我們,但只要理想是正確的,不被世人接納也沒關(guān)系,走自己的路方顯君子本色!”
——見《史記·孔子世家》陳蔡之厄的典故第3章Go語言面向?qū)ο缶幊堂嫦驅(qū)ο笤贕o中的實(shí)現(xiàn)01封裝的實(shí)現(xiàn)1.屬性2.方法3.屬性訪問4.對象創(chuàng)建封裝的實(shí)現(xiàn)1.屬性Go語言并沒有用于表示類的class關(guān)鍵字,但可以使用結(jié)構(gòu)體(struct)實(shí)現(xiàn)對屬性的封裝,形式為:type類名struct{
屬性1類型1
屬性2類型2 ...
屬性n類型n}例如,定義一個(gè)人類Human,包括姓名、身高、體重、年齡4個(gè)屬性,如下:typeHumanstruct{ namestring heightfloat32 weightfloat32 ageint}封裝的實(shí)現(xiàn)2.方法Go類的方法不像其他面向?qū)ο笳Z言那樣寫在類體內(nèi)部,而是一個(gè)以指針作用于類上的外部函數(shù),形如:func(指針名*類名)方法名([形參列表])[(返回值列表)]{
方法體 [return[值列表]]}例如,給人類Human定義一個(gè)計(jì)算BMI(BodyMassIndex,身體質(zhì)量指數(shù))的方法bmiCal,如下:func(h*Human)bmiCal()float32{ returnh.weight/(h.height*h.height)}封裝的實(shí)現(xiàn)3.屬性訪問在面向?qū)ο蟮木幊谭绞较?,外部程序通常不建議直接訪問類內(nèi)部的屬性,而是通過類提供的一對get/set方法來獲取和設(shè)置屬性值,即所謂的通過“模型(值對象)”操作數(shù)據(jù),很多持久化框架也是基于這樣的規(guī)范來編寫程序的。Go類的get/set方法的定義方式與普通方法一樣,但建議將它們分別命名為getXxx、setXxx(其中Xxx為屬性名,首字母大寫)。例如,定義一對獲取與設(shè)置人類體重的get/set方法,如下://get方法func(h*Human)getWeight()float32{ returnh.weight //獲取體重}//set方法func(h*Human)setWeight(weightfloat32){ h.weight=weight //設(shè)置體重}這樣在程序中就可以通過這對方法來設(shè)置和獲取一個(gè)人的體重值,如下:man:=Human{} //創(chuàng)建人類的對象(一個(gè)人)man.setWeight(60) //設(shè)置他(她)的體重fmt.Println(man.getWeight()) //60封裝的實(shí)現(xiàn)4.對象創(chuàng)建創(chuàng)建類的對象,通常有如下幾種寫法:對象名:=類名{}對象名:=new(類名)var對象名類名=類名{}在創(chuàng)建對象后,再通過定義好的一系列set方法給對象的各屬性賦初值,形如:對象名.setXxx1(屬性1值)對象名.setXxx2(屬性2值)...對象名.setXxxn(屬性n值)當(dāng)然,也可以在創(chuàng)建對象的同時(shí)就初始化其各個(gè)屬性的值,比如只寫一句:對象名:=類名{屬性1值,屬性2值,...,屬性n值}封裝的實(shí)現(xiàn)【實(shí)例3.1】用面向?qū)ο蠓椒ǚ庋b一個(gè)人的身高、體重等屬性,并計(jì)算其BMI值。程序代碼如下(human.go):運(yùn)行結(jié)果如圖。02繼承的實(shí)現(xiàn)繼承的實(shí)現(xiàn)Go語言沒有用于聲明繼承關(guān)系的extends關(guān)鍵字,而是采用在結(jié)構(gòu)體中內(nèi)嵌類型的方式來實(shí)現(xiàn)繼承,即讓子類包含其父類名稱的屬性,形式如下:type父類名struct{
屬性1類型1
屬性2類型2 ...
屬性n類型n}
type子類名struct{
父類名
屬性n+1類型n+1
屬性n+2類型n+2 ...
屬性n+n類型n+n}這樣繼承父類后,子類不僅自動“擁有”父類原來的所有屬性(屬性1~屬性n),還可以增加定義一些自己特有的屬性(如上面的屬性n+1~屬性n+n),同時(shí),原來定義在父類上的方法也會自動屬于子類,當(dāng)然也可以另外增加定義一些子類所特有的方法。繼承的實(shí)現(xiàn)【實(shí)例3.2】定義一個(gè)動物類Animal作為父類,人類Human作為子類繼承動物類的屬性,并增加一個(gè)物種(species)屬性,然后輸出一個(gè)具體的人的信息。程序代碼如下(animal.go):運(yùn)行結(jié)果如圖。03多態(tài)的實(shí)現(xiàn)1.定義接口2.實(shí)現(xiàn)方法3.動態(tài)綁定多態(tài)的實(shí)現(xiàn)1.定義接口先定義一個(gè)接口,里面聲明(羅列出)需要實(shí)現(xiàn)多態(tài)的一系列方法:type接口名interface{
方法名1()類型1
方法名2()類型2 ...
方法名n()類型n}多態(tài)的實(shí)現(xiàn)//第1個(gè)類對接口中方法的實(shí)現(xiàn)func(指針名*類名1)方法名1()類型1{ ...//方法體}func(指針名*類名1)方法名2()類型2{ ...//方法體}...func(指針名*類名1)方法名n()類型n{ ...//方法體}
//第2個(gè)類對接口中方法的實(shí)現(xiàn)func(指針名*類名2)方法名1()類型1{ ...//方法體}func(指針名*類名2)方法名2()類型2{ ...//方法體}...func(指針名*類名2)方法名n()類型n{ ...//方法體}2.實(shí)現(xiàn)方法接口僅提供方法聲明,并未有方法實(shí)現(xiàn),具體的實(shí)現(xiàn)則留給各個(gè)類自己去完成,這里假設(shè)有兩個(gè)類,分別獨(dú)立實(shí)現(xiàn)上面接口中的方法如下:多態(tài)的實(shí)現(xiàn)3.動態(tài)綁定編程時(shí),可聲明一個(gè)接口類型的變量,將不同對象實(shí)例的引用(地址)賦給它,運(yùn)行時(shí)就會動態(tài)綁定到相應(yīng)的類上,執(zhí)行其所實(shí)現(xiàn)的方法,如下:var變量名接口名變量名=&類名1{...} //給變量賦第1個(gè)類的對象實(shí)例變量名.方法名i() //執(zhí)行第1個(gè)類所實(shí)現(xiàn)的方法i變量名=&類名2{...} //給變量賦第2個(gè)類的對象實(shí)例變量名.方法名i() //執(zhí)行第2個(gè)類所實(shí)現(xiàn)的方法i多態(tài)的實(shí)現(xiàn)【實(shí)例3.3】運(yùn)用多態(tài)分別判斷一個(gè)人和一只大熊貓是否成年。背景知識:對于一個(gè)人而言,滿18周歲才算成年,熊貓則不然,由于熊貓的生理發(fā)育進(jìn)程比人類快得多(大約在3倍以上),四五歲就已性成熟,而一般超過20歲的大熊貓就被認(rèn)為是老年熊貓。大熊貓的年齡和人類的年齡可以用以下公式來大致?lián)Q算:
大熊貓年齡≈3.5×人類年齡+1.5實(shí)現(xiàn)思路:本例先定義一個(gè)父類Animal(動物類),再定義兩個(gè)子類Human(人類)和Panda(熊貓類)繼承自Animal類。(1)定義一個(gè)Adult(成年)接口,其中有獲取姓名和年齡的getName和getAge方法,獲取物種名的getSpecies方法,還有判斷對象是否成年的isAdult方法。(2)由父類Animal實(shí)現(xiàn)接口的getName和getAge方法,這兩個(gè)方法是公共的,僅有唯一的實(shí)現(xiàn),Human和Panda類都可以繼承使用。多態(tài)的實(shí)現(xiàn)(3)Human和Panda類分別實(shí)現(xiàn)各自的getSpecies和isAdult方法,獲取自身所屬的物種名,并以不同的算法來判斷自己的類對象是否成年,實(shí)現(xiàn)多態(tài)。程序代碼如下(adult.go):運(yùn)行結(jié)果如圖。第3章Go語言面向?qū)ο缶幊填惻c方法01用結(jié)構(gòu)體定義類1.命名與未命名類型2.自定義命名類型3.基于結(jié)構(gòu)體定義的類4.基于類定義的類用結(jié)構(gòu)體定義類1.命名與未命名類型在Go語言中,數(shù)據(jù)類型分為命名與未命名兩種。(1)命名類型所有基本數(shù)據(jù)類型,包括整型、浮點(diǎn)型、復(fù)數(shù)型、布爾型、字符串型等都是命名類型,之所以叫“命名類型”是因?yàn)?,基本?shù)據(jù)類型的保留字就唯一確定了這個(gè)類型本身,比如,兩個(gè)整型變量“varaint”與“varbint”,它們的類型完全相同并無任何差異,其保留字名int也就是類型名。除了Go內(nèi)置的基本數(shù)據(jù)類型之外,用戶自定義的類型也是命名類型,例如,自定義的類:typeHumanstruct{ ...}(2)未命名類型反之,那些沒有固定名稱來唯一確定其類型的則是未命名類型。用結(jié)構(gòu)體定義類2.自定義命名類型Go的對象系統(tǒng)是基于用戶自定義類型構(gòu)建起來的,自定義類型使用關(guān)鍵字type,基本語法格式為:type類型名已有類型其中,“類型名”是自定義類型的名稱,由用戶任取,只要符合Go的標(biāo)識符命名規(guī)范就行;“已有類型”可以是Go語言的基本數(shù)據(jù)類型、任何型態(tài)的復(fù)合數(shù)據(jù)類型,當(dāng)然也可以是另一個(gè)自定義類型。顯然,自定義類型有其確定的類型名,是“命名類型”。例如:typeMyFloatfloat32 //基于基本數(shù)據(jù)類型float32定義的類型typeINTint //基于基本數(shù)據(jù)類型int定義的類型typep_INT*int //基于整型指針定義的類型types_INT[]int //基于整型切片定義的類型typecircleAreafunc(float32)float32 //基于函數(shù)(函數(shù)簽名)定義的類型用結(jié)構(gòu)體定義類3.基于結(jié)構(gòu)體定義的類Go語言的結(jié)構(gòu)體(struct)是一種由一系列相同或不同類型的數(shù)據(jù)組合而成的集合,其中每個(gè)數(shù)據(jù)項(xiàng)稱為該結(jié)構(gòu)體的“成員”,各成員可以是基本類型也可以是復(fù)合類型的數(shù)據(jù),甚至還可以是另一個(gè)結(jié)構(gòu)體。顯然,結(jié)構(gòu)體是一種“未命名”的復(fù)合數(shù)據(jù)類型,可以基于它用以上方法定義出一個(gè)個(gè)命名的數(shù)據(jù)類型來,形式如下:type類型名struct{
字段1類型1
字段2類型2 ...
字段n類型n}用結(jié)構(gòu)體定義類其中,結(jié)構(gòu)體的每個(gè)成員對應(yīng)于所定義類型中的一個(gè)字段,每個(gè)字段都擁有自己的類型,且同一個(gè)結(jié)構(gòu)體類型定義中不能有相同的字段名,字段的類型可以相同也可以不同,如果幾個(gè)字段的類型相同,也可以將它們寫在同一行,形如:type類型名struct{
字段1類型1 ...
字段i,字段i+1,...,字段i+k類型i ...}將以上定義中的“類型名”作為“類名”、“字段”作為“屬性”,就得到了之前所講的面向?qū)ο蠓庋b中類的定義:type類名struct{
屬性1類型1
屬性2類型2 ...
屬性n類型n}用結(jié)構(gòu)體定義類4.基于類定義的類既然類本質(zhì)上是一種類型(自定義的命名類型),當(dāng)然也可以基于已有類定義出新類,使用語句:type新類名已有類名但要注意:用這種方式定義的類是一個(gè)新的命名類型,它與原有類之間并不存在繼承關(guān)系,也不會繼承原有類的方法?!緦?shí)例3.4】證明“白馬非馬”。背景知識:“白馬非馬”是戰(zhàn)國時(shí)思想家、名家代表人物公孫龍(前320~前250年)所提出的一個(gè)著名的命題。相傳有一次公孫龍牽一匹白馬出關(guān),被守關(guān)士兵攔下告知“國君有令嚴(yán)禁馬匹出關(guān)!”公孫龍說“國君只說不讓馬出關(guān),而我牽的這匹是白馬,白馬與馬是不同的……”一番長篇大論,有理有據(jù),駁得士兵啞口無言,只得放行。
——詳見《公孫龍子·白馬論》用結(jié)構(gòu)體定義類讀者可能會奇怪:白馬難道不是馬么?公孫龍究竟是用什么樣的理由說服守關(guān)的士兵放行的,看了下面的程序大家就會明白其中道理了。程序代碼如下(horse.go):說明:(a)語句fmt.Println(whitehorse.isHorse())執(zhí)行輸出錯(cuò)誤信息:whitehorse.isHorseundefined(typeWhiteHorsehasnofieldormethodisHorse)。這說明白馬確實(shí)“非馬”。(b)語句fmt.Println(yellowhorse.isHorse())執(zhí)行輸出錯(cuò)誤信息:yellowhorse.isHorseundefined(typeYellowHorsehasnofieldormethodisHorse)。黃馬也“非馬”。在注釋掉以上兩句代碼后,運(yùn)行結(jié)果如圖。02類的初始化1.按屬性順序2.指定屬性名3.使用new函數(shù)類的初始化1.按屬性順序此方式將類的各個(gè)屬性值按照定義時(shí)所聲明的順序依次羅列在一對大括號“{}”內(nèi),有3種不同寫法,如下://寫法1h1:=Human{"王林",1.75,65,19}
//寫法2h2:=Human{ "Tom", 1.83, 81.5, 18, //加上英文逗號}
//寫法3h3:=Human{ "王燕", 1.66, 49, 20}類的初始化2.指定屬性名此方式顯式地指定需要初始化的屬性名及其值(中間以冒號“:”分隔),也有3種寫法://寫法1h1:=Human{name:"王林",height:1.75,weight:65,age:19}
//寫法2h2:=Human{ name:"Tom", height:1.83, weight:81.5, age:18, //加上英文逗號}
//寫法3h3:=Human{ name:"王燕", height:1.66, weight:49, age:20}同樣地,如果結(jié)尾的“}”獨(dú)占一行,最后的屬性值后面也要加逗號。類的初始化這種方式的好處是寫法比較靈活,可以不必嚴(yán)格按照類定義的屬性順序賦值,也可以省略一些屬性(由系統(tǒng)自動初始化為其類型的零值),另外,當(dāng)修改了類的定義(如增加屬性)時(shí),只須對增加的屬性單獨(dú)賦值,而原來的初始化代碼段不用做任何修改,例如:3.使用new函數(shù)new是Go系統(tǒng)的內(nèi)置函數(shù),它一次性將類的所有屬性都初始化為各自類型的零值,并返回一個(gè)指向類體(結(jié)構(gòu)體)的指針,如下:h3:=new(Human)fmt.Println(h3) //&{000}03類的方法1.方法的本質(zhì)2.方法調(diào)用類的方法1.方法的本質(zhì)方法是一種對類行為的封裝,將3.2.1節(jié)方法定義與2.7.1節(jié)函數(shù)定義的語法格式放在一起加以比較,如下。方法定義:func(指針名*類名)方法名([形參列表])[(返回值列表)]{
方法體 [return[值列表]]}函數(shù)定義:func函數(shù)名([參數(shù)列表])[(返回值列表)]{
函數(shù)體 [return[值列表]]}類的方法如果將方法定義語法中的“方法名”看作是一個(gè)特殊的參數(shù)(其類型為指向類名的指針)并與后面的“形參列表”合并為一個(gè)完整的“參數(shù)列表”,那么方法本質(zhì)上其實(shí)就是一個(gè)函數(shù),只不過它顯式地指定將類對象的指針作為自己的第一個(gè)參數(shù)而已,這個(gè)參數(shù)在Go語言中又被稱為方法的“接收者”,這樣一來,方法定義的語法也就可以改寫為函數(shù)定義的形式,如下:func函數(shù)名(接收者名接收類型[,其他參數(shù)列表])[(返回值列表)]{
函數(shù)(方法)體 [return[值列表]]}類的方法【實(shí)例3.5】將前面【實(shí)例3.1】人類Human計(jì)算BMI的方法改寫為一個(gè)函數(shù),實(shí)現(xiàn)同樣的計(jì)算功能。程序代碼如下(method01.go):運(yùn)行結(jié)果如圖。方法的“接收者”除了是指針類型外,還可以是值類型,如將上例中計(jì)算BMI的函數(shù)寫成如下:funcbmiCal(hHuman)float32{ //接收者為值類型 returnh.weight/(h.height*h.height)}然后在調(diào)用函數(shù)時(shí)將傳入的實(shí)參由引用改為類對象的變量值:fmt.Println(man.getName(),"BMI指數(shù)是",bmiCal(man))類的方法2.方法調(diào)用可通過兩種方式調(diào)用類的方法,如下。(1)方法值調(diào)用這是最普通的方式,調(diào)用格式為:對象名.方法名([實(shí)參列表])或者(對象名).方法名([實(shí)參列表])值調(diào)用返回的是一個(gè)值類型的變量,可以直接在程序中使用,如打印輸出或賦值給其他變量。類的方法(2)方法表達(dá)式這種方式實(shí)際是將類的方法轉(zhuǎn)換為函數(shù),再通過調(diào)用函數(shù)來執(zhí)行方法。剛剛已揭示了方法的本質(zhì)其實(shí)就是函數(shù),既然如此,可以用“類名”與“方法名”所構(gòu)成的表達(dá)式來唯一地確定一個(gè)等價(jià)函數(shù),這個(gè)表達(dá)式又稱為“方法表達(dá)式”。根據(jù)方法“接收者”類型的不同,方法表達(dá)式有兩種書寫格式,如下。①當(dāng)“接收者”為值類型時(shí),方法表達(dá)式寫為:類名.方法名②當(dāng)“接收者”為指針類型時(shí),方法表達(dá)式寫為:(*類名).方法名 //注意這里的括號不能省略類的方法【實(shí)例3.6】分別用上述兩種方式調(diào)用方法,計(jì)算圓面積和周長。程序代碼如下(method02.go):運(yùn)行結(jié)果如圖。04類的嵌套和方法覆蓋1.內(nèi)嵌屬性的訪問2.內(nèi)嵌方法的覆蓋類的嵌套和方法覆蓋1.內(nèi)嵌屬性的訪問用點(diǎn)操作符“.”訪問內(nèi)嵌屬性,當(dāng)有n層類的嵌套時(shí),可使用全路徑進(jìn)行訪問,形如“對象名.類名1.類名2....類名n.屬性”,但是,如果屬性在其整個(gè)路徑的嵌套結(jié)構(gòu)中是唯一的,就不需要寫出全路徑,簡寫為“對象名.屬性”即可。例如,定義A、B、C三個(gè)類:typeAstruct{ astring bstring}
typeBstruct{ A bstring}
typeCstruct{ B bstring cstring}類的嵌套和方法覆蓋分別創(chuàng)建它們的對象實(shí)例并初始化如下:objA:=A{ a:"I'mA.", b:"It'sA'sb."}objB:=B{ A:objA, b:"I'mB."}objC:=C{ B:objB, b:"It'sC'sb.", c:"I'mC.",}類的嵌套和方法覆蓋由于只有基類A具有a屬性,故objC.a、objC.B.a、objC.B.A.a、objB.A.a、objB.a都指的是A類的a,輸出測試如下:fmt.Println(objC.a) //I'mA.fmt.Println(objC.B.a) //I'mA.fmt.Println(objC.B.A.a) //I'mA.fmt.Println(objB.A.a) //I'mA.fmt.Println(objB.a) //I'mA.但是,因?yàn)檫@三個(gè)類皆有b屬性,所以objC.b、objC.B.b、objC.B.A.b是不同類的b,訪問時(shí)必須寫出全路徑而不能簡寫,輸出測試如下:fmt.Println(objC.a) //I'mA.fmt.Println(objC.B.a) //I'mA.fmt.Println(objC.B.A.a) //I'mA.fmt.Println(objB.A.a) //I'mA.fmt.Println(objB.a) //I'mA.fmt.Println(objC.b) //It'sC'sb.fmt.Println(objC.B.b) //I'mB.fmt.Println(objC.B.A.b) //It'sA'sb.類的嵌套和方法覆蓋2.內(nèi)嵌方法的覆蓋內(nèi)嵌方法調(diào)用也使用點(diǎn)操作符“.”,外層對象調(diào)用內(nèi)嵌類的方法時(shí)也可以像訪問內(nèi)嵌屬性一樣使用全路徑或簡寫,當(dāng)采用簡寫形式時(shí),Go編譯器會從外向內(nèi)逐層查找,如果外層類與內(nèi)嵌類有相同的方法,優(yōu)先調(diào)用最外層的方法,從而實(shí)現(xiàn)子類方法對父類方法的覆蓋。比如,對上面的A、B、C三個(gè)類,分別定義如下同名的方法:func(tA)say(){ //A類的say方法 fmt.Println("Hi!",t.a)}
func(tB)say(){ //B類的say方法 fmt.Println("Hi!",t.b)}
func(tC)say(){ //C類的say方法 fmt.Println("Hi!",t.c)}類的嵌套和方法覆蓋在程序中用不同方式調(diào)用它們,測試如下://從外向內(nèi)查找,首先找到的是C類的say方法objC.say() //Hi!I'mC.//自B類對象開始向內(nèi)查找,優(yōu)先執(zhí)行B類的say方法objB.say() //Hi!I'mB.//用全路徑調(diào)用最內(nèi)層A類的say方法objC.B.A.say() //Hi!I'mA.類的嵌套和方法覆蓋使得Go語言的類具備了強(qiáng)大的表達(dá)力,幾乎可以表示客觀世界中任何復(fù)雜的對象實(shí)體,并給對象擴(kuò)充出豐富的行為能力,下面通過一個(gè)實(shí)例形象地演示這一點(diǎn)。類的嵌套和方法覆蓋【實(shí)例3.7】演示從“魚”到“人”的進(jìn)化。背景知識:根據(jù)古生物學(xué)的研究,生物的進(jìn)化經(jīng)歷了從水生到陸生的演變過程。最初地球上的生物都生活在海洋中,是魚類的時(shí)代。大約3億7500萬年前(泥盆紀(jì)晚期)的某個(gè)時(shí)候,有一種提塔利克魚(學(xué)名:Tiktaalik,見圖)的鰭發(fā)生了變異,長出原始的腕骨及趾頭,于是這些魚紛紛嘗試著用鰭支撐身體爬上岸來,具有了初步的陸上爬行能力,演化出包括恐龍、猿猴在內(nèi)種類繁多的陸地動物。到了距今550萬年前(中新世末期),生活在非洲大陸東南部的一群猿猴(南方古猿)由于氣候環(huán)境變化被迫下到地面,逐步學(xué)會了直立行走,最終進(jìn)化成人類。類的嵌套和方法覆蓋實(shí)現(xiàn)思路:本例先定義一個(gè)基類Fish(魚類),及兩個(gè)表示能力的類SwimAbility(游泳)和WalkAbility(行走)。Fish類嵌套SwimAbility表示魚會游泳,并實(shí)現(xiàn)一個(gè)基礎(chǔ)的游泳方法swimming;再定義一個(gè)Tiktaalik(提塔利克魚類)繼承自Fish類,增加嵌套一個(gè)WalkAbility類表示它比一般的魚多了行走能力,并實(shí)現(xiàn)基礎(chǔ)的行走方法walking;然后定義Tiktaalik的子類Monkey(猿猴類),覆蓋其父類的walking方法,以直立行走取代爬行;最后定義的Human(人類)繼承Monkey類,就同時(shí)擁有了魚和猿的能力。另外,還定義了一個(gè)Sailfish(旗魚類),它直接派生自Fish,并沒有嵌套新的能力類,但重寫(覆蓋)了Fish類的swimming方法,游泳能力極大地增強(qiáng)了。程序代碼如下(fishtohuman.go):運(yùn)行結(jié)果如圖。第3章Go語言面向?qū)ο缶幊探涌?1接口聲明與初始化1.接口聲明2.接口初始化3.空接口接口聲明與初始化1.接口聲明接口在本質(zhì)上是一種類型,故也像其他自定義類型一樣用type關(guān)鍵字聲明。接口是一組方法的集合(也可以只有一個(gè)方法),但不包含這些方法的具體實(shí)現(xiàn),其聲明的語法格式如下:type接口名interface{
方法1([形參列表])[(返回值列表)]
方法2([形參列表])[(返回值列表)] ...
方法n([形參列表])[(返回值列表)]}例如:typeAquaticAnimalinterface{ //水生動物接口 swimming()string //游泳方法}
typeLandAnimalinterface{ //陸地動物接口 swimming()string //游泳方法 walking()string //行走方法}
typeManKindinterface{ //人類接口 swimming()string //游泳方法 walking()string //行走方法 manufacturing(toolstring)string //制造工具方法}接口聲明與初始化接口聲明中除了單純的方法,還可以嵌入其他接口,這一點(diǎn)與類的嵌套(繼承)有相似之處,如上面人類接口的定義還可以寫成:typeManKindinterface{ AquaticAnimal //嵌入水生動物接口 walking()string manufacturing(toolstring)string}或者:typeManKindinterface{ LandAnimal //嵌入陸地動物接口 manufacturing(toolstring)string}接口聲明與初始化2.接口初始化接口初始化的方式有兩種,如下。1)用對象實(shí)例賦值如果一個(gè)類實(shí)現(xiàn)了接口中的所有方法(實(shí)現(xiàn)了該接口),就可以把這個(gè)類的對象實(shí)例賦值給接口。例如,定義一個(gè)人類Human,并實(shí)現(xiàn)人類接口中的所有(3個(gè))方法,如下:typeHumanstruct{ //人類 namestring}
func(h*Human)swimming()string{ //實(shí)現(xiàn)游泳方法 return"會游泳"}
func(h*Human)walking()string{ //實(shí)現(xiàn)行走方法 return"會行走"}
func(h*Human)manufacturing(toolstring)string{ //實(shí)現(xiàn)制造工具方法 return"會制造"+tool}接口聲明與初始化人類實(shí)現(xiàn)了ManKind接口,就可以將人類的對象實(shí)例賦值給ManKind接口,如下:funcmain(){ man:=Human{"北京猿人"} //創(chuàng)建一個(gè)人類的對象實(shí)例 varmanKindManKind=&man //賦值給接口 fmt.Println("我是",,",",manKind.manufacturing("石器"),"。")} //我是北京猿人,會制造石器。說明:(1)在賦值給接口時(shí)使用的是對象實(shí)例man的引用(&),因?yàn)镚o語言的接口本質(zhì)上是一個(gè)指針類型。(2)雖然對象實(shí)例賦給了接口,但只能通過這個(gè)接口調(diào)用對象實(shí)例的方法而不能訪問其屬性,要獲取對象屬性,只能用“對象.getXxx()”(若有g(shù)et方法)或“對象.屬性名”,而不能用“接口.屬性名”,例如,如果將最后的輸出語句改為:fmt.Println("我是",manK,",",manKind.manufacturing("石器"),"。")運(yùn)行會報(bào)錯(cuò):manKundefined(typeManKindhasnofieldormethodname)(3)只要接口的方法集是對象實(shí)例方法集的子集就都可以實(shí)現(xiàn)這種賦值,例如,人類對象也同樣可以賦給陸地動物和水生動物接口,如下:varlandAnimalLandAnimal=&man //賦給陸地動物接口fmt.Println("我是",,",",landAnimal.walking(),"。") //我是北京猿人,會行走。varaquaticAnimalAquaticAnimal=&man //賦給水生動物接口fmt.Println("我是",,",",aquaticAnimal.swimming(),"。") //我是北京猿人,會游泳。接口聲明與初始化2)用接口變量賦值用一個(gè)已經(jīng)初始化的接口類型變量賦給另一個(gè)接口,這種方式在以下幾種情況下可以。(1)兩個(gè)接口等價(jià)兩個(gè)擁有完全相同的方法集的接口稱為等價(jià)接口,這個(gè)很好理解,如果接口A和接口B的方法是相同的,那么一個(gè)類只要實(shí)現(xiàn)了接口A自然也就實(shí)現(xiàn)了接口B,反之亦然,A和B實(shí)際上是等同的,它們的變量可以相互賦值。由于接口聲明對方法的先后順序并無要求,所以只要兩個(gè)接口包含一樣的方法,它們就滿足等價(jià)條件,如下面這兩個(gè)接口:typeOldManinterface{ //古人接口 swimming()string walking()string manufacturing(toolstring)string}
typeNewManinterface{ //新人接口 manufacturing(toolstring)string walking()string swimming()string}接口聲明與初始化它們包含的都是swimming(游泳)、walking(行走)和manufacturing(制造工具)這3個(gè)方法,雖然方法聲明的順序不一致,接口的名稱也不一樣,但這兩個(gè)接口實(shí)質(zhì)是相同的,即它們完全等價(jià),于是可以編寫語句相互賦值,如下:man1:=Human{"北京猿人"}varoldManOldMan=&man1varnewManNewMan=oldMan //古人接口的變量賦給新人接口fmt.Println("我是",,",",newMan.manufacturing("舊石器"),"。") //我是北京猿人,會制造舊石器。man2:=Human{"山頂洞人"}newMan=&man2oldMan=newMan //新人接口的變量賦給古人接口fmt.Println("我是",,",",oldMan.manufacturing("新石器"),"。") //我是山頂洞人,會制造新石器。接口聲明與初始化(2)被賦值接口的方法集是對方的子集如果接口A的方法集中包含了接口B的所有方法,即B的方法集是A的方法集的子集,就可以將接口A的變量賦值給B,但反之不行。例如:typeLandAnimalinterface{ //陸地動物(對應(yīng)上面所說接口A) swimming()string walking()string}
typeAquaticAnimalinterface{ //水生動物(對應(yīng)上面所說接口B) swimming()string}接口聲明與初始化陸地動物接口的方法集有swimming(游泳)和walking(行走)兩個(gè)方法,它包含了水生動物接口僅有的一個(gè)swimming方法,故陸地動物接口的變量可以賦給水生動物接口,例如:typeFishstruct{ //魚類 categorystring}func(f*Fish)swimming()string{ //實(shí)現(xiàn)水生動物接口 return"會游泳"}
typeTiktaalikstruct{ //提塔利克魚 Fish}func(t*Tiktaalik)walking()string{ //實(shí)現(xiàn)陸地動物接口 return"會爬行"}
funcmain(){ fish1:=Fish{"魚"} fish2:=Tiktaalik{Fish{"提塔利克魚"}} varnewAnimalLandAnimal=&fish2 varoldAnimalAquaticAnimal=newAnimal //陸地動物接口變量賦給水生動物 fmt.Println(fish2.category,"是",fish1.category,",",oldAnimal.swimming(),"。") //提塔利克魚是魚,會游泳。}接口聲明與初始化但是,反過來卻不行,如下語句:oldAnimal=&fish1newAnimal=oldAnimal //水生動物接口變量賦給陸地動物fmt.Println(fish1.category,"是",fish2.category,",",newAnimal.walking(),"。")運(yùn)行會報(bào)錯(cuò):cannotuseoldAnimal(variableoftypeAquaticAnimal)asLandAnimalvalueinassignment:AquaticAnimaldoesnotimplementLandAnimal(missingmethodwalking)接口聲明與初始化3.空接口1)空接口的賦值顯然,空接口的方法集為空,所以任何類(包括數(shù)據(jù)類型)都被認(rèn)為實(shí)現(xiàn)了空接口,任何類(類型)的實(shí)例都可以賦值給空接口。例如:2)空接口的比較在Go中用一個(gè)內(nèi)部常量nil代表空值,它也是空接口的初始值,但是,一個(gè)空接口類型的變量并非在任何情況下都是空的,兩個(gè)空接口也不總是相等。接口聲明與初始化下面聲明兩個(gè)空接口nulFace1和nulFace2,用程序測試并比較它們的實(shí)際值。varnulFace1,nulFace2interface{} //聲明兩個(gè)空接口(1)所有空接口變量初始值都為nil,都相等。測試如下:fmt.Println(nulFace1,nulFace2) //<nil><nil>fmt.Println(nulFace1==nil) //truefmt.Println(nulFace1==nulFace2) //true(2)任何非空接口變量的默認(rèn)值也為nil,與空接口相等。例如,對于尚未初始化的水生動物接口:typeAquaticAnimalinterface{ swimming()string}執(zhí)行語句:varoldAnimalAquaticAnimal //聲明接口變量(但不初始化)fmt.Println(oldAnimal) //<nil>fmt.Println(nulFace1==oldAnimal) //true接口聲明與初始化(3)當(dāng)一個(gè)空接口接受了賦值之后,其值會出現(xiàn)多種情形,如下。①如果給空接口賦值的是一個(gè)有值的變量(或常量),則賦值后空接口值就等于該變量(或常量)的值,不再為nil,也與其他空接口不再相等。例如:constcint=299792458 //整型常量nulFace1=c //常量賦給空接口fmt.Println(nulFace1) //299792458fmt.Println(nulFace1==c) //truefmt.Println(nulFace1==nil) //falsefmt.Println(nulFace1==nulFace2) //falsenulFace1=nil //將接口nulFace1重置為空②如果給空接口賦值的是一個(gè)已經(jīng)初始化了的非空接口,則賦值后空接口就與該非空接口相等,不再為nil,也與其他空接口不再相等。例如,將水生動物接口初始化后賦給空接口:fish1:=Fish{"魚"}oldAnimal=&fish1 //初始化水生動物接口nulFace1=oldAnimal //賦給空接口fmt.Println(nulFace1) //&{魚}fmt.Println(nulFace1==oldAnimal) //truefmt.Println(nulFace1==nil) //falsefmt.Println(nulFace1==nulFace2) //false接口聲明與初始化③如果給空接口賦值的是一個(gè)尚未初始化的非空接口,則賦值后空接口值為(回歸)空。例如,對于尚未初始化的陸地動物接口:typeLandAnimalinterface{ swimming()string walking()string}執(zhí)行語句:varlandAnimalLandAnimal //聲明接口變量(但未初始化)nulFace1=landAnimal //賦給空接口fmt.Println(nulFace1==nil) //truefmt.Println(nulFace1==nulFace2) //true接口聲明與初始化④如果給空接口賦值的是未初始化的變量,則賦值后空接口值為該變量類型的零值或空值,不再為nil,也與其他空接口不再相等。例如:varaintnulFace1=a //未初始化的整型變量賦給空接口fmt.Println(nulFace1) //0fmt.Println(nulFace1==nil) //falsefmt.Println(nulFace1==nulFace2) //falsevarbcomplex64nulFace1=b //未初始化復(fù)數(shù)型變量賦給空接口fmt.Println(nulFace1) //(0+0i)接口聲明與初始化(4)兩個(gè)分別被賦了變量值的空接口的相等性取決于賦給它們的變量的值是否相等。例如:vard1float32=3.14vard2float32=math.Pi //圓周率精確值nulFace1=d1nulFace2=d2fmt.Println(nulFace1==nulFace2) //falsenulFace2=d1fmt.Println(nulFace1==nulFace2) //true02接口類型推斷1.類型判斷2.類型查詢接口類型推斷1.類型判斷類型判斷又稱“類型斷言”,寫為一個(gè)表達(dá)式:接口變量名.(類型名)它用于判斷接口變量綁定的實(shí)例是否實(shí)現(xiàn)了(或本身就是)括號中所指類型的接口(或數(shù)據(jù)),故這里的“類型名”可以是一個(gè)接口類型名,也可以是其他(基本或復(fù)合)數(shù)據(jù)類型名。程序中的類型判斷表達(dá)式通常寫在如下形式的代碼塊中:if_,ok:=類型判斷表達(dá)式;ok{ ...//代碼段1}else{ ...//代碼段2}接口類型推斷【實(shí)例3.8】判斷一種類人動物是否是“人”。背景知識:在人類從“猿”到“人”的進(jìn)化過程中,產(chǎn)生了很多中間過渡類型的動物,古人類學(xué)家判斷一種動物是否是真正意義上的“人”,主要依據(jù)兩條標(biāo)準(zhǔn)——直立行走和制造工具。如果一種類人動物已經(jīng)會直立行走了,但還不能制造工具,那么它只能被劃歸為類人猿亞目下的“人科”成員,而不是“人屬”物種,即還不能算作人,例如,史上曾經(jīng)出現(xiàn)過的乍得沙赫人、始祖地猿、南方古猿、鮑氏傍人……雖然它們有的名稱中也帶有“人”字,但本質(zhì)上并不是人;只有會制造工具的物種,如元謀人、藍(lán)田人、北京猿人、山頂洞人、尼安德特人等,才是“人屬”動物,才算真正的“人”。實(shí)現(xiàn)思路:本例先定義一個(gè)Monkey(猿猴)接口,里面有walking(直立行走)方法;定義ManKind(人類)接口嵌套(繼承)Monkey接口,再增加一個(gè)manufacturing(制造工具)方法。Ape(類人猿)類實(shí)現(xiàn)Monkey接口,Human(人)類繼承Ape類,并進(jìn)一步實(shí)現(xiàn)ManKind接口。程序根據(jù)運(yùn)行時(shí)接口的實(shí)際類型來判斷一個(gè)對象究竟是猿還是人。程序代碼如下(ishuman.go):運(yùn)行結(jié)果如圖。接口類型推斷2.類型查詢?nèi)绻粋€(gè)接口變量的類型尚不確定(或有多種可能),可使用“接口變量名.(type)”表達(dá)式結(jié)合switch語句進(jìn)行類型查詢以確定變量所屬的準(zhǔn)確類型,語法格式如下:switch接口變量名.(type){case類型名1: [<語句1>]case類型名2: [<語句2>]...case類型名n: [<語句n>][default:<語句n+1>]}接口類型推斷【實(shí)例3.9】查詢確定動物的類型。程序代碼如下(iswhatanimal.go):運(yùn)行結(jié)果如圖。接口類型推斷需要特別注意以下兩點(diǎn):(1)fallthrough語句不能用在類型查詢的switch語句中。(2)當(dāng)查詢的多個(gè)可能類型之間存在嵌套(繼承)關(guān)系,如本例的三個(gè)接口之間是逐層嵌套定義的,要將子接口的判斷分支寫在父接口之前,因?yàn)槌绦蛑灰ヅ渖弦粋€(gè)分支,就不會再去比對其余的分支,若將上面的查詢函數(shù)改成如下:funcisWhatAnimal(animalAquaticAnimal){ switchanimal.(type){ caseAquaticAnimal: fmt.Println(animal.getName(),animal.swimming(),",是水生動物。") caseLandAnimal: fmt.Println(animal.getName(),animal.swimming(),",是陸地動物。") caseManKind: fmt.Println(animal.getName(),animal.swimming(),",是人。") default: fmt.Println(animal.getName(),"所屬動物類型不確定!") }}接口類型推斷再執(zhí)行語句:varanimalAquaticAnimalanimal=&Human{Ape{Fish{"周何駿"}}}isWhatAnimal(animal)就會得出一個(gè)人是水生動物的結(jié)論如圖,這顯然是荒謬的!第3章Go語言面向?qū)ο缶幊谭?/p>
射反
射Go語言提供一種機(jī)制在運(yùn)行時(shí)更新變量和檢查它們的值、調(diào)用它們的方法,但是在編譯時(shí)并不“知道”這些變量的具體類型,這稱為“反射機(jī)制”。在Go內(nèi)置的reflect包里定義了一個(gè)接口reflect.Type和一個(gè)結(jié)構(gòu)體reflect.Value,它們提供很多函數(shù)來獲取存儲在接口里的類型信息。(1)reflect.Type接口:主要提供關(guān)于類型相關(guān)的信息。(2)reflect.Value結(jié)構(gòu)體:主要提供關(guān)于值相關(guān)的信息,可以獲取甚至改變類型的值。reflect包中提供了兩個(gè)基礎(chǔ)的函數(shù)來獲取上述的接口和結(jié)構(gòu)體,原型如下:funcTypeof(iinterface{})TypefuncValueOf(iinterface{})ValueGo語言中反射的使用遵循三大法則(又稱“反射三定律”,詳見《TheLawsofReflection》),如下:法則一:反射可以將“接口變量”轉(zhuǎn)換為“反射對象”。法則二:反射可以由“反射對象”創(chuàng)建出“接口變量”。法則三:如果要修改“反射對象”,則其值必須是“可寫的”。01接口變量轉(zhuǎn)換為反射對象接口變量轉(zhuǎn)換為反射對象反射是一種檢查存儲在接口變量中的(類型,值)對的機(jī)制。
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 穿戴式設(shè)備在智能執(zhí)法記錄儀中的應(yīng)用考核試卷
- 空調(diào)器智能濕度調(diào)節(jié)算法考核試卷
- 2025年中國電鍍金剛石打孔鉆市場調(diào)查研究報(bào)告
- 自動扶梯驅(qū)動電機(jī)與控制技術(shù)考核試卷
- 2025鈷產(chǎn)品購銷合同范本版
- gps考試試題及答案
- 配送員考試試題及答案
- 新疆遴選公務(wù)員筆試題及答案
- 對口考試試題及答案
- 臨床營養(yǎng)考試試題及答案
- 【MOOC】食品化學(xué)-西北農(nóng)林科技大學(xué) 中國大學(xué)慕課MOOC答案
- 2024年江蘇泰州市第五人民醫(yī)院招考聘用備案制人員165人管理單位遴選500模擬題附帶答案詳解
- Unit 4 My Favourite Subject .大單元整體說課稿2024-2025學(xué)年人教版英語七年級上冊
- 二位數(shù)乘二位數(shù)600道
- 膿毒血癥護(hù)理課件
- 南航集團(tuán)招聘筆試題庫2024
- 新能源發(fā)電技術(shù) 課件 第七章-新能源發(fā)電的故障穿越技術(shù)
- 醫(yī)學(xué)倫理學(xué)智慧樹知到答案2024年寧波大學(xué)
- 質(zhì)量為綱-華為公司質(zhì)量理念與實(shí)踐
- 商業(yè)廣場前期物業(yè)技術(shù)方案投標(biāo)方案(技術(shù)方案)
- GB/T 4706.1-2024家用和類似用途電器的安全第1部分:通用要求
評論
0/150
提交評論