




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第6章面向?qū)ο筇卣髅嫦驅(qū)ο蟪绦蛟O(shè)計(jì)
1面向?qū)ο筇卣?3主要內(nèi)容包與類庫(kù)封裝性與訪問(wèn)權(quán)限45類的繼承final關(guān)鍵字6抽象類7對(duì)象轉(zhuǎn)換8案例:開(kāi)發(fā)自定義類庫(kù)面向?qū)ο蟪绦蛟O(shè)計(jì)(Java語(yǔ)言描述微課版基于IntelliJIDEA)類的關(guān)系910理解多態(tài)面向?qū)ο筇卣髅嫦驅(qū)ο蟪绦蛟O(shè)計(jì)面向?qū)ο筇卣骱兔嫦蜻^(guò)程編程方法相比,面向?qū)ο蟮某绦蛟O(shè)計(jì)方法的最顯著的特點(diǎn)是它更接近于人們通常的思維規(guī)律,因而設(shè)計(jì)出的軟件系統(tǒng)能夠更直接地、自然地反映客觀現(xiàn)實(shí)中的問(wèn)題。封裝性、繼承性和多態(tài)性是面向?qū)ο缶幊陶Z(yǔ)言的三大特性,Java語(yǔ)言支持這三大特性。面向?qū)ο蟪绦蛟O(shè)計(jì)(Java語(yǔ)言描述微課版基于IntelliJIDEA)6.1.1封裝性封裝性是面向?qū)ο蟮囊粋€(gè)重要特征。在Java語(yǔ)言中,對(duì)象就是一組變量和方法的封裝體。對(duì)象是狀態(tài)(屬性)和行為(操作或方法)封裝體。例如,電視機(jī)是一個(gè)封裝體。實(shí)現(xiàn)信息隱藏,通過(guò)接口與外界通信。通過(guò)對(duì)象的封裝,用戶不必了解對(duì)象是如何實(shí)現(xiàn)的,只須通過(guò)對(duì)象提供的接口與對(duì)象進(jìn)行交互就可以。封裝性實(shí)現(xiàn)了模塊化和信息隱藏,有利于程序的可移植性和對(duì)象的管理。面向?qū)ο蟪绦蛟O(shè)計(jì)(Java語(yǔ)言描述微課版基于IntelliJIDEA)6.1.1繼承性繼承(inheritance)的概念普遍存在于現(xiàn)實(shí)世界中。它是一個(gè)對(duì)象獲得另一個(gè)對(duì)象的屬性的過(guò)程。繼承之所以重要,是因?yàn)樗С謱哟谓Y(jié)構(gòu)類的概念。我們發(fā)現(xiàn),在現(xiàn)實(shí)世界中,許多知識(shí)都是通過(guò)層次結(jié)構(gòu)方式進(jìn)行管理的。圖7-1給出了常用交通工具類及其子類的繼承關(guān)系。有交通工具的所有特性。例如,小汽車(chē)是一種車(chē),而車(chē)又是一種交通工具。交通工具類有的某些特性(可運(yùn)貨,有動(dòng)力)也適用于它的子類車(chē)。飛機(jī)也是一種交通工具,它具有與車(chē)不同的特性,但都具有交通工具的所有特性。面向?qū)ο蟪绦蛟O(shè)計(jì)(Java語(yǔ)言描述微課版基于IntelliJIDEA)6.1.1繼承性類的繼承描述了類之間的一種關(guān)系,它實(shí)際是類的一種泛化關(guān)系,即是一種(is-a)關(guān)系,比如飛機(jī)是一種(is-a)交通工具。類的繼承是復(fù)用類的一種形式。在面向?qū)ο蠓治鲋校^承外,還有其他關(guān)系,如關(guān)聯(lián)關(guān)系、組合關(guān)系、聚合關(guān)系和依賴關(guān)系等。比如,一臺(tái)小汽車(chē)就是由發(fā)動(dòng)機(jī)、車(chē)身、輪胎、方向盤(pán)等組成,它們共同組成一輛車(chē)。面向?qū)ο蟪绦蛟O(shè)計(jì)(Java語(yǔ)言描述微課版基于IntelliJIDEA)多態(tài)性(polymorphism)是面向?qū)ο缶幊陶Z(yǔ)言的一個(gè)重要特性。所謂多態(tài),是指一個(gè)程序中相同的名字表示不同含義的情況。多態(tài)性比如對(duì)于“running”這個(gè)動(dòng)作,我們可以說(shuō)狗可以running,人也可以running,汽車(chē)也可以running。這是無(wú)關(guān)的類使用相同的名字情況。多態(tài)性多態(tài)也可存在于具有父子關(guān)系的類型中,例如,假設(shè)Employee類是Programmer類的父類,那么Employee類的“working”與Programmer類的“working”通常具有不同的含義,這是子類中定義的與父類中的方法同名的方法,即稱為方法覆蓋。6.2包與類庫(kù)面向?qū)ο蟪绦蛟O(shè)計(jì)Java語(yǔ)言使用包來(lái)組織類庫(kù)。包(package)實(shí)際是一組相關(guān)類或接口的集合。Java類庫(kù)中的類都是通過(guò)包來(lái)組織的。我們自己編寫(xiě)的類也可以通過(guò)包組織。包實(shí)際上提供了類的訪問(wèn)權(quán)限和命名管理機(jī)制。概述具體來(lái)說(shuō),包主要有下面幾個(gè)作用:可以將功能相關(guān)的類和接口放到一個(gè)包中。通過(guò)包實(shí)現(xiàn)命名管理機(jī)制,不同包中可以有同名的類。通過(guò)包還可以實(shí)現(xiàn)對(duì)類的訪問(wèn)控制。用戶定義的類都應(yīng)存放到某個(gè)包中,這需要在定義類時(shí)使用package語(yǔ)句。包在計(jì)算機(jī)系統(tǒng)中實(shí)際上對(duì)應(yīng)于文件系統(tǒng)的目錄(文件夾)。包與package語(yǔ)句如果在定義類時(shí)沒(méi)有指定類屬于哪個(gè)包,則該類屬于默認(rèn)包(defaultpackage),即當(dāng)前目錄。默認(rèn)包中的類只能被該包中的類訪問(wèn)。為了保證自己創(chuàng)建的類不與其他人創(chuàng)建的類沖突,需要給包取一個(gè)獨(dú)一無(wú)二的名稱。為了使你的包名與別人的包名不同,建議將域名反轉(zhuǎn)過(guò)來(lái)作為包的名稱。例如,假設(shè)一個(gè)域名為,那么創(chuàng)建的包名可以為com.boda.xy。創(chuàng)建的類都存放在這個(gè)包下,這些類就不會(huì)與任何人的類沖突。package語(yǔ)句要將某個(gè)類放到包中,需在定義類時(shí)使用package語(yǔ)句,如下所示。
packagecom.boda.xy;publicclassEmployee{…}在Java一個(gè)源文件只能有一條package語(yǔ)句,該語(yǔ)句必須為源文件的第一條非注釋語(yǔ)句。創(chuàng)建包通常有兩種方法。許多IDE工具(如Eclipse或IntelliJIDEA等)創(chuàng)建帶包的類時(shí)自動(dòng)創(chuàng)建包的路徑,并將編譯后的類放入指定的包中。如何創(chuàng)建包若使用java命令編譯源文件,使用帶–d選項(xiàng)的編譯命令。如上述源文件可使用下列方法編譯。D:\study>javac–dD:\studyEmployee.java這里,-d后面指定的路徑為包的上一級(jí)目錄。這樣編譯器自動(dòng)在D:\study目錄創(chuàng)建一個(gè)com\boda\xy子目錄,然后將編譯后的Employee.class類文件放到該目錄中。如果一個(gè)類屬于某個(gè)包,就可以用類的完全限定名(fullyqualifiedname)來(lái)表示它。例如,若Employee類屬于com.boda.xy包,則它的完全限定名是
com.boda.xy.Employee類的完全限定名為了使用某個(gè)包中的類或接口,需要將它們導(dǎo)入到源程序中。在Java語(yǔ)言中可以使用兩種導(dǎo)入:一是使用import語(yǔ)句導(dǎo)入指定包中的類或接口。二是使用importstatic導(dǎo)入類或接口中的靜態(tài)成員。類的導(dǎo)入import語(yǔ)句用于導(dǎo)入程序中需要使用的類,它有兩種寫(xiě)法。一是具體指定要導(dǎo)入的完整類名,另一種是使用星號(hào)(*)通配符指定導(dǎo)入某個(gè)包中的所有類。比如,程序要使用java.util包中的Scanner類,就可以使用下面兩種方式:import語(yǔ)句importjava.util.Scanner;importjava.util.*;如果一個(gè)源程序中要使用某個(gè)包中的多個(gè)類,用第二種方式比較方便,否則要寫(xiě)多個(gè)import語(yǔ)句。導(dǎo)入某個(gè)包中所有類并不是將所有的類都加到源文件中,而是使用到哪個(gè)類才導(dǎo)入哪個(gè)類。也可以不用import語(yǔ)句而在使用某個(gè)類時(shí)指明該類所屬的包。java.util.Scannersc=newjava.util.Scanner(System.in);import語(yǔ)句另外,需要注意的是如果用“*”號(hào)這種方式導(dǎo)入不同包中有同名的類,在使用時(shí)應(yīng)指明類的全名。importjava.util.*;importjava.sql.*;publicclassPackageDemo{publicstaticvoidmain(String[]args){Dated=newDate();//該語(yǔ)句編譯錯(cuò)誤System.out.println("d="+d);}}程序7.1PackageDemo.java需要使用類的完全限定名。如要?jiǎng)?chuàng)建java.util包中的Date類對(duì)象,創(chuàng)建對(duì)象的語(yǔ)句應(yīng)該改為:
java.util.Dated=newjava.util.Date();在Java5版中,允許使用importstatic語(yǔ)句導(dǎo)入類中的常量和靜態(tài)方法,然后再使用這些類中的常量或方法就不用加類名前綴了。importstatic語(yǔ)句例如,要使用Math類的random()等方法,就可以先使用下列靜態(tài)導(dǎo)入語(yǔ)句。
importstaticjava.lang.Math.*;然后在程序中就可以直接使用random()了,請(qǐng)看下面程序。importstaticjava.lang.Math.*;importstaticjava.lang.System.*;publicclassImportStaticDemo{publicstaticvoidmain(String[]args){vard=random();//不需要加類名前綴varpi=PI;
out.println("d="+d);//out是System類的一個(gè)靜態(tài)成員
out.println("pi="+pi);} }程序7.2ImportStaticDemo.java程序員除了使用自己定義的類外,還可以使用Java類庫(kù)(JavaClassLibrary,JCL)中定義的類或者第三方定義的類。JCL是Java語(yǔ)言實(shí)現(xiàn)的包的集合。簡(jiǎn)單地說(shuō),它是JDK中的可用.class文件集合。Java類庫(kù)一旦安裝了Java,它們就將作為安裝的一部分,并可以使用JCL類作為構(gòu)建塊來(lái)構(gòu)建應(yīng)用程序代碼,這些構(gòu)建塊負(fù)責(zé)完成許多底層開(kāi)發(fā)。JCL的豐富性和易用性極大地促進(jìn)了Java的流行。包名說(shuō)明java.langJava語(yǔ)言基礎(chǔ)包,該包中的類不需要導(dǎo)入就可以使用。常用類有Object、Class、String和StringBuilder、System、Math、基本類型包裝類等java.util該包主要包含工具類,其中集合類和接口定義在該包中。常用的有Collection、List、Set、Queue、Map等接口以及這些接口的實(shí)現(xiàn)類java.time包含有用于管理日期、時(shí)間、期間和持續(xù)時(shí)間的類。常用的有LocalDate、LocalTime和LocalDateTime類以及Month、DayOfWeek枚舉java.io包含支持使用流、序列化和文件系統(tǒng)讀寫(xiě)數(shù)據(jù)的類和接口java.sql和javax.sql這兩個(gè)包組成Java數(shù)據(jù)庫(kù)連接(JDBC)API,該API允許訪問(wèn)和處理存儲(chǔ)在數(shù)據(jù)源(通常是關(guān)系數(shù)據(jù)庫(kù))中的數(shù)據(jù)。javax.sql包是java.sql包的補(bǔ)充該包存放網(wǎng)絡(luò)編程類,例如:Socket和ServerSocket類等java.awt和javax.swing這兩個(gè)包存放圖形界面程序開(kāi)發(fā)所需要的類Java類庫(kù)6.3案例學(xué)習(xí):開(kāi)發(fā)自定義類庫(kù)面向?qū)ο蟪绦蛟O(shè)計(jì)在Java應(yīng)用開(kāi)發(fā)中通常需要開(kāi)發(fā)自己的類庫(kù),然后在應(yīng)用程序中使用。本例學(xué)習(xí)如何開(kāi)發(fā)一個(gè)簡(jiǎn)單的類庫(kù),然后將它打包成.jar文件,并且在程序中使用它。要求定義一個(gè)名為com.boda.utils.MathUtils類,在該類中定義如下兩個(gè)靜態(tài)方法:自定義類庫(kù)的開(kāi)發(fā)publicstaticbooleanisPrime(intn)publicstaticbooleanisPalindrome(intn)isPrime(intn)方法返回n是否是素?cái)?shù),isPalindrome(intn)方法返回n是否是回文數(shù),如363是一個(gè)回文數(shù)。對(duì)于自定義類庫(kù),按下面思路設(shè)計(jì)。(1)按要求編寫(xiě)com.boda.utils.MathUtils類,其中定義兩個(gè)靜態(tài)方法isPrime(intn)和isPalindrome(intn)。(2)將編譯好的類文件打包到.jar文件中。(3)在應(yīng)用程序中使用自定義類庫(kù),需要添加.jar文件。自定義類庫(kù)的開(kāi)發(fā)程序7.13是類庫(kù)的com.boda.utils.MathUtils類,該類定義了兩個(gè)靜態(tài)方法,其中isPrime()用于返回參數(shù)是否是素?cái)?shù),isPalindrome()返回參數(shù)是否是回文數(shù)。
publicstaticbooleanisPrime(intn){//判斷素?cái)?shù)
for(vardivisor=2;divisor*divisor<=n;divisor++){
if(n%divisor==0)
returnfalse;
}
returntrue;
}程序7.13MathUtils.java
publicstaticbooleanisPalindrome(intn){//判斷回文數(shù)
vars=String.valueOf(n);
varlow=0;
varheigh=s.length()-1;
while(low<heigh){if(s.charAt(low)!=s.charAt(heigh)){
returnfalse;//不是回文}low++;heigh--;}returntrue;
}要將上述類打包到.jar文件中還需創(chuàng)建一個(gè)主類和一個(gè)清單文件,程序7.13的MathUtils類中包含一個(gè)main()方法,所以可把它作為主類,否則就需單獨(dú)創(chuàng)建一個(gè)主類。自定義類庫(kù)的開(kāi)發(fā)在IntelliJIDEA中選擇File→ProjectStructure,在彈出的窗口中,選擇左側(cè)的Artifact,點(diǎn)擊窗口右上角的“+”按鈕,選擇JAR→FromModuleswithdependencies,打開(kāi)如圖6-5所示的窗口。自定義類庫(kù)的開(kāi)發(fā)在該對(duì)話框中指定主類名(MainClass)、指定清單文件(MANIFEST.MF)路徑,IDEA將自動(dòng)創(chuàng)建META-INF目錄,并建立MANIFEST.MF清單文件,內(nèi)容如下:Manifest-Version:1.0Main-Class:com.boda.xy.MathUtils在IDEA主窗口選擇Build→BuildArtifacts命令構(gòu)建JAR文件。要在應(yīng)用程序中使用JAR文件,需要將它作為作為庫(kù)添加到項(xiàng)目中即可。自定義類庫(kù)的開(kāi)發(fā)由于該JAR文件包含一個(gè)主類,因此它是可執(zhí)行的JAR文件。要執(zhí)行這個(gè)JAR文件,在命令提示符下使用帶-jar參數(shù)的java命令,命令及運(yùn)行結(jié)果如圖所示。運(yùn)行程序,輸出2-1000之間所有回文素?cái)?shù)如圖7-7所示。自定義類庫(kù)的開(kāi)發(fā)6.4封裝性與訪問(wèn)修飾符面向?qū)ο蟪绦蛟O(shè)計(jì)封裝性是面向?qū)ο蟮囊粋€(gè)重要特征。在Java語(yǔ)言中,對(duì)象就是一組變量和方法的封裝體。通過(guò)對(duì)象的封裝,用戶不必了解對(duì)象是如何實(shí)現(xiàn)的,只須通過(guò)對(duì)象提供的接口與對(duì)象進(jìn)行交互就可以。封裝性實(shí)現(xiàn)了模塊化和信息隱藏,有利于程序可移植性和對(duì)象的管理。概述對(duì)象的封裝是通過(guò)兩種方式實(shí)現(xiàn):(1)通過(guò)包實(shí)現(xiàn)封裝性。在定義類時(shí)使用package語(yǔ)句指定類屬于哪個(gè)包。包是Java語(yǔ)言最大的封裝單位,它定義了程序?qū)︻惖脑L問(wèn)權(quán)限。(2)通過(guò)類或類的成員的訪問(wèn)權(quán)限實(shí)現(xiàn)封裝性。包是Java語(yǔ)言最大的封裝單位,它定義了程序?qū)︻惖脑L問(wèn)權(quán)限。圖7-2給出了兩個(gè)包c(diǎn)om.boda.xy和org.demo.ab的結(jié)構(gòu),其中A、B、C類屬于com.boda.xy包,D和E類屬于org.demo.ab包。箭頭表示類繼承關(guān)系,其中B是A的子類,且與A在同一個(gè)包中,D也是A的子類,但與A不在同一個(gè)包中。概述類(也包括接口和枚舉等)的訪問(wèn)權(quán)限通過(guò)修飾符public實(shí)現(xiàn)。它定義哪些類可以使用該類。public類可以被任何其他類使用,而缺省訪問(wèn)修飾符的類僅能被同一包中的類使用。下面的Bicycle類定義在com.boda.xy包中,該類缺省訪問(wèn)修飾符。6.4.1類的訪問(wèn)權(quán)限packagecom.boda.xy;classBicycle{Bicycle(){System.out.println(“生產(chǎn)一輛自行車(chē)");
}}下面的BicycleDemo類定義在org.demo.ab包中,它與Bicycle類不在同一個(gè)包,在該類中試圖使用com.boda.xy包中的Bicycle類。7.3.1類的訪問(wèn)權(quán)限packageorg.demo.ab;
importcom.boda.xy.Bicycle;
publicclassRobotDemo{publicstaticvoidmain(String[]args){Bicyclebike=newBicycle();
}}對(duì)出現(xiàn)這樣問(wèn)題可以有兩種解決辦法:(1)將Bicycle類的訪問(wèn)修飾符修改為public,使它成為公共類,這樣就可以被所有其他類訪問(wèn)。(2)將BicycleDemo類和Bicycle類定義在一個(gè)包中,即BicycleDemo類的package語(yǔ)句改為如下語(yǔ)句。packagecom.boda.xy;7.3.1類的訪問(wèn)權(quán)限一般情況下,如果一個(gè)類只提供給同一個(gè)包中的類訪問(wèn)可以不加訪問(wèn)修飾符,如果還希望被包外的類訪問(wèn),則需要加上public訪問(wèn)修飾符。類成員的訪問(wèn)權(quán)限包括成員變量和成員方法的訪問(wèn)權(quán)限。共有4個(gè)修飾符,它們分別是:private缺省的protectedpublic這些修飾符控制成員可以在程序的哪些部分被訪問(wèn),也叫成員的可見(jiàn)性。7.3.2類成員的訪問(wèn)權(quán)限用private修飾的成員稱為私有成員,私有成員只能被這個(gè)類本身訪問(wèn),外界不能訪問(wèn)。private修飾符最能體現(xiàn)對(duì)象的封裝性,從而可以實(shí)現(xiàn)信息的隱藏。private修飾符packagecom.boda.xy;classAnimal{
privateStringname="大熊貓";
privatevoiddisplay(){System.out.println("Mynameis"+name);}}程序7.3AnimalDemo.javapublicclassAnimalDemo{
publicstaticvoidmain(String[]args){Animala=newAnimal();System.out.println("="+);a.display();
}}如果將上面程序的main()方法寫(xiě)在Animal類中,程序能正常編譯和運(yùn)行。這時(shí),main()方法定義在Animal類中,它可訪問(wèn)本類中的private變量和private方法。類的構(gòu)造方法也可以被聲明為私有的,這樣其他類就不能生成該類的實(shí)例,一般是通過(guò)調(diào)用該類的工廠方法來(lái)創(chuàng)建類的實(shí)例。缺省修飾符的成員,一般稱為包可訪問(wèn)的。這樣的成員可以被該類本身和同一個(gè)包中的類訪問(wèn)。其他包中的類不能訪問(wèn)這些成員。對(duì)于構(gòu)造方法,如果沒(méi)有加訪問(wèn)修飾符,也只能被同一個(gè)包的類產(chǎn)生實(shí)例。缺省修飾符當(dāng)成員被聲明為protected時(shí),一般稱為保護(hù)成員。該類成員可以被這個(gè)類本身、同一個(gè)包中的類以及該類的子類(包括同一個(gè)包以及不同包中的子類)訪問(wèn)。protected修飾符如果一個(gè)類有子類且子類可能處于不同的包中,為了使子類能直接訪問(wèn)父類的成員,那么應(yīng)該將其聲明為保護(hù)成員,而不應(yīng)該聲明為私有或默認(rèn)的成員。用public修飾的成員一般稱為公共成員,公共成員可以被任何其他的類訪問(wèn),但前提是類是可訪問(wèn)的。表6-2總結(jié)了各種修飾符的訪問(wèn)權(quán)限。public修飾符修飾符同一個(gè)類同一個(gè)包的類不同包的子類任何類private√???缺省√√??protected√√√?public√√√√6.5類的繼承面向?qū)ο蟪绦蛟O(shè)計(jì)繼承的基本思想是可以從已有的類派生出新類。不同的類可能會(huì)有一些共同的特征和行為,可以將這些共同的特征和行為統(tǒng)一放在一個(gè)類中,使它們可以被其他類所共享。概述例如,可以將人定義為一個(gè)類(Person),因?yàn)閱T工具有人的所有的特征和行為,則可以將員工類定義為人的子類(Employee),這就叫繼承。進(jìn)一步,還可以將經(jīng)理(Manager)又定義為員工類的子類,經(jīng)理也繼承了員工的特征和行為,這樣形成類的層次結(jié)構(gòu)。在類的層次結(jié)構(gòu)中,被繼承的類稱為父類(parentclass)或超類(superclass),而繼承得到的類稱為子類(subclass)或派生類(derivedclass)。子類繼承父類的狀態(tài)和行為,同時(shí)也可以具有自己的特征。概述在Java程序中要實(shí)現(xiàn)類的繼承,使用extends關(guān)鍵字,格式如下:[public]classSubClassextendsSuperClass{//類體定義}6.5.1類繼承的實(shí)現(xiàn)關(guān)鍵字extends把SubClass聲明為SuperClass直接子類。這樣聲明后就說(shuō)SubClass類繼承了SuperClass類或者說(shuō)SubClass類擴(kuò)展了SuperClass類。如果SuperClass又是其他類的子類,則SubClass就為那個(gè)類的間接子類。6.1.1類繼承的實(shí)現(xiàn)將人(Person)定義為一個(gè)類,因?yàn)閱T工(Employee)具有人的所有的特征和行為,則可以將員工類定義為人的子類,這就叫繼承。用UML圖表示繼承:PersonEmployee父類或超類子類或派生類面向?qū)ο蟪绦蛟O(shè)計(jì)(Java語(yǔ)言描述微課版基于IntelliJIDEA)6.1.1實(shí)現(xiàn)類的繼承,使用extends關(guān)鍵字,格式如下:
[public]classSubClassextendsSuperClass{//類體定義}說(shuō)明:1.子類繼承父類中非private的成員變量和成員方法。2省略extends,定義的類繼承Object類。3Java僅支持單繼承。PersonEmployeeObjectPersonStudentObjectEmployeeEmployeeWorkStudentStudent類繼承的實(shí)現(xiàn)面向?qū)ο蟪绦蛟O(shè)計(jì)(Java語(yǔ)言描述微課版基于IntelliJIDEA)publicclassPerson{publicStringname;publicintage;publicPerson(){//無(wú)參構(gòu)造方法
}publicPerson(Stringname,intage){//帶參數(shù)構(gòu)造方法
=name;this.age=age;}publicvoidsayHello(){System.out.println("Mynameis"+name);}}程序6-7Person.javapublicclassEmployeeextendsPerson{publicdoublesalary;//表示員工工資
publicEmployee(){//無(wú)參構(gòu)造方法}publicEmployee(Stringname,intage,doublesalary){//帶3個(gè)參數(shù)構(gòu)造方法super(name,age);this.salary=salary;}publicdoublecomputeSalary(inthours,doublerate){ doubletotalSalary; totalSalary=this.salary+hours*rate; returntotalSalary;}}程序6-8Employee.javapublicstaticvoidmain(String[]args){varemp=newEmployee("劉明",30,5000);System.out.println("姓名="+);System.out.println("年齡="+emp.age);emp.sayHello();//調(diào)用從父類繼承的方法System.out.println(puteSalary(10,50.0));//調(diào)用子類定義的方法}Java中創(chuàng)建子類實(shí)例之前都先調(diào)用父類的構(gòu)造方法創(chuàng)建父類的實(shí)例。程序6-9EmployeeDemo.java在子類中可以定義與父類中的名字、參數(shù)列表、返回值類型都相同的方法,這時(shí)子類的方法就叫做覆蓋(overriding)或重寫(xiě)了父類的方法。6.5.2方法覆蓋說(shuō)明:1子類不能覆蓋超類的private方法。2父類中static方法不能被覆蓋,但可以被繼承。假設(shè)要在Employee類中也定義一個(gè)sayHello()方法,它用來(lái)輸出員工信息,定義如下:
publicvoidsayHello(){System.out.println("Hello,Iam"+name);System.out.println("Iam"+age);System.out.println("Mysalaryis"+salary);}該方法就是對(duì)Person類的sayHello()方法的覆蓋。如果子類覆蓋了超類的方法,再調(diào)用相同的方法時(shí),調(diào)用的是子類的方法。為了避免在覆蓋方法時(shí)寫(xiě)錯(cuò)方法頭,可以使用@Override注解語(yǔ)法,即在要覆蓋的方法前面添加@Override。例如,假設(shè)一個(gè)Employee類要覆蓋Object類的toString()方法,代碼如下:6.5.2方法覆蓋
@OverridepublicStringtoString(){return"姓名:"+name+"年齡:"+age;}@Override注解表示其后的方法必須是覆蓋父類的一個(gè)方法。如果具有該注解的方法沒(méi)有覆蓋父類的方法,編譯器將報(bào)告一個(gè)錯(cuò)誤。6.5.2方法覆蓋例如,toString如果被錯(cuò)誤地寫(xiě)成tosrting,將報(bào)告一個(gè)編譯錯(cuò)誤。如果沒(méi)有使用注解,編譯器不會(huì)報(bào)告錯(cuò)誤。使用注解可以避免錯(cuò)誤。關(guān)于方法覆蓋,有下面兩點(diǎn)值得注意:6.5.2方法覆蓋(1)private方法不能被覆蓋。只有非private的實(shí)例方法才可以覆蓋,如果在子類中定義了一個(gè)方法在父類中是private的,則這兩個(gè)方法完全無(wú)關(guān)。(2)父類中static方法也不能被覆蓋,但可以被繼承。如果子類中定義了與父類中的static方法完全一樣的方法,那么父類中的方法被隱藏。父類中被隱藏的static方法仍然可以使用“類名.方法名()”形式調(diào)用。在子類中可以使用super關(guān)鍵字,它用來(lái)引用當(dāng)前對(duì)象的父類對(duì)象,它可用于下面三種情況。
(1)在子類中訪問(wèn)父類中被隱藏的成員變量,格式為:
super.variableName6.5.3super關(guān)鍵字(2)在子類中調(diào)用父類中被覆蓋的方法,格式為:
super.methodName([paramlist])(3)在子類中調(diào)用父類的構(gòu)造方法,格式為:
super([paramlist])子類不能繼承父類的構(gòu)造方法。要?jiǎng)?chuàng)建子類對(duì)象,需要使用默認(rèn)構(gòu)造方法或?yàn)樽宇惗x構(gòu)造方法。6.5.4調(diào)用父類的構(gòu)造方法Java語(yǔ)言規(guī)定,在創(chuàng)建子類對(duì)象時(shí),必須先構(gòu)造該類的所有父類對(duì)象。因此,在編寫(xiě)子類的構(gòu)造方法時(shí),必須保證它能夠調(diào)用父類的構(gòu)造方法。在子類的構(gòu)造方法中調(diào)用父類的構(gòu)造方法有兩種方式:(1)使用super來(lái)調(diào)用父類的構(gòu)造方法
super([paramlist]);這里super指直接父類的構(gòu)造方法,paramlist指調(diào)用父類帶參數(shù)的構(gòu)造方法。6.5.4調(diào)用父類的構(gòu)造方法(2)調(diào)用父類的默認(rèn)構(gòu)造方法在子類構(gòu)造方法中若沒(méi)有使用super調(diào)用父類的構(gòu)造方法,則編譯器在子類的構(gòu)造方法的第一句自動(dòng)加上super(),即調(diào)用父類無(wú)參數(shù)的構(gòu)造方法。另外,在子類構(gòu)造方法中也可以使用this調(diào)用本類的其他構(gòu)造方法。不管使用哪種方式調(diào)用構(gòu)造方法,this和super語(yǔ)句必須是構(gòu)造方法中的第一條語(yǔ)句,并且最多只有一條這樣的語(yǔ)句。6.5.4調(diào)用父類的構(gòu)造方法不能既調(diào)用this,又調(diào)用super。在任何情況下,創(chuàng)建一個(gè)類的實(shí)例時(shí),將會(huì)沿著繼承鏈調(diào)用所有父類的構(gòu)造方法,這叫做構(gòu)造方法鏈。下面代碼定義了Vehicle類、Bicycle類和ElectricBicycle類,代碼演示了子類和父類構(gòu)造方法的調(diào)用。6.5.4調(diào)用父類的構(gòu)造方法Vehicle交通工具類Bicycle自行車(chē)類ElectricBicycle電動(dòng)自行車(chē)類VehicleBicycleObjectElectricBicycleclassVehicle{//定義Vehicle車(chē)輛類publicVehicle(){System.out.println("創(chuàng)建Vehicle對(duì)象");}}程序7.8ElectricBicycle.javaclassBicycleextendsVehicle{privateStringbrand;publicBicycle(){this("捷安特牌");System.out.println("創(chuàng)建Bicycle對(duì)象");}publicBicycle(Stringbrand){this.brand=brand;}}//ElectricBicycle類擴(kuò)展了Bicycle類publicclassElectricBicycleextendsBicycle{Stringfactory;publicElectricBicycle(){System.out.println("創(chuàng)建ElectricBicycle對(duì)象");}publicstaticvoidmain(String[]args){ElectricBicyclemyBicycle=newElectricBicycle();}}6.6final修飾符面向?qū)ο蟪绦蛟O(shè)計(jì)如果一個(gè)類使用final修飾,則該類就為最終類(finalclass),最終類不能被繼承。下面代碼會(huì)發(fā)生編譯錯(cuò)誤。6.6.1final修飾類classBBextendsAA{//…}final
classAA{//…}不能繼承final類如果一個(gè)方法使用final修飾,則該方法不能被子類覆蓋。例如,下面的代碼會(huì)發(fā)生編譯錯(cuò)誤:6.6.2final修飾方法classAA{publicfinal
voidmethod(){}//最終方法}classBBextendsAA{
@Overridepublicvoidmethod(){}}不能覆蓋final方法用final修飾的變量包括類的成員變量、方法的參數(shù)和方法的局部變量。一個(gè)變量如果用final修飾,則該變量為常值變量,一旦賦值便不能改變。6.6.3final修飾變量對(duì)于類的成員變量一般使用static與final組合定義類常量。這種常量稱為編譯時(shí)常量,編譯器可以將該常量值代入任何可能用到它的表達(dá)式中,這可以減輕運(yùn)行時(shí)的負(fù)擔(dān)。如果使用final修飾方法的參數(shù),則參數(shù)的值在方法體中只能被使用而不能被改變,請(qǐng)看下面代碼:classTest{publicstatic
finalintSIZE=50;publicvoidmethodA(finalinti){
i=i+1;}publicintmethodB(finalinti){
finalintj=i+1;returnj;}}不能修改final參數(shù)可以使用final參數(shù)注意,如果一個(gè)引用變量使用final修飾,表示該變量的引用(地址)不能被改變,一旦引用被初始化指向一個(gè)對(duì)象,就無(wú)法改變使它指向另一個(gè)對(duì)象。但對(duì)象本身是可以改變的,Java沒(méi)有提供任何機(jī)制使對(duì)象本身保持不變。6.6.3final修飾變量6.7類的關(guān)系面向?qū)ο蟪绦蛟O(shè)計(jì)在Java語(yǔ)言中,除繼承外,還有下面的關(guān)系:關(guān)聯(lián)關(guān)系、組合關(guān)系、聚合關(guān)系和依賴關(guān)系。如圖6-11所示。概述關(guān)聯(lián)關(guān)系(association)是一種擁有(has-a)的關(guān)系,它使一個(gè)類知道另一個(gè)類的屬性和方法。如,教師(Teacher)與課程(Course)的關(guān)系就是一種關(guān)聯(lián)關(guān)系,教師講授某門(mén)課程。這種關(guān)系可以是單向的,也可以是雙向的。在UML中使用帶箭頭的實(shí)線表示,箭頭指向被擁有者,如圖6-12所示。6.7.1關(guān)聯(lián)關(guān)系組合關(guān)系(composition)是整體與部分的(contains-a)關(guān)系,但部分不能離開(kāi)整體而單獨(dú)存在。如公司(Company)和部門(mén)(Department)是整體與部分關(guān)系,沒(méi)有公司就不存在部門(mén),即部門(mén)不能單獨(dú)存在。在UML中使用帶實(shí)心菱形的實(shí)線表示,菱形指向整體。如圖6-13所示。6.7.2組合關(guān)系聚合關(guān)系(aggregation)也是整體與部分的(is-a-part-of)關(guān)系,但部分可以離開(kāi)整體而單獨(dú)存在。如車(chē)(Car)和發(fā)動(dòng)機(jī)(Engine)是整體和部分關(guān)系,發(fā)動(dòng)機(jī)離開(kāi)車(chē)仍然可以存在。聚合關(guān)系是關(guān)聯(lián)關(guān)系的一種,是強(qiáng)的關(guān)聯(lián)關(guān)系。關(guān)聯(lián)和聚合在語(yǔ)法上無(wú)法區(qū)分,必須考查具體的邏輯關(guān)系。在UML中使用帶空心菱形的實(shí)線表示,菱形指向整體。如圖6-14所示。6.7.3聚合關(guān)系publicclassEngine{privateStringmodel;privatedoublepower;}三種關(guān)系的實(shí)現(xiàn)publicclassCar{
publicEngineengine;publicvoidsetEngine(Engineengine){this.engine=engine;}//Car類其他代碼}依賴關(guān)系(dependency)是一種使用(usea)關(guān)系,即一個(gè)類的實(shí)現(xiàn)需要另一個(gè)類的協(xié)助。在代碼實(shí)現(xiàn)上,依賴關(guān)系通常用局部變量、方法的參數(shù)或者方法的返回值實(shí)現(xiàn)。依賴關(guān)系是最弱的一種關(guān)聯(lián)形式。例如,Car對(duì)象可能有一個(gè)名為startEngine()的方法,它帶一個(gè)Key對(duì)象作為參數(shù)。作為參數(shù)的Key對(duì)象與Car之間是一種臨時(shí)關(guān)聯(lián)。依賴關(guān)系在UML中使用帶箭頭的虛線表示,箭頭指向被使用者,如圖6-16所示。6.7.4依賴關(guān)系假設(shè)A類依賴于B類。那么這種依賴關(guān)系在Java語(yǔ)言中可通過(guò)下面幾種方式實(shí)現(xiàn):A類使用B類的對(duì)象作為實(shí)例方法的參數(shù)。A類具有一個(gè)成員方法,該成員方法的返回類型為B類的一個(gè)對(duì)象。A類具有一個(gè)成員方法,B類對(duì)象作為該方法的一個(gè)局部變量。當(dāng)然,在Java語(yǔ)言中,依賴關(guān)系也可以定義為類的成員變量,然后通過(guò)構(gòu)造方法或?qū)嵗椒▌?chuàng)建依賴對(duì)象。6.7.4依賴關(guān)系軟件設(shè)計(jì)的一個(gè)原則是“高內(nèi)聚,低耦合”。在類的設(shè)計(jì)中,最好避免這種對(duì)象的依賴關(guān)系,因?yàn)檫@樣可能導(dǎo)致系統(tǒng)的高度耦合。6.8抽象類面向?qū)ο蟪绦蛟O(shè)計(jì)前面章節(jié)中定義的類可以創(chuàng)建對(duì)象,它們都是具體的類。在Java中還可以定義抽象類。抽象類(abstractclass)是包含抽象方法的類。抽象類假設(shè)要開(kāi)發(fā)一個(gè)圖形繪制系統(tǒng),需要定義圓(Circle)類、矩形(Rectangle)類和三角形(Triangle)類等,這些類都需要定義求周長(zhǎng)和面積的方法,這些方法對(duì)不同的圖形有不同的實(shí)現(xiàn)。這時(shí)就可以設(shè)計(jì)一個(gè)更一般的類,比如幾何形狀(Shape)類,在該類中定義求周長(zhǎng)和面積的方法。由于Shape不是一個(gè)具體的形狀,這些方法就不能實(shí)現(xiàn),因此要定義為抽象方法(abstractmethod)。定義抽象方法需要在方法前加上abstract修飾符。抽象方法只有方法的聲明,沒(méi)有方法的實(shí)現(xiàn)。包含抽象方法的類必須定義為抽象類,定義抽象類需要的類前加上abstract修飾符。下面定義的Shape類即為抽象類,其中定義了兩個(gè)抽象方法。抽象類publicabstractclassShape{Stringname;
publicShape(){}//抽象類可以定義構(gòu)造方法
publicShape(Stringname){=name;}publicabstractdoublegetArea();//定義抽象方法publicabstractdoublegetPerimeter();//定義抽象方法}程序6-11Shape.java在抽象類中可以定義構(gòu)造方法,這些構(gòu)造方法可以在子類的構(gòu)造方法中調(diào)用。盡管在抽象類中可以定義構(gòu)造方法,但抽象類不能被實(shí)例化,即不能用new生成抽象類的對(duì)象,如下列語(yǔ)句將會(huì)產(chǎn)生編譯錯(cuò)誤:
Shapesh=newShape();抽象類在抽象類中可以定義非抽象的方法。可以創(chuàng)建抽象類的子類,抽象類的子類還可以是抽象類。只有非抽象的子類才能使用new創(chuàng)建該類的對(duì)象。抽象類中可以沒(méi)有抽象方法,但仍然需要被子類繼承,才能實(shí)例化。publicclassCircleextendsShape{protecteddoubleradius;publicCircle(){this(0.0);
}publicCircle(doubleradius){super("圓");//調(diào)用父類的構(gòu)造方法this.radius=radius;
}publicvoidsetRadius(doubleradius){this.radius=radius;
}
程序6-12Circle.javapublicdoublegetRadius(){returnradius;
}@OverridepublicdoublegetPerimeter(){//實(shí)現(xiàn)父類的抽象方法return2*Math.PI*radius;
}@OverridepublicdoublegetArea(){//實(shí)現(xiàn)父類的抽象方法returnMath.PI*radius*radius;
}@OverridepublicStringtoString(){//覆蓋Object類的toString()方法return"[圓]radius="+radius;
}}6.1.1課堂討論及訓(xùn)練定義Rectangle類表示矩形,繼承Shape抽象類,實(shí)現(xiàn)其中的getPerimeter()方法和getArea()方法。面向?qū)ο蟪绦蛟O(shè)計(jì)(Java語(yǔ)言描述微課版基于IntelliJIDEA)6.9對(duì)象轉(zhuǎn)換面向?qū)ο蟪绦蛟O(shè)計(jì)為了討論方便,先介紹兩個(gè)術(shù)語(yǔ):
子類型和父類型。一個(gè)類(或接口)實(shí)際上定義了一種類型。子類定義的類型稱為子類型,而父類(或接口)定義的類型稱為父類型。因此,對(duì)7.6節(jié)中定義的Shape類和Circle類,就可以說(shuō)Circle是Shape的子類型,Shape類是Circle的父類型。概述子類是它的父類的特殊化,每個(gè)子類的實(shí)例也都是它父類的實(shí)例,但反過(guò)來(lái)不成立。因此,子類對(duì)象和父類對(duì)象在一定條件下也可以相互轉(zhuǎn)換,這種類型轉(zhuǎn)換一般稱為對(duì)象轉(zhuǎn)換或造型(casting)。對(duì)象轉(zhuǎn)換也有自動(dòng)轉(zhuǎn)換和強(qiáng)制轉(zhuǎn)換之分。對(duì)象轉(zhuǎn)換由于子類繼承了父類的數(shù)據(jù)和行為,因此子類對(duì)象可以作為父類對(duì)象使用,即子類對(duì)象可以自動(dòng)轉(zhuǎn)換為父類對(duì)象。可以將子類型的引用賦值給父類型的引用,也就是,在需要父類對(duì)象時(shí),可以用子類對(duì)象替換,這也稱為里氏替換原則(Liskovsubstitutionprinciple,LSP)。假設(shè)parent是一個(gè)父類型引用,child是一個(gè)子類型(直接或間接)引用,則下面的賦值語(yǔ)句是合法的:
parent=child;//子類對(duì)象自動(dòng)轉(zhuǎn)換為父類對(duì)象對(duì)象轉(zhuǎn)換這種轉(zhuǎn)換稱為向上轉(zhuǎn)換(upcasting)。向上轉(zhuǎn)換指的是在類的層次結(jié)構(gòu)圖中,位于下方的類(或接口)對(duì)象都可以自動(dòng)轉(zhuǎn)換為位于上方的類(或接口)對(duì)象,但這種轉(zhuǎn)換必須是直接或間接類(或接口)。6.1.1自動(dòng)轉(zhuǎn)換(向上轉(zhuǎn)換):子類對(duì)象可以自動(dòng)轉(zhuǎn)換為父類對(duì)象。可以將子類型的引用賦值給父類型的引用。自動(dòng)轉(zhuǎn)換:Employeeemp=newEmployee(“劉明”,30,5000);Personp=emp;PersonEmployeeObject自動(dòng)轉(zhuǎn)換Objectobj=emp;對(duì)象轉(zhuǎn)換面向?qū)ο蟪绦蛟O(shè)計(jì)(Java語(yǔ)言描述微課版基于IntelliJIDEA)6.1.1強(qiáng)制轉(zhuǎn)換(向下造型):將父類對(duì)象強(qiáng)制轉(zhuǎn)換為子類對(duì)象。用“()”運(yùn)算符。將父類型的引用賦值給子類型的引用。強(qiáng)制轉(zhuǎn)換:Employeeemp=newEmployee(“劉明”,30,5000);Personp=emp;emp=(Employee)p;PersonEmployeeObject強(qiáng)制轉(zhuǎn)換強(qiáng)制轉(zhuǎn)換Java語(yǔ)言程序設(shè)計(jì)(第4版)
QQ群:288639486對(duì)象轉(zhuǎn)換6.1.1注意,不是任何情況下都可以進(jìn)行強(qiáng)制類型轉(zhuǎn)換,請(qǐng)看下面代碼:不正確的強(qiáng)制轉(zhuǎn)換:Personp=newPerson();Employeeemp=(Employee)p;代碼編譯時(shí)沒(méi)有錯(cuò)誤,但運(yùn)行時(shí)會(huì)拋出ClassCastException異常。PersonEmployeeObject強(qiáng)制轉(zhuǎn)換對(duì)象轉(zhuǎn)換面向?qū)ο蟪绦蛟O(shè)計(jì)(Java語(yǔ)言描述微課版基于IntelliJIDEA)instanceof運(yùn)算符用來(lái)測(cè)試一個(gè)實(shí)例是否是某種類型的實(shí)例,這里的類型可以是類、抽象類、接口等。instanceof運(yùn)算符的格式為:
variableinstanceofTypeName該表達(dá)式返回邏輯值。如果variable是TypeName類型或其父類型的實(shí)例,返回true,否則返回false。6.9.2instanceof運(yùn)算符設(shè)有Fruit(水果)類及它的兩個(gè)子類Apple(蘋(píng)果)和Orange(橘子),假設(shè)給出下面聲明:
Fruitfruit=newApple();Orangeorange=newOrange();6.9.2instanceof運(yùn)算符fruitinstanceofOrange的結(jié)果是false;fruitinstanceofFruit的結(jié)果是true;orangeinstanceofFruit的結(jié)果是true;orangeinstanceofApple的結(jié)果是false。如果一個(gè)實(shí)例是某種類型的實(shí)例,那么該實(shí)例也是該類型的所有父類型的實(shí)例。表達(dá)式fruitinstanceofObject的結(jié)果也是true。6.9.2instanceof運(yùn)算符在Java14之前,instanceof主要是在類型轉(zhuǎn)換之前檢測(cè)對(duì)象的具體類型,然后執(zhí)行具體的強(qiáng)制轉(zhuǎn)換。從Java14開(kāi)始,使用instanceof可以在判斷是否屬于具體的類型同時(shí)完成轉(zhuǎn)換,例如:Objectobj="這是一個(gè)字符串";if(objinstanceofStringstr){System.out.println(str.length());}多態(tài)(polymorphism)是指由繼承而產(chǎn)生的相關(guān)的不同的類,其對(duì)象對(duì)同一消息會(huì)做出不同的響應(yīng)。多態(tài)性是指在運(yùn)行時(shí)系統(tǒng)判斷應(yīng)該執(zhí)行對(duì)象哪個(gè)方法的代碼的能力。6.10理解多態(tài)將方法調(diào)用與方法體關(guān)聯(lián)起
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 賓館監(jiān)控系統(tǒng)設(shè)計(jì)方案樣本
- 2025屆江蘇省蔣王中學(xué)高一化學(xué)第二學(xué)期期末預(yù)測(cè)試題含解析
- 居民認(rèn)領(lǐng)樹(shù)苗活動(dòng)方案
- 岳陽(yáng)電玩城活動(dòng)方案
- 工會(huì)立冬活動(dòng)方案
- 小學(xué)遺體捐獻(xiàn)活動(dòng)方案
- 小學(xué)環(huán)境教育活動(dòng)方案
- 小孩影樓活動(dòng)方案
- 工程車(chē)買(mǎi)十送一活動(dòng)方案
- 幫扶家居門(mén)店活動(dòng)方案
- 乳腺癌患者靜脈管理
- 地球化學(xué)復(fù)習(xí)資料
- 《接觸網(wǎng)施工》課件 4.8.1 交叉線岔安裝
- 高速公路改擴(kuò)建工程實(shí)施性交通組織方案
- 藝術(shù)培訓(xùn)學(xué)校檔案管理制度(3篇)
- 校長(zhǎng)考核管理評(píng)價(jià)細(xì)則
- 風(fēng)電項(xiàng)目工程總承包合同
- 企業(yè)架構(gòu)數(shù)字化轉(zhuǎn)型規(guī)劃
- DB1306-T 232-2023 養(yǎng)老護(hù)理員職業(yè)技能規(guī)范
- 公寓股權(quán)合伙協(xié)議書(shū)
- 土壤酸化耕地治理方案(技術(shù)方案)
評(píng)論
0/150
提交評(píng)論