Java的面向?qū)ο缶幊袒靖拍顚W(xué)習(xí)筆記整理
個(gè)人理解,編程中所謂的 類¨ 與現(xiàn)實(shí)世界中對(duì)物體的分門別類中的類是同一個(gè)概念,只是在編程中將其借用進(jìn)來(lái)。類代表有一系列共性和相同操作或動(dòng)作的事物,在編程中即為抽象的數(shù)據(jù)類型。具體的每個(gè)個(gè)體(現(xiàn)實(shí)世界中)、實(shí)例變量(對(duì)于在編程中來(lái)說(shuō))就是對(duì)象。
類是現(xiàn)實(shí)世界某些對(duì)象的共同特征(屬性和操作)的表示,對(duì)象是類的實(shí)例。
類的屬性:就是類的靜態(tài)屬性的簡(jiǎn)稱,指類內(nèi)包含的各項(xiàng)數(shù)據(jù),如變量或其他類的對(duì)象;
類的服務(wù): 則被稱為成員函數(shù)或方法。
¨
Java中類的定義形式如下:
[修飾符] class 類名 [extends 父類] [implements 接口名] { 類成員變量聲明 類方法聲明 }
我們?cè)賮?lái)仔細(xì)說(shuō)說(shuō)這中間的每一個(gè)部分:
在class關(guān)鍵字前,也即類的修飾符有大體分三種類型——訪問(wèn)修飾符public公共類、final修飾符(最終類說(shuō)明符)和abstract修飾符(抽象類說(shuō)明符)
而其中,權(quán)限修飾符只能為public或默認(rèn)(即為空,什么都沒(méi)有,表示定義為友好的),public表示該類可被任何地方使用和訪問(wèn)(只要程序能找到該類位置),無(wú)論是在同一包內(nèi),還是在不同包。注意,這與C++中不同,C++中沒(méi)有還對(duì)類的訪問(wèn)權(quán)限用修飾符來(lái)限制的,而是對(duì)類之間的繼承關(guān)系有訪問(wèn)權(quán)限的說(shuō)明,除此之外,它們倒是都對(duì)類的屬性和方法有訪問(wèn)權(quán)限有限制。 默認(rèn)的訪問(wèn)權(quán)限(即定義為友好的),即是指只能被同一包內(nèi)的類引用和訪問(wèn),而不能被其它包中的類訪問(wèn)和引用,即使import進(jìn)去。
后面還會(huì)提到:以類的屬性和方法缺省修飾符時(shí),也表示為只能被同一包中的類引用和訪問(wèn)。
Java中不允許多重繼承,這與C++中不同,也算是為了彌補(bǔ)這個(gè)不足,Java中引進(jìn)了接口的概念。
上述類的定義中,類體中主要是類的具體內(nèi)容,包括類的屬性和類的方法。類的屬性可以是簡(jiǎn)單變量,也可以是某些類的實(shí)例,如果是類的實(shí)例,可以如下定義:
[修飾符] 類名 對(duì)象名=new類名(參數(shù)列表);
在聲明對(duì)象和復(fù)雜變量時(shí),可以不在聲明時(shí)用創(chuàng)建,可以在以后的構(gòu)造函數(shù)中創(chuàng)建。
類中定義的方法通常起到兩種作用:一是圍繞著類的屬性進(jìn)行各種操作;二是與其他的類或?qū)ο筮M(jìn)行數(shù)據(jù)交流、消息傳遞等操作。
Java中聲明方法的語(yǔ)法如下:
[修飾符] 返回值類型 方法名(參數(shù)列表) throws 例外名1,例外名2,… { 方法體: 局部變量聲明; 語(yǔ)句序列; }
類的方法,又稱為成員函數(shù),用來(lái)規(guī)定類屬性上的操作,實(shí)現(xiàn)類的內(nèi)部功能的機(jī)制,同時(shí)也是類與外界進(jìn)行交互的重要窗口。
Java程序員把注意力放在創(chuàng)建稱為類的用戶自定義類型(user-definedtype)上,類也稱為程序員定義的類型(programmer-definedtype),每個(gè)類都含有數(shù)據(jù)和一組操作數(shù)據(jù)的方法,類中的數(shù)據(jù)部分稱為實(shí)例變量。用戶定義類型(即類)的實(shí)例稱為對(duì)象。
對(duì)象是類的一個(gè)實(shí)例,類是同種對(duì)象的抽象,是創(chuàng)建對(duì)象的模板。在程序中創(chuàng)建—個(gè)對(duì)象將在內(nèi)存中開(kāi)辟一塊空間,其中包括該對(duì)象的屬性和方法。創(chuàng)建對(duì)象使用關(guān)鍵字運(yùn)算符new。
構(gòu)造函數(shù)(可以對(duì)比C++中,與C++幾乎相同)
創(chuàng)建自己的構(gòu)造函數(shù)
•構(gòu)造函數(shù)的名字和類的名字是相同的。當(dāng)構(gòu)造Employee類的對(duì)象時(shí),此構(gòu)造函數(shù)被啟動(dòng),實(shí)例字段賦初值,在Java中,定義和初始化是統(tǒng)一的——兩者缺一不可。
例如,用下面的代碼創(chuàng)建Employee類的一個(gè)實(shí)例時(shí),
newEmployee (“James Bond”,100000,1950,1,1);
構(gòu)造函數(shù)的特點(diǎn)有:
(1)構(gòu)造函數(shù)和類具有相同的名字。
(2)一個(gè)類可以有多個(gè)構(gòu)造函數(shù)。
(3)構(gòu)造函數(shù)可以有0個(gè)、1個(gè)或多個(gè)參數(shù)。
(4)構(gòu)造函數(shù)沒(méi)有返回值。
(5)構(gòu)造函數(shù)總是和new運(yùn)算符一起被調(diào)用。
構(gòu)造函數(shù)的作用
(1)對(duì)象初始化
(2)引入更多的靈活度(變量賦值或更復(fù)雜的操作)
(3)Java中可以不定義構(gòu)造函數(shù)
Java中可以不定義構(gòu)造函數(shù),此時(shí)系統(tǒng)會(huì)自動(dòng)為該系統(tǒng)生成一個(gè)默認(rèn)的構(gòu)造函數(shù)。這個(gè)構(gòu)造函數(shù)的名字與類名相同,它沒(méi)有任何形式參數(shù),也不完成任何操作。
方法概述
Java程序是由一個(gè)個(gè)類定義組成的,類有兩個(gè)部分:屬性和方法。屬性描述類是什么,方法描述類做什么。任何對(duì)象都有獨(dú)立的內(nèi)存存儲(chǔ)它的屬性。類的所有的對(duì)象共享存貯在內(nèi)存的方法。
換言之:方法是類的主要組成部分。在一個(gè)類中,程序的作用體現(xiàn)在方法中。
方法即是JAVA創(chuàng)建一個(gè)有名字的子程序。一個(gè)主方法和若干個(gè)子方法構(gòu)成。主方法調(diào)用其他方法,其他方法間也可互相調(diào)用,同一個(gè)方法可被一個(gè)或多個(gè)方法調(diào)用任意次。
在一個(gè)方法中定義另一個(gè)方法將產(chǎn)生語(yǔ)法錯(cuò)誤。
(1)最好避免局部變量“屏蔽”實(shí)例變量,在一個(gè)類中不使用同名標(biāo)識(shí)符就可以做到這一點(diǎn);方法調(diào)用中參數(shù)用來(lái)傳遞數(shù)值、傳遞引用,同時(shí)方法還可以嵌套、遞歸調(diào)用。
(2)方法體中如果指定了非void的返回值類型,方法中就必須包含一條return語(yǔ)句保證任何情況下都有返回?cái)?shù)值,return語(yǔ)句后面不能跟任何表達(dá)式;
Java程序的基本結(jié)構(gòu)如下:
引入Java類庫(kù); 定義用戶類1 { 定義類1的若干變量或?qū)ο螅? 定義類1的方法1; 定義類1的方法2; … 定義類1的方法M1; } 定義用戶類2 { 定義類2的若干變量或?qū)ο螅? 定義類2的方法1; 定義類2的方法2; … 定義類2的方法M2 }
Java推出了“訪問(wèn)控制修飾符”的概念,允許庫(kù)創(chuàng)建者聲明哪些東西是客戶程序員可以使用的,哪些是不可使用的。
這種訪問(wèn)控制的級(jí)別在“最大訪問(wèn)”和“最小訪問(wèn)”的范圍之間,分別包括:public,“默認(rèn)”(無(wú)關(guān)鍵字),protected以及private。下面的列表說(shuō)明訪問(wèn)控制修飾符含義:
公共訪問(wèn)控制符public
用于類:
Java中類的訪問(wèn)控制符只有一個(gè):public,即公共的。一個(gè)類被聲明為公共類,表明它可以被所有的其他類所訪問(wèn)和引用,這里的訪問(wèn)和引用是指這個(gè)類作為整體是可見(jiàn)和可使用的,程序的其他部分可以創(chuàng)建這個(gè)類的對(duì)象、訪問(wèn)這個(gè)類內(nèi)部可見(jiàn)的成員變量和調(diào)用它的可見(jiàn)的方法。
一個(gè)類作為整體對(duì)程序的其他部分可見(jiàn),并不能代表類內(nèi)的所有屬性和方法也同時(shí)對(duì)程序的其他部分可見(jiàn),前者只是后者的必要條件,類的屬性和方法能否為所有其他類所訪問(wèn),還要看這些屬性和方法自己的訪問(wèn)控制符。
用于類內(nèi)屬性:
用public修飾的類內(nèi)屬性稱為公共屬性,若這個(gè)類是公共類則它可以被所有的其他類訪問(wèn)。
缺省訪問(wèn)控制符
用于類
假如一個(gè)類沒(méi)有訪問(wèn)控制符,說(shuō)明它具有缺省的訪問(wèn)控制特性。這種缺省的訪問(wèn)控制權(quán)規(guī)定該類只能被同一個(gè)包中的類訪問(wèn)和引用,而不可以被其他包中的類使用,這種訪問(wèn)特性稱為包訪問(wèn)性。通過(guò)聲明類的訪問(wèn)控制符可以使整個(gè)程序結(jié)構(gòu)清晰、嚴(yán)謹(jǐn),減少可能產(chǎn)生類間干擾和錯(cuò)誤。
用于類屬性
類內(nèi)的屬性和方法如果沒(méi)有訪問(wèn)控制符號(hào)來(lái)限定,也說(shuō)明它們具有包訪問(wèn)性。
3 私有訪問(wèn)控制符private
用private修飾的屬性或方法只能被該類自身所訪問(wèn)和修改,而不能被任何其他類,包括該類的子類,來(lái)獲取和引用
1). 私有數(shù)據(jù)
例如有三個(gè)實(shí)例字段,它們含有在Employee類的實(shí)例內(nèi)部被操作的數(shù)據(jù)。
private string name;
private double salary;
private Date hireDay;
private(私有的)關(guān)鍵字用來(lái)確??梢栽L問(wèn)這些實(shí)例字段的只能是Employee類本身的方法。
2).私有方法
在實(shí)現(xiàn)類時(shí),我們使所有的數(shù)據(jù)字段都是私有的,因?yàn)楣_(kāi)的數(shù)據(jù)是危險(xiǎn)的。對(duì)于方法又是什么情況呢 ?雖然大多數(shù)方法是公開(kāi)的,但是私有方法也經(jīng)常使用。這些方法只能被同一個(gè)分離的方法。
總起來(lái)說(shuō),在下面的情況下可以選擇私有方法:
(1)與類的使用者無(wú)關(guān)的那些方法。
(2)如果類的實(shí)現(xiàn)改變了,不容易維護(hù)的那些方法。
保護(hù)訪問(wèn)控制符protected
用protected修飾的成員變量可以被三種類所引用:該類自身、與它在同一個(gè)包中的其他類、在其他包中的該類的子類。使用protected修飾符的主要作用是允許其他包中的它的子類來(lái)訪問(wèn)父類的特定屬性。
protected關(guān)鍵字為我們引入了一種名為“繼承”的概念,它以現(xiàn)有的類為基礎(chǔ),并在其中加入新的成員,同時(shí)不會(huì)對(duì)現(xiàn)有的類產(chǎn)生影響——我們將這種現(xiàn)有的類稱為“基礎(chǔ)類”或者“基本類”(Base Class)。亦可改變那個(gè)類現(xiàn)有成員的行為。對(duì)于從一個(gè)現(xiàn)有類的繼承,我們說(shuō)自己的新類“擴(kuò)展”(extends)了那個(gè)現(xiàn)有的類
私有保護(hù)訪問(wèn)控制符private protected
private和protected按順序連用構(gòu)成一個(gè)完整的訪問(wèn)控制符:私有保護(hù)訪問(wèn)控制符。用privateprotected修飾的成員變量可以被兩種類訪問(wèn)和引用,一種是該類本身,一種是該類的所有子類,不論這些子類是與該類在同一個(gè)包里,還是處于其他的包中。
相對(duì)于protected,privateprotected修飾符把同一包內(nèi)的非子類排除在可訪問(wèn)的范圍之外,使得成員變量更專有于具有明確繼承關(guān)系的類,而不是松散地組合在一起的包。
靜態(tài)修飾符
static稱為靜態(tài)修飾符,它可以修飾類中的屬性和方法。
使用static(靜態(tài))關(guān)鍵字,可滿足兩方面的要求:
(1)一種情形是只想用一個(gè)存儲(chǔ)區(qū)域來(lái)保存一個(gè)特定的數(shù)據(jù)——無(wú)論要?jiǎng)?chuàng)建多少個(gè)對(duì)象,甚至根本不創(chuàng)建對(duì)象;被static修飾的屬性稱為靜態(tài)屬性,這類屬性一個(gè)最本質(zhì)的特點(diǎn)是:它們是類的屬性,而不屬于任何一個(gè)類的具體對(duì)象。換句話說(shuō),對(duì)于該類的任何一個(gè)具體對(duì)象而言,靜態(tài)屬性是一個(gè)公共的存儲(chǔ)單元,任何一個(gè)類的對(duì)象訪問(wèn)它時(shí),取到的都是相同的數(shù)值,同樣任何一個(gè)類的對(duì)象去修改它時(shí),也都是在對(duì)同一個(gè)內(nèi)存單元做操作。
(2)另一種情形是我們需要一個(gè)特殊的方法,它沒(méi)有與這個(gè)類的任何對(duì)象關(guān)聯(lián)。也就是說(shuō),即使沒(méi)有創(chuàng)建對(duì)象,也需要一個(gè)能用類直接調(diào)用的方法。
static一項(xiàng)重要的用途就是幫助我們?cè)诓槐貏?chuàng)建對(duì)象的前提下調(diào)用那個(gè)方法。
靜態(tài)常量
靜態(tài)變量是很少見(jiàn)的。然而,靜態(tài)常量卻很普遍。例如,Math類中定義了一個(gè)靜態(tài)常量:
public class Math
{ …… public static final double PI=3.1.4159265358979323846; …… }
靜態(tài)方法
聲明一個(gè)方法為static至少有三重含義:
(1)使用這個(gè)方法時(shí),應(yīng)該使用類名做前綴,而不是某一個(gè)具體的對(duì)象名;
(2)非static的方法是屬于某個(gè)對(duì)象的方法,在這個(gè)對(duì)象創(chuàng)建時(shí)對(duì)象的方法在內(nèi)存中擁有自己專用的代碼段;而static的方法是屬于整個(gè)類的,它在內(nèi)存中的代碼段將隨著類的定義而分配和裝載,不被任何一個(gè)對(duì)象專有;
(3)由于static方法是屬于整個(gè)類的,所以它不能操縱和處理屬于某個(gè)對(duì)象的成員變量,而只能處理屬于整個(gè)類的成員變量。
5 main方法
main方法并不對(duì)任何對(duì)象施加操作。實(shí)際上,當(dāng)程序開(kāi)始執(zhí)行時(shí),還不存在任何對(duì)象。靜態(tài)方法被執(zhí)行,并構(gòu)造程序所需的對(duì)象。
提示 每個(gè)類都可以有一個(gè)main方法。這是對(duì)類進(jìn)行單元測(cè)試的一個(gè)很方便技巧。
abstract是抽象修飾符,可以用來(lái)修飾類或方法。
抽象類
當(dāng)一個(gè)類被聲明為abstract時(shí),這個(gè)類被稱為是抽象類。所謂抽象類就是沒(méi)有具體實(shí)例對(duì)象的類。
針對(duì)這個(gè)問(wèn)題,Java專門提供了一種機(jī)制,名為“抽象方法”。它屬于一種不完整的方法,只含有一個(gè)聲明,沒(méi)有方法主體。下面是抽象方法聲明時(shí)采用的語(yǔ)法:
abstract void X();
抽象方法
作為類方法修飾符,abstract則聲明了一種僅有方法頭,而沒(méi)有具體的方法體和操作實(shí)現(xiàn)的抽象方法。
可見(jiàn),abstract方法只有方法頭的聲明,而用一個(gè)分號(hào)來(lái)代替方法體的定義:至于方法體的具體實(shí)現(xiàn),那是由當(dāng)前類的不同子類在它們各自的類定義中完成的。
需要特別注意的是,所有的抽象方法,都必須存在于抽象類之
中。
除了抽象方法,抽象類也可以有具體的數(shù)據(jù)和方法。
在Java編程語(yǔ)言中抽象方法是非常重要的概念。在接口里你會(huì)大量的用到它。
注意:這里要與接口進(jìn)行對(duì)比、記憶,接口中的方法都屬于抽象方法,當(dāng)然,接口中也有屬性,其具體性質(zhì)將在后文詳述。
最終類、最終屬性、最終方法與終結(jié)器(C++中可沒(méi)有final最終修飾符)
final是最終修飾符,它可以修飾類、屬性和方法。另外終結(jié)器的關(guān)鍵字與final很相近,一并介紹
最終類
如果一個(gè)類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承。因此一個(gè)類不能既被聲明為abstract的,又被聲明為final的。
被定義成final的類,通常是一些有特殊作用的、用來(lái)完成標(biāo)準(zhǔn)功能的類,將一個(gè)類定義為final則可以將它的內(nèi)容、屬性和功能固定下來(lái),與它的類名形成穩(wěn)定的映射關(guān)系,從而保證引用這個(gè)類時(shí)所實(shí)現(xiàn)的功能是準(zhǔn)確無(wú)誤的
最終屬性
許多程序設(shè)計(jì)語(yǔ)言都有自己的辦法告訴編譯器某個(gè)數(shù)據(jù)是“常數(shù)”。常數(shù)主要應(yīng)用于下述兩個(gè)方面:
(1)編譯期常數(shù),它永遠(yuǎn)不會(huì)改變;
(2)在運(yùn)行期初始化的一個(gè)值,我們不希望它發(fā)生變化。
可以把一個(gè)實(shí)例字段定義為final(不能改變的)。在對(duì)象被構(gòu)造時(shí),這種字段必須被初始化。即,必須保證在每一個(gè)構(gòu)造函數(shù)結(jié)束之前其值已被設(shè)定。以后字段的值不能改變
最終方法
之所以要使用final方法,可能是出于對(duì)兩方面理由的考慮。
第一個(gè)是為方法“上鎖”,防止任何繼承類改變它的本來(lái)含義。設(shè)計(jì)程序時(shí),若希望一個(gè)方法的行為在繼承期間保持不變,而且不可被覆蓋或改寫(xiě),就可以采取這種做法。
采用final方法的第二個(gè)理由是程序執(zhí)行的效率
終結(jié)器
終結(jié)器的作用是回收對(duì)象時(shí)執(zhí)行的方法。類似與構(gòu)造函數(shù)是創(chuàng)建對(duì)象時(shí)執(zhí)行的方法一樣。
例
protected voidfinalize(){ System.out.println(“ “); }
其它修飾符
volatile
如果一個(gè)屬性被volatile修飾,說(shuō)明這個(gè)屬性可以同時(shí)被幾個(gè)線程所控制和修改。
synchronized
主要用于線程同步
native
表示該方法不是用java語(yǔ)言寫(xiě)成的(是用C,C++等語(yǔ)言寫(xiě)的)
網(wǎng)上查到的一點(diǎn)資料:——內(nèi)部類
簡(jiǎn)單的說(shuō),內(nèi)部類就是類中的類,舉個(gè)例子:
class A { private int i; private void m() { } class B { mm(int j) { i = j; m(); } } }
這里,B就是A的內(nèi)部類
內(nèi)部類的特點(diǎn)就是,可以方便的訪問(wèn)外部類里面的私有方法和屬性,比如,這里B里面可以直接訪問(wèn)A里面的私有屬性i,和私有方法m()
面向?qū)ο缶幊套钪匾奶卣骶褪欠庋b性(也可稱作抽象性)、繼承性和多態(tài)性,那么,作為面向?qū)ο缶幊陶Z(yǔ)言,Java在這方面更是有其出色之處:
“繼承性是軟件復(fù)用的一種形式,對(duì)降低軟件復(fù)雜性行之有效。繼承性同時(shí)是面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言的特點(diǎn),采用對(duì)象但沒(méi)有繼承性的語(yǔ)言是基于對(duì)象的語(yǔ)言,但不是面向?qū)ο蟮恼Z(yǔ)言,這是兩者的區(qū)別”
類之間的繼承關(guān)系是現(xiàn)實(shí)世界中遺傳關(guān)系的直接模擬,它表示類之間的內(nèi)在聯(lián)系以及對(duì)屬性和操作的共享,即子類可以沿用父類(被繼承類)的某些特征。當(dāng)然,子類也可以具有自己獨(dú)立的屬性和操作
繼承性是軟件復(fù)用的一種形式。新類由已存在的類生成,通過(guò)保留它們的屬性和行為,并且根據(jù)新類的要求對(duì)性能加以修改,添加新的屬性和行為。如果子類只從一個(gè)父類繼承,則稱為單繼承;如果子類從一個(gè)以上父類繼承,則稱為多繼承。注意Java不支持多重繼承,但它支持“接口”概念。接口使Java獲得了多重繼承的許多優(yōu)點(diǎn),摒棄了相應(yīng)的缺點(diǎn)。注意:C++支持多繼承
繼承關(guān)系的定義:
[修飾符]class子類名 extends父類名,父類名2
父類名跟在extends
關(guān)鍵字后面,用來(lái)說(shuō)明當(dāng)前類是哪個(gè)已經(jīng)存在類的子類,存在繼承關(guān)系。
定義 雇員類 Employee的兩個(gè)子類:
一般雇員類:CommonEmployee
主 管 類:ManagerEmployee
子類從父類繼承有兩個(gè)主要的方面:
(1)屬性的繼承。例如,公司是一個(gè)父類,一個(gè)公司有名稱、地址、經(jīng)理、雇員等,這些都屬于結(jié)構(gòu)方面。
(2)方法的繼承。一個(gè)父類定義了若干操作,如一個(gè)公司要有項(xiàng)目、利潤(rùn)、任命經(jīng)理、錄用職工等操作,子公司也將繼承這些行為s;mp
classCommonEmployeeextends Employee//子類1: { intm_ManagerNo ;//定義類屬性m _ManagerNo,代表雇員上司的編號(hào) } classManagerEmployeeextends Employee //子類2: { intm_SecretaryNo; //定義類屬性m_SecretaryNo,代表秘書(shū)的編號(hào) }
屬性繼承與隱藏
盡管Employee類是一個(gè)父類,但是并不因?yàn)樗歉割惥鸵馕吨懈嗟墓δ?。恰恰相反,子類比它們的父類具有更多的功能。因?yàn)樽宇愂歉割惖臄U(kuò)展,增加了父類沒(méi)有的屬性和方法
(1)子類不能訪問(wèn)父類的private成員,但子類可以訪問(wèn)其父類的public,
(2)protected訪問(wèn)是public和private訪問(wèn)之間一個(gè)保護(hù)性的中間層次。
(3)由于被繼承的父類成員沒(méi)有在子類聲明中列出,但是這些成員確實(shí)存在于子類中。
在這里,要區(qū)分一下繼承、覆蓋與重載這幾個(gè)易混淆的概念:
只有方法這一概念層面,這三個(gè)概念才易混淆:
方法繼承
對(duì)于子類對(duì)象,可以使用父類中的方法。即使這些方法沒(méi)有明顯地在子類中定義,它們也自動(dòng)地從父類中繼承過(guò)來(lái)了
方法覆蓋
方法的覆蓋是指:子類定義同名方法來(lái)覆蓋父類的方法,是多態(tài)技術(shù)的一個(gè)實(shí)現(xiàn)。當(dāng)父類方法在子類中被覆蓋時(shí),通常是子類版本調(diào)用父類版本,并做一些附加的工作。
有很多注意事項(xiàng),這里,我主要提一下this與super,C++中有this(且與Java中中概念差不多),但是沒(méi)有super。
this表示的是當(dāng)前對(duì)象本身,this代表當(dāng)前對(duì)象的一個(gè)引用??梢岳斫鉃閷?duì)象的另一個(gè)名字。利用this可以調(diào)用當(dāng)前對(duì)象的方法和屬性。
如:this.getName()和getName()在類中是一樣的。
super表示的是當(dāng)前對(duì)象的直接父類對(duì)象,是當(dāng)前對(duì)象的父類對(duì)象的引用
方法重載
重載的定義:可以用相同的方法名但不同的參數(shù)表來(lái)定義方法(參數(shù)表中參數(shù)的數(shù)量、類型或次序有差異),這稱為方法重載。
•重載(overloading):當(dāng)多個(gè)方法具有相同的名字而含有不同的參數(shù)時(shí),便發(fā)生重載。編譯器必須挑選處調(diào)用哪個(gè)方法。它通過(guò)將在不同方法頭部中的參數(shù)類型和在特定的方法調(diào)用中使用值的類型進(jìn)行比較,從而挑選出正確的方法。
多態(tài)性允許以統(tǒng)一的風(fēng)格處理已存在的變量及相關(guān)的類,使增加系統(tǒng)中新功能變得容易。這里,貼一下網(wǎng)上找的資料,能更清楚地將繼承中需特別注意的多態(tài)、繼承中的問(wèn)題弄清:
Java的多態(tài)性
面向?qū)ο缶幊逃腥齻€(gè)特征,即封裝、繼承和多態(tài)。
封裝隱藏了類的內(nèi)部實(shí)現(xiàn)機(jī)制,從而可以在不影響使用者的前提下改變類的內(nèi)部結(jié)構(gòu),同時(shí)保護(hù)了數(shù)據(jù)。
繼承是為了重用父類代碼,同時(shí)為實(shí)現(xiàn)多態(tài)性作準(zhǔn)備。那么什么是多態(tài)呢?
方法的重寫(xiě)、重載與動(dòng)態(tài)連接構(gòu)成多態(tài)性。Java之所以引入多態(tài)的概念,原因之一是它在類的繼承問(wèn)題上和C++不同,后者允許多繼承,這確實(shí)給其帶來(lái)的非常強(qiáng)大的功能,但是復(fù)雜的繼承關(guān)系也給C++開(kāi)發(fā)者帶來(lái)了更大的麻煩,為了規(guī)避風(fēng)險(xiǎn),Java只允許單繼承,派生類與基類間有IS-A的關(guān)系(即“貓”is a “動(dòng)物”)。這樣做雖然保證了繼承關(guān)系的簡(jiǎn)單明了,但是勢(shì)必在功能上有很大的限制,所以,Java引入了多態(tài)性的概念以彌補(bǔ)這點(diǎn)的不足,此外,抽象類和接口也是解決單繼承規(guī)定限制的重要手段。同時(shí),多態(tài)也是面向?qū)ο缶幊痰木杷凇?/p>
要理解多態(tài)性,首先要知道什么是“向上轉(zhuǎn)型”。
我定義了一個(gè)子類Cat,它繼承了Animal類,那么后者就是前者是父類。我可以通過(guò)
Cat c = new Cat();
實(shí)例化一個(gè)Cat的對(duì)象,這個(gè)不難理解。但當(dāng)我這樣定義時(shí):
Animal a = new Cat();
這代表什么意思呢?
很簡(jiǎn)單,它表示我定義了一個(gè)Animal類型的引用,指向新建的Cat類型的對(duì)象。由于Cat是繼承自它的父類Animal,所以Animal類型的引用是可以指向Cat類型的對(duì)象的。那么這樣做有什么意義呢?因?yàn)樽宇愂菍?duì)父類的一個(gè)改進(jìn)和擴(kuò)充,所以一般子類在功能上較父類更強(qiáng)大,屬性較父類更獨(dú)特,
定義一個(gè)父類類型的引用指向一個(gè)子類的對(duì)象既可以使用子類強(qiáng)大的功能,又可以抽取父類的共性。
所以,父類類型的引用可以調(diào)用父類中定義的所有屬性和方法,而對(duì)于子類中定義而父類中沒(méi)有的方法,它是無(wú)可奈何的;
同時(shí),父類中的一個(gè)方法只有在在父類中定義而在子類中沒(méi)有重寫(xiě)的情況下,才可以被父類類型的引用調(diào)用;
對(duì)于父類中定義的方法,如果子類中重寫(xiě)了該方法,那么父類類型的引用將會(huì)調(diào)用子類中的這個(gè)方法,這就是動(dòng)態(tài)連接。
看下面這段程序:
class Father{ public void func1(){ func2(); } //這是父類中的func2()方法,因?yàn)橄旅娴淖宇愔兄貙?xiě)了該方法 //所以在父類類型的引用中調(diào)用時(shí),這個(gè)方法將不再有效 //取而代之的是將調(diào)用子類中重寫(xiě)的func2()方法 public void func2(){ System.out.println("AAA"); } } class Child extends Father{ //func1(int i)是對(duì)func1()方法的一個(gè)重載 //由于在父類中沒(méi)有定義這個(gè)方法,所以它不能被父類類型的引用調(diào)用 //所以在下面的main方法中child.func1(68)是不對(duì)的 public void func1(int i){ System.out.println("BBB"); } //func2()重寫(xiě)了父類Father中的func2()方法 //如果父類類型的引用中調(diào)用了func2()方法,那么必然是子類中重寫(xiě)的這個(gè)方法 public void func2(){ System.out.println("CCC"); } } public class PolymorphismTest { public static void main(String[] args) { Father child = new Child(); child.func1();//打印結(jié)果將會(huì)是什么? } }
上面的程序是個(gè)很典型的多態(tài)的例子。子類Child繼承了父類Father,并重載了父類的func1()方法,重寫(xiě)了父類的func2()方法。重載后的func1(int i)和func1()不再是同一個(gè)方法,由于父類中沒(méi)有func1(int i),那么,父類類型的引用child就不能調(diào)用func1(int i)方法。而子類重寫(xiě)了func2()方法,那么父類類型的引用child在調(diào)用該方法時(shí)將會(huì)調(diào)用子類中重寫(xiě)的func2()。
那么該程序?qū)?huì)打印出什么樣的結(jié)果呢?
很顯然,應(yīng)該是“CCC”。
對(duì)于多態(tài),可以總結(jié)它為:
(1)使用父類類型的引用指向子類的對(duì)象(實(shí)際對(duì)象);
(2)該引用只能調(diào)用父類中定義的方法和變量;
(3)如果子類中重寫(xiě)了父類中的一個(gè)方法,那么在調(diào)用這個(gè)方法的時(shí)候,將會(huì)調(diào)用子類中的這個(gè)方法;(動(dòng)態(tài)連接、動(dòng)態(tài)調(diào)用)
(4)變量不能被重寫(xiě)(覆蓋),”重寫(xiě)“的概念只針對(duì)方法,如果在子類中”重寫(xiě)“了父類中的變量,那么在編譯時(shí)會(huì)報(bào)錯(cuò)。
多態(tài)是通過(guò):
(1) 接口 和 實(shí)現(xiàn)接口并覆蓋接口中同一方法的幾個(gè)不同的類體現(xiàn)的
(2) 父類 和 繼承父類并覆蓋父類中同一方法的幾個(gè)不同子類實(shí)現(xiàn)的.
1.基本概念
多態(tài)性:發(fā)送消息給某個(gè)對(duì)象,讓該對(duì)象自行決定響應(yīng)何種行為。
通過(guò)將子類對(duì)象引用賦值給超類對(duì)象引用變量來(lái)實(shí)現(xiàn)動(dòng)態(tài)方法調(diào)用。
ava 的這種機(jī)制遵循一個(gè)原則:當(dāng)超類對(duì)象引用變量引用子類對(duì)象時(shí),被引用對(duì)象的類型而不是引用變量的類型決定了調(diào)用誰(shuí)的成員方法,但是這個(gè)被調(diào)用的方法必須是在超類中定義過(guò)的,也就是說(shuō)被子類覆蓋的方法。
(1)如果a是類A的一個(gè)引用,那么,a可以指向類A的一個(gè)實(shí)例,或者說(shuō)指向類A的一個(gè)子類。
(2)如果a是接口A的一個(gè)引用,那么,a必須指向?qū)崿F(xiàn)了接口A的一個(gè)類的實(shí)例。
Java多態(tài)性實(shí)現(xiàn)機(jī)制
SUN目前的JVM實(shí)現(xiàn)機(jī)制,類實(shí)例的引用就是指向一個(gè)句柄(handle)的指針,這個(gè)句柄是一對(duì)指針:
一個(gè)指針指向一張表格,實(shí)際上這個(gè)表格也有兩個(gè)指針(一個(gè)指針指向一個(gè)包含了對(duì)象的方法表,另外一個(gè)指向類對(duì)象,表明該對(duì)象所屬的類型);
另一個(gè)指針指向一塊從java堆中為分配出來(lái)內(nèi)存空間。
總結(jié)
(1)通過(guò)將子類對(duì)象引用賦值給超類對(duì)象引用變量來(lái)實(shí)現(xiàn)動(dòng)態(tài)方法調(diào)用。
DerivedC c2=new DerivedC(); BaseClass a1= c2; //BaseClass 基類,DerivedC是繼承自BaseClass的子類 a1.play(); //play()在BaseClass,DerivedC中均有定義,即子類覆寫(xiě)了該方法
分析:
* 為什么子類的類型的對(duì)象實(shí)例可以覆給超類引用?
自動(dòng)實(shí)現(xiàn)向上轉(zhuǎn)型。通過(guò)該語(yǔ)句,編譯器自動(dòng)將子類實(shí)例向上移動(dòng),成為通用類型BaseClass;
* a.play()將執(zhí)行子類還是父類定義的方法?
子類的。在運(yùn)行時(shí)期,將根據(jù)a這個(gè)對(duì)象引用實(shí)際的類型來(lái)獲取對(duì)應(yīng)的方法。所以才有多態(tài)性。一個(gè)基類的對(duì)象引用,被賦予不同的子類對(duì)象引用,執(zhí)行該方法時(shí),將表現(xiàn)出不同的行為。
在a1=c2的時(shí)候,仍然是存在兩個(gè)句柄,a1和c2,但是a1和c2擁有同一塊數(shù)據(jù)內(nèi)存塊和不同的函數(shù)表。
(2)不能把父類對(duì)象引用賦給子類對(duì)象引用變量
BaseClass a2=new BaseClass(); DerivedC c1=a2;//出錯(cuò)
在java里面,向上轉(zhuǎn)型是自動(dòng)進(jìn)行的,但是向下轉(zhuǎn)型卻不是,需要我們自己定義強(qiáng)制進(jìn)行。
c1=(DerivedC)a2; 進(jìn)行強(qiáng)制轉(zhuǎn)化,也就是向下轉(zhuǎn)型.
(3)記住一個(gè)很簡(jiǎn)單又很復(fù)雜的規(guī)則,一個(gè)類型引用只能引用引用類型自身含有的方法和變量。
你可能說(shuō)這個(gè)規(guī)則不對(duì)的,因?yàn)楦割愐弥赶蜃宇悓?duì)象的時(shí)候,最后執(zhí)行的是子類的方法的。
其實(shí)這并不矛盾,那是因?yàn)椴捎昧撕笃诮壎?,?dòng)態(tài)運(yùn)行的時(shí)候又根據(jù)型別去調(diào)用了子類的方法。而假若子類的這個(gè)方法在父類中并沒(méi)有定義,則會(huì)出錯(cuò)。
例如,DerivedC類在繼承BaseClass中定義的函數(shù)外,還增加了幾個(gè)函數(shù)(例如 myFun())
分析:
當(dāng)你使用父類引用指向子類的時(shí)候,其實(shí)jvm已經(jīng)使用了編譯器產(chǎn)生的類型信息調(diào)整轉(zhuǎn)換了。
這里你可以這樣理解,相當(dāng)于把不是父類中含有的函數(shù)從虛擬函數(shù)表中設(shè)置為不可見(jiàn)的。注意有可能虛擬函數(shù)表中有些函數(shù)地址由于在子類中已經(jīng)被改寫(xiě)了,所以對(duì)象虛擬函數(shù)表中虛擬函數(shù)項(xiàng)目地址已經(jīng)被設(shè)置為子類中完成的方法體的地址了。
(4)Java與C++多態(tài)性的比較
jvm關(guān)于多態(tài)性支持解決方法是和c++中幾乎一樣的,
只是c++中編譯器很多是把類型信息和虛擬函數(shù)信息都放在一個(gè)虛擬函數(shù)表中,但是利用某種技術(shù)來(lái)區(qū)別。
Java把類型信息和函數(shù)信息分開(kāi)放。Java中在繼承以后,子類會(huì)重新設(shè)置自己的虛擬函數(shù)表,這個(gè)虛擬函數(shù)表中的項(xiàng)目有由兩部分組成。從父類繼承的虛擬函數(shù)和子類自己的虛擬函數(shù)。
虛擬函數(shù)調(diào)用是經(jīng)過(guò)虛擬函數(shù)表間接調(diào)用的,所以才得以實(shí)現(xiàn)多態(tài)的。
Java的所有函數(shù),除了被聲明為final的,都是用后期綁定。
1個(gè)行為,不同的對(duì)象,他們具體體現(xiàn)出來(lái)的方式不一樣,
比如: 方法重載 overloading 以及 方法重寫(xiě)(覆蓋)override
class Human{ void run(){輸出 人在跑} } class Man extends Human{ void run(){輸出 男人在跑} } 這個(gè)時(shí)候,同是跑,不同的對(duì)象,不一樣(這個(gè)是方法覆蓋的例子) class Test{ void out(String str){輸出 str} void out(int i){輸出 i} }
這個(gè)例子是方法重載,方法名相同,參數(shù)表不同
ok,明白了這些還不夠,還用人在跑舉例
Human ahuman=new Man();
這樣我等于實(shí)例化了一個(gè)Man的對(duì)象,并聲明了一個(gè)Human的引用,讓它去指向Man這個(gè)對(duì)象
意思是說(shuō),把 Man這個(gè)對(duì)象當(dāng) Human看了.
比如去動(dòng)物園,你看見(jiàn)了一個(gè)動(dòng)物,不知道它是什么, "這是什么動(dòng)物? " "這是大熊貓! "
這2句話,就是最好的證明,因?yàn)椴恢浪谴笮茇?但知道它的父類是動(dòng)物,所以,
這個(gè)大熊貓對(duì)象,你把它當(dāng)成其父類 動(dòng)物看,這樣子合情合理.
這種方式下要注意 new Man();的確實(shí)例化了Man對(duì)象,所以 ahuman.run()這個(gè)方法 輸出的 是 "男人在跑 "
如果在子類 Man下你 寫(xiě)了一些它獨(dú)有的方法 比如 eat(),而Human沒(méi)有這個(gè)方法,
在調(diào)用eat方法時(shí),一定要注意 強(qiáng)制類型轉(zhuǎn)換 ((Man)ahuman).eat(),這樣才可以...
對(duì)接口來(lái)說(shuō),情況是類似的...
實(shí)例:
package domatic; //定義超類superA class superA { int i = 100; void fun(int j) { j = i; System.out.println("This is superA"); } } // 定義superA的子類subB class subB extends superA { int m = 1; void fun(int aa) { System.out.println("This is subB"); } } // 定義superA的子類subC class subC extends superA { int n = 1; void fun(int cc) { System.out.println("This is subC"); } } class Test { public static void main(String[] args) { superA a = new superA(); subB b = new subB(); subC c = new subC(); a = b; a.fun(100); a = c; a.fun(200); } }
/*
* 上述代碼中subB和subC是超類superA的子類,我們?cè)陬怲est中聲明了3個(gè)引用變量a, b,
* c,通過(guò)將子類對(duì)象引用賦值給超類對(duì)象引用變量來(lái)實(shí)現(xiàn)動(dòng)態(tài)方法調(diào)用。也許有人會(huì)問(wèn):
* "為什么(1)和(2)不輸出:This is superA"。
* java的這種機(jī)制遵循一個(gè)原則:當(dāng)超類對(duì)象引用變量引用子類對(duì)象時(shí),
* 被引用對(duì)象的類型而不是引用變量的類型決定了調(diào)用誰(shuí)的成員方法,
* 但是這個(gè)被調(diào)用的方法必須是在超類中定義過(guò)的,
* 也就是說(shuō)被子類覆蓋的方法。
* 所以,不要被上例中(1)和(2)所迷惑,雖然寫(xiě)成a.fun(),但是由于(1)中的a被b賦值,
* 指向了子類subB的一個(gè)實(shí)例,因而(1)所調(diào)用的fun()實(shí)際上是子類subB的成員方法fun(),
* 它覆蓋了超類superA的成員方法fun();同樣(2)調(diào)用的是子類subC的成員方法fun()。
* 另外,如果子類繼承的超類是一個(gè)抽象類,雖然抽象類不能通過(guò)new操作符實(shí)例化,
* 但是可以創(chuàng)建抽象類的對(duì)象引用指向子類對(duì)象,以實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)性。具體的實(shí)現(xiàn)方法同上例。
* 不過(guò),抽象類的子類必須覆蓋實(shí)現(xiàn)超類中的所有的抽象方法,
* 否則子類必須被abstract修飾符修飾,當(dāng)然也就不能被實(shí)例化了
*/
以上大多數(shù)是以子類覆蓋父類的方法實(shí)現(xiàn)多態(tài).下面是另一種實(shí)現(xiàn)多態(tài)的方法-----------重寫(xiě)父類方法
JAVA里沒(méi)有多繼承,一個(gè)類之能有一個(gè)父類。而繼承的表現(xiàn)就是多態(tài)。一個(gè)父類可以有多個(gè)子類,而在子類里可以重寫(xiě)父類的方法(例如方法print()),這樣每個(gè)子類里重寫(xiě)的代碼不一樣,自然表現(xiàn)形式就不一樣。這樣用父類的變量去引用不同的子類,在調(diào)用這個(gè)相同的方法print()的時(shí)候得到的結(jié)果和表現(xiàn)形式就不一樣了,這就是多態(tài),相同的消息(也就是調(diào)用相同的方法)會(huì)有不同的結(jié)果。舉例說(shuō)明:
//父類 public class Father{ //父類有一個(gè)打孩子方法 public void hitChild(){ } } //子類1 public class Son1 extends Father{ //重寫(xiě)父類打孩子方法 public void hitChild(){ System.out.println("為什么打我?我做錯(cuò)什么了!"); } } //子類2 public class Son2 extends Father{ //重寫(xiě)父類打孩子方法 public void hitChild(){ System.out.println("我知道錯(cuò)了,別打了!"); } } //子類3 public class Son3 extends Father{ //重寫(xiě)父類打孩子方法 public void hitChild(){ System.out.println("我跑,你打不著!"); } } //測(cè)試類 public class Test{ public static void main(String args[]){ Father father; father = new Son1(); father.hitChild(); father = new Son2(); father.hitChild(); father = new Son3(); father.hitChild(); } }
都調(diào)用了相同的方法,出現(xiàn)了不同的結(jié)果!這就是多態(tài)的表現(xiàn)!
import java.io.*; class Super{ Super(){ System.out.println("This is super class!"); } void method(){ System.out.println("Super's method"); } } class Sub extends Super{ Sub(){ super(); System.out.println("\n\t:and here is the child"); } void method(){ System.out.println("child's method"); } } public class Super_Sub{ public static void main(String[] args){ Super sup=new Sub(); sup.method(); Sub child=(Sub)new Super();//這里,實(shí)際分配的內(nèi)存是Super的,但是卻用Child來(lái)指代它,這就是“向下轉(zhuǎn)型”(父類冒充子類,因?yàn)樽宇愒赨ML中畫(huà)時(shí)是在下的嘛),必經(jīng)強(qiáng)制類型轉(zhuǎn)換 child.method(); } }
對(duì)于數(shù)據(jù)來(lái)說(shuō),繼承是否為正確的設(shè)計(jì)可以用一個(gè)簡(jiǎn)單的規(guī)則來(lái)判斷?!癷s-a”規(guī)則表明子類的每一個(gè)對(duì)象都是一個(gè)超類的對(duì)象。例如,每一個(gè)經(jīng)理是一個(gè)員工。然而,只有經(jīng)理類是員工類的子類才是有意義的。很明顯,反過(guò)來(lái)就不行了——并不是每個(gè)員工都是經(jīng)理。
還有一個(gè)明確敘述“is-a”規(guī)則的方法是替代原則。該原則規(guī)定無(wú)論何時(shí),如果程序需要一個(gè)超類對(duì)象,都可以用一個(gè)子類對(duì)象來(lái)代替
動(dòng)態(tài)綁定
理解調(diào)用一個(gè)對(duì)象方法的機(jī)制是非常重要的。下面具體介紹:X.f;
(1)編譯器檢查對(duì)象的聲明類型和方法名。
(2)接著,編譯器檢查方法調(diào)用中的參數(shù)類型。如果在所有的叫做f的方法中有一個(gè)其參數(shù)類型同調(diào)用提供的參數(shù)類型最匹配,那么該方法就會(huì)被選擇調(diào)用。這個(gè)過(guò)程稱作超載選擇。(靜態(tài))
(3)當(dāng)程序運(yùn)行并且使用動(dòng)態(tài)綁定來(lái)調(diào)用一個(gè)方法時(shí),那么虛擬機(jī)必須調(diào)用同x所指向的對(duì)象的實(shí)際類型相匹配的方法版本。
……
如果類中沒(méi)有寫(xiě)構(gòu)造函數(shù),那么系統(tǒng)會(huì)自動(dòng)為該類提供一個(gè)默認(rèn)構(gòu)造函數(shù),該構(gòu)造函數(shù)將所有的實(shí)例字段初始化為默認(rèn)值:
……
包用途:
Java允許把多個(gè)類收集在一起成為一組,稱作包(package)。包便于組織任務(wù),以及使自己的任務(wù)和其他人提供的代碼庫(kù)相分離。
標(biāo)準(zhǔn)Java庫(kù)被分類成許多的包,其中包括java.1ang、java.util和java.net等等。標(biāo)準(zhǔn)Java包是分層次的。就像在硬盤(pán)上嵌套有各級(jí)子目錄一樣,可以通過(guò)層次嵌套組織包。所有的Java包都在Java和Javax包層次內(nèi)
創(chuàng)建包
已經(jīng)看到,已有的庫(kù),比如JavaAPI中的類和接口,可以導(dǎo)入到Java程序中。
Java API中的每一個(gè)類和接口屬于一個(gè)特定的包。它包含一組相關(guān)聯(lián)的類和接口,實(shí)際是對(duì)類和接口進(jìn)行組織的目錄結(jié)構(gòu)。
例如,假定文件名是MyClass.java。它意味著在那個(gè)文件有一個(gè)、而且只能有一個(gè)public類。而且那個(gè)類的名字必須是MyClass(包括大小寫(xiě)形式):
packagemypackage; publicclass MyClass { …… }
創(chuàng)建可復(fù)用的類的步驟簡(jiǎn)要說(shuō)明如下:
(1)定義一個(gè)public類。如果類不是public,它只能被同一包中的其他類使用。
(2)選擇一個(gè)包名,并把package語(yǔ)句加到可復(fù)用的類的源代碼文件中。
(3)編譯這個(gè)類。這樣,它就被放到適當(dāng)?shù)陌夸浗Y(jié)構(gòu)中,以供編譯器和解譯器使用。
(4)把這個(gè)可復(fù)用的類導(dǎo)入到需要用它的程序中。現(xiàn)在就可以使用它了。
注意 在Java語(yǔ)言中可以出現(xiàn)在類定義的括號(hào)外面的僅有兩個(gè)語(yǔ)句,它們是package和import。
包引用---每個(gè)類名前加上完整的包名
例如,給出一個(gè)指向此包中的類的快捷方式。一旦使用import(導(dǎo)入)了以后,就不再需要給出完整的包名。
可以引入一個(gè)特定的類,也可以引入整個(gè)包。import語(yǔ)句要放在源文件的頭部(但在所有package語(yǔ)句的下面)。例如,可以通過(guò)下面的語(yǔ)句引入在java.util包中的所有的類:
importjava.util.*;
然后,就可以使用
Datetoday=new Date();
而不需要在前面加上包名。也可以引入包中某個(gè)特定的類:
importjava.util.Date;
要把類放人一個(gè)包中,必須把此包的名字放在源文件頭部,并且放在對(duì)包中的類進(jìn)行定義的代碼之前。例如,在文件Employee.java的開(kāi)始部分如下:
packagecom.horstmann.corejava; publicclass Employee { …… }
把包中的文件放入與此完整的包名相匹配的子目錄中。例如,在包c(diǎn)om.horstmann.corejava中的所有的類文件都必須放在子目錄com/horstmann/core.java(Windows下的com\horstmann\corejava)下。這是最簡(jiǎn)單的一種方法
類被存儲(chǔ)在文件系統(tǒng)的子目錄中。類的路徑必須與所在包名相匹配。
在前面的例子中,包目錄com/horstmann/corejava是程序目錄的一個(gè)子目錄。然而這樣安排很不靈活。一般,有多個(gè)程序需要訪問(wèn)包文件。為了使包可以在多個(gè)程序間共享,需要做以下事情:
1)把類放在一個(gè)或多個(gè)特定的目錄中,比如/home/user/classdir。此目錄是包樹(shù)的基本目錄。如果加入了類com.horstmann.corejava.Employee,那么此類文件必須位于子目錄/home/user/classdir/com/horstmann/corejava下。
2)設(shè)置類路徑。類路徑是其子目錄包含類文件的所有基本目錄的集合。classpath
已經(jīng)接觸過(guò)public和private訪問(wèn)指示符。
被標(biāo)記為Public的部件可以被任何類使用,而私有部件只能被定義它們的類使用。如果沒(méi)有指定public或private,那么部件(即類、方法或變量)可以被同一個(gè)包中的所有方法訪問(wèn)。
Java API包
為了簡(jiǎn)化面向?qū)ο蟮木幊踢^(guò)程,Java系統(tǒng)事先設(shè)計(jì)并實(shí)現(xiàn)了一些體現(xiàn)了常用功能的標(biāo)準(zhǔn)類,如用于輸入/輸出的類,用于數(shù)學(xué)運(yùn)算的類,用于圖形用戶界面設(shè)計(jì)的類,用于網(wǎng)絡(luò)處理的類等。這些系統(tǒng)標(biāo)準(zhǔn)類根據(jù)實(shí)現(xiàn)的功能不同,可以劃分成不同的集合,每個(gè)集合是一個(gè)包,合稱為類庫(kù)??梢砸眠@些包,也可以創(chuàng)建自己的包。
Java的類庫(kù)是系統(tǒng)提供的已實(shí)現(xiàn)的標(biāo)準(zhǔn)類的集合,是Java編程的API,它可以幫助開(kāi)發(fā)者方便、快捷地開(kāi)發(fā)Java程序
接口主要作用是可以幫助實(shí)現(xiàn)類似于類的多重繼承的功能。在Java中,出于簡(jiǎn)化程序結(jié)構(gòu)的考慮,不再支持類間的多重繼承而只支持單重繼承,即一個(gè)類至多只能有一個(gè)直接父類。然而在解決實(shí)際問(wèn)題的過(guò)程中,僅僅依靠單重繼承在很多情況下都不能將問(wèn)題的復(fù)雜性表述完整,需要其他的機(jī)制作為輔助。
接口聲明
Java中聲明接口的語(yǔ)法如下:
[public] interface 接口名 [extends 父接口名列表] { //接口體; //常量域聲明 [public] [static] [final] 域類型 域名=常量值; //抽象方法聲明 [public] [abstract] 返回值 方法名(參數(shù)列表) [throw異常列表]; }
從上面的語(yǔ)法規(guī)定可以看出,定義接口與定義類非常相似,實(shí)際上完全可以把接口理解成為一種特殊的類,接口是由常量和抽象方法組成的特殊類
(1)接口中的屬性都是用final修飾的常量,
(2)接口中的方法都是用abstract修飾的抽象方法,在接口中只能給出這些抽象方法的方法名、返回值和參數(shù)列表,而不能定義方法體,即僅僅規(guī)定了一組信息交換、傳輸和處理的“接口”
接口的實(shí)現(xiàn)
一個(gè)類要實(shí)現(xiàn)某個(gè)或某幾個(gè)接口時(shí),有如下的步驟和注意事項(xiàng):
(1)在類的聲明部分,用implements關(guān)鍵字聲明該類將要實(shí)現(xiàn)哪些接口;
如下:
class類名implements接口{ }
(2)如果實(shí)現(xiàn)某接口的類不是abstract的抽象類,則在類的定義部分必須實(shí)現(xiàn)指定接口的所有抽象方法,即為所有抽象方法定義方法體,而且方法頭部分應(yīng)該與接口中的定義完全一致,即有完全相同的返回值和參數(shù)列表;
(3)如果實(shí)現(xiàn)某接口的類是abstract的抽象類,則它可以不實(shí)現(xiàn)該接口所有的方法。
(4)一個(gè)類在實(shí)現(xiàn)某接口的抽象方法時(shí),必須使用完全相同的方法頭。
(5)接口的抽象方法,其訪問(wèn)限制符都已指定是public,所以類在實(shí)現(xiàn)方法時(shí),必須顯式地使用public修飾符。
小結(jié):
多重繼承是指一個(gè)子類繼承多個(gè)父類。Java不支持多重繼承,但Java提供了接口。
子類不能訪問(wèn)父類的private成員,但子類可以訪問(wèn)其父類的public,protected和包訪問(wèn)成員;要訪問(wèn)父類的包訪問(wèn)成員,子類一定要在父類的包內(nèi)。
子類構(gòu)造函數(shù)總是先調(diào)用(顯式的或隱式地)其父類的構(gòu)造函數(shù),以創(chuàng)建和初始化子類的父類成員。
子類的對(duì)象可以當(dāng)作其父類的對(duì)象對(duì)待,反之則不行(即向上轉(zhuǎn)型)
protected訪問(wèn)是public和private訪問(wèn)之間一個(gè)保護(hù)性的中間層次。父類方法、子類方法和在同一個(gè)包內(nèi)類的方法都能訪問(wèn)父類的protected成員,但其他方法均不能訪問(wèn)
一個(gè)子類對(duì)象引用可以隱式地轉(zhuǎn)換成一個(gè)父類對(duì)象引用。使用顯式的類型轉(zhuǎn)換,可以把父類引用轉(zhuǎn)換成子類引用。如果目標(biāo)不是子類對(duì)象,將產(chǎn)生ClassCastException例外處理。
相關(guān)文章
SSH框架網(wǎng)上商城項(xiàng)目第23戰(zhàn)之在線支付功能實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了SSH框架網(wǎng)上商城項(xiàng)目第23戰(zhàn)之在線支付功能實(shí)現(xiàn),感興趣的小伙伴們可以參考一下2016-06-06Spring Boot高效數(shù)據(jù)聚合之道深入講解
這篇文章主要給大家介紹了關(guān)于Spring Boot高效數(shù)據(jù)聚合之道的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06SpringBoot配置mybatis駝峰命名規(guī)則自動(dòng)轉(zhuǎn)換的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot配置mybatis駝峰命名規(guī)則自動(dòng)轉(zhuǎn)換的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09java8學(xué)習(xí)教程之lambda表達(dá)式的使用方法
Java8最值得學(xué)習(xí)的特性就是Lambda表達(dá)式,下面這篇文章主要給大家介紹了關(guān)于java8學(xué)習(xí)教程之lambda表達(dá)式使用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09基于selenium-java封裝chrome、firefox、phantomjs實(shí)現(xiàn)爬蟲(chóng)
這篇文章主要介紹了基于selenium-java封裝chrome、firefox、phantomjs實(shí)現(xiàn)爬蟲(chóng),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2020-10-10MyBatis-Plus通用CRUD操作的實(shí)現(xiàn)
MyBatis-Plus是基于MyBatis的增強(qiáng)工具,主要目的是簡(jiǎn)化MyBatis的使用并提升開(kāi)發(fā)效率,它提供了通可以用CRUD操作、分頁(yè)插件、多種插件支持、自動(dòng)代碼生成器等功能,感興趣的可以了解一下2024-10-10