小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

學(xué)習(xí)Java語(yǔ)言-接口和繼承-繼承

 山峰云繞 2021-04-03

https://m.toutiao.com/is/e2Pfsdv/ 



繼承

在前面的課程中,您多次看到繼承。在Java語(yǔ)言中,類(lèi)可以從其他類(lèi)派生,從而從這些類(lèi)繼承字段和方法。

定義: 從另一個(gè)類(lèi)派生的類(lèi)稱(chēng)為子類(lèi)(也稱(chēng)為派生類(lèi),擴(kuò)展類(lèi)子類(lèi))。派生子類(lèi)的類(lèi)稱(chēng)為超類(lèi)(也稱(chēng)為基類(lèi)父類(lèi))。
除了Object沒(méi)有超類(lèi)的之外,每個(gè)類(lèi)都有一個(gè)且只有一個(gè)直接超類(lèi)(單個(gè)繼承)。在沒(méi)有其他任何顯式超類(lèi)的情況下,每個(gè)類(lèi)都隱式為的子類(lèi)Object。
類(lèi)可以派生自類(lèi),派生自類(lèi),派生自類(lèi),派生類(lèi),等等,最后派生自最頂層的類(lèi),Object。據(jù)說(shuō)這樣的類(lèi)是繼承鏈中所有類(lèi)的
后代,延伸到Object。

繼承的概念很簡(jiǎn)單但是很強(qiáng)大:當(dāng)您要?jiǎng)?chuàng)建一個(gè)新類(lèi)并且已經(jīng)有一個(gè)包含所需代碼的類(lèi)時(shí),可以從現(xiàn)有類(lèi)中派生新類(lèi)。這樣,您可以重用現(xiàn)有類(lèi)的字段和方法,而不必自己編寫(xiě)(和調(diào)試?。┧鼈儭?/span>

子類(lèi)從其超類(lèi)繼承所有成員(字段,方法和嵌套類(lèi))。構(gòu)造函數(shù)不是成員,因此它們不會(huì)被子類(lèi)繼承,但是可以從子類(lèi)中調(diào)用超類(lèi)的構(gòu)造函數(shù)。

Java平臺(tái)類(lèi)層次結(jié)構(gòu)

包中定義的 Object類(lèi)java.lang定義并實(shí)現(xiàn)了所有類(lèi)(包括您編寫(xiě)的類(lèi))共有的行為。在Java平臺(tái)中,許多類(lèi)直接從派生Object,其他類(lèi)從其中一些類(lèi)派生,依此類(lèi)推,形成了類(lèi)的層次結(jié)構(gòu)。

Java平臺(tái)中的所有類(lèi)都是對(duì)象的后代

在層次結(jié)構(gòu)的頂部,Object是所有類(lèi)中最通用的。層次結(jié)構(gòu)底部附近的類(lèi)提供了更特殊的行為。

繼承的例子

以下是“Bicycle類(lèi)和對(duì)象”課程中介紹的類(lèi)的可能實(shí)現(xiàn)的示例代碼:

public class Bicycle {

// the Bicycle class has three fields

public int cadence;

public int gear;

public int speed;

// the Bicycle class has one constructor

public Bicycle(int startCadence, int startSpeed, int startGear) {

gear = startGear;

cadence = startCadence;

speed = startSpeed;

}

// the Bicycle class has four methods

public void setCadence(int newValue) {

cadence = newValue;

}

public void setGear(int newValue) {

gear = newValue;

}

public void applyBrake(int decrement) {

speed -= decrement;

}

public void speedUp(int increment) {

speed += increment;

}

}

類(lèi)聲明的MountainBike類(lèi),它是一個(gè)子類(lèi)Bicycle可能是這樣的:

public class MountainBike extends Bicycle {

// the MountainBike subclass adds one field

public int seatHeight;

// the MountainBike subclass has one constructor

public MountainBike(int startHeight,

int startCadence,

int startSpeed,

int startGear) {

super(startCadence, startSpeed, startGear);

seatHeight = startHeight;

}

// the MountainBike subclass adds one method

public void setHeight(int newValue) {

seatHeight = newValue;

}

}

MountainBike繼承的所有字段和方法,Bicycle并添加字段seatHeight和設(shè)置它的方法。除了構(gòu)造函數(shù)外,就好像您MountainBike完全從頭開(kāi)始編寫(xiě)了一個(gè)新類(lèi),具有四個(gè)字段和五個(gè)方法。但是,您不必完成所有工作。如果Bicycle類(lèi)中的方法很復(fù)雜并且調(diào)試花費(fèi)了大量時(shí)間,那么這將特別有價(jià)值。

您可以在子類(lèi)中做什么

子類(lèi)繼承其父級(jí)的所有公共成員和受保護(hù)成員,無(wú)論該子類(lèi)位于哪個(gè)包中。如果該子類(lèi)與其父級(jí)位于同一包中,則它還將繼承父級(jí)的包私有成員。您可以按原樣使用繼承的成員,替換它們,隱藏它們,或用新成員補(bǔ)充它們:

  • 繼承的字段可以像其他任何字段一樣直接使用。
  • 您可以在子類(lèi)中聲明一個(gè)與超類(lèi)中的名稱(chēng)相同的字段,從而隱藏(不建議)。
  • 您可以在子類(lèi)中聲明不在超類(lèi)中的新字段。
  • 繼承的方法可以直接使用。
  • 您可以在子類(lèi)中編寫(xiě)一個(gè)新的實(shí)例方法,該方法具有與超類(lèi)中的簽名相同的簽名,從而將其覆蓋
  • 您可以在子類(lèi)中編寫(xiě)一個(gè)新的靜態(tài)方法,該方法具有與超類(lèi)中的簽名相同的簽名,從而隱藏。
  • 您可以在子類(lèi)中聲明不在超類(lèi)中的新方法。
  • 您可以編寫(xiě)一個(gè)隱式或使用關(guān)鍵字調(diào)用超類(lèi)的構(gòu)造函數(shù)的子類(lèi)構(gòu)造函數(shù)super。

本課的以下各節(jié)將對(duì)這些主題進(jìn)行擴(kuò)展。

超類(lèi)中的私人成員

子類(lèi)不繼承private其父類(lèi)的成員。但是,如果超類(lèi)具有用于訪問(wèn)其私有字段的公共或受保護(hù)的方法,則子類(lèi)也可以使用這些方法。

嵌套類(lèi)可以訪問(wèn)其封閉類(lèi)的所有私有成員,包括字段和方法。因此,子類(lèi)繼承的公共或受保護(hù)的嵌套類(lèi)可以間接訪問(wèn)超類(lèi)的所有私有成員。

投射對(duì)象

我們已經(jīng)看到對(duì)象是實(shí)例化該類(lèi)的數(shù)據(jù)類(lèi)型的。例如,如果我們寫(xiě)

public MountainBike myBike = new MountainBike();

然后myBike是類(lèi)型MountainBike。

MountainBike是Bicycle和的后代Object。因此,MountainBike是一個(gè)Bicycle,也是一個(gè)Object,并且它可用于任何Bicycle或Object對(duì)象被要求。

相反的情況不一定成立:aBicycle 可以是a MountainBike,但不一定。同樣,anObject 可以是aBicycle或a MountainBike,但不是必須的。

在繼承和實(shí)現(xiàn)允許的對(duì)象中,強(qiáng)制轉(zhuǎn)換顯示了使用一種類(lèi)型的對(duì)象代替另一種類(lèi)型的對(duì)象。例如,如果我們寫(xiě)

Object obj = new MountainBike();

然后obj是Object和兩者M(jìn)ountainBike(直到obj分配了另一個(gè)不是的對(duì)象的時(shí)間MountainBike)。這稱(chēng)為隱式轉(zhuǎn)換

另一方面,如果我們寫(xiě)

MountainBike myBike = obj;

我們會(huì)得到一個(gè)編譯時(shí)錯(cuò)誤,因?yàn)閛bj編譯器不知道是MountainBike。但是,我們可以告訴編譯器,我們承諾分配MountainBike給obj通過(guò)顯式轉(zhuǎn)換:

MountainBike myBike =(MountainBike)obj;

此強(qiáng)制轉(zhuǎn)換插入obj分配了的運(yùn)行時(shí)檢查,MountainBike以便編譯器可以安全地假定obj為MountainBike。如果obj不是MountainBike在運(yùn)行時(shí),則將引發(fā)異常。

注意: 您可以使用instanceof運(yùn)算符對(duì)特定對(duì)象的類(lèi)型進(jìn)行邏輯測(cè)試。由于不正確的轉(zhuǎn)換,可以避免運(yùn)行時(shí)錯(cuò)誤。例如:

if (obj instanceof MountainBike) {

MountainBike myBike = (MountainBike)obj;

}

在這里,instanceof操作員驗(yàn)證obj引用了a的內(nèi)容,MountainBike以便我們可以在不引發(fā)任何運(yùn)行時(shí)異常的情況下進(jìn)行強(qiáng)制轉(zhuǎn)換。

狀態(tài),實(shí)現(xiàn)和類(lèi)型的多重繼承

類(lèi)和接口之間的一個(gè)重要區(qū)別是,類(lèi)可以具有字段,而接口則不能。另外,您可以實(shí)例化一個(gè)類(lèi)來(lái)創(chuàng)建對(duì)象,而這是無(wú)法使用接口完成的。如“什么是對(duì)象? ”部分中所述 。,對(duì)象將其狀態(tài)存儲(chǔ)在類(lèi)中定義的字段中。Java編程語(yǔ)言不允許您擴(kuò)展多個(gè)類(lèi)的原因之一是避免狀態(tài)的多重繼承問(wèn)題,這是從多個(gè)類(lèi)繼承字段的能力。例如,假設(shè)您能夠定義一個(gè)擴(kuò)展多個(gè)類(lèi)的新類(lèi)。當(dāng)通過(guò)實(shí)例化該類(lèi)創(chuàng)建對(duì)象時(shí),該對(duì)象將繼承該類(lèi)所有超類(lèi)的字段。如果來(lái)自不同超類(lèi)的方法或構(gòu)造函數(shù)實(shí)例化同一字段怎么辦?哪個(gè)方法或構(gòu)造函數(shù)優(yōu)先?因?yàn)榻涌诓话侄危阅槐負(fù)?dān)心狀態(tài)的多重繼承引起的問(wèn)題。

實(shí)現(xiàn)的多重繼承是從多個(gè)類(lèi)繼承方法定義的能力。這種類(lèi)型的多重繼承會(huì)產(chǎn)生問(wèn)題,例如名稱(chēng)沖突和歧義。當(dāng)支持這種多重繼承的編程語(yǔ)言的編譯器遇到包含具有相同名稱(chēng)的方法的超類(lèi)時(shí),它們有時(shí)無(wú)法確定要訪問(wèn)或調(diào)用的成員或方法。另外,程序員可以通過(guò)向超類(lèi)添加新方法來(lái)無(wú)意間引入名稱(chēng)沖突。 默認(rèn)方法介紹實(shí)現(xiàn)的多重繼承的一種形式。一個(gè)類(lèi)可以實(shí)現(xiàn)多個(gè)接口,該接口可以包含具有相同名稱(chēng)的默認(rèn)方法。Java編譯器提供了一些規(guī)則來(lái)確定特定類(lèi)使用哪種默認(rèn)方法。

Java編程語(yǔ)言支持type的多重繼承,這是類(lèi)實(shí)現(xiàn)多個(gè)接口的能力。一個(gè)對(duì)象可以具有多種類(lèi)型:其自己的類(lèi)的類(lèi)型以及該類(lèi)實(shí)現(xiàn)的所有接口的類(lèi)型。這意味著,如果將變量聲明為接口的類(lèi)型,則其值可以引用從實(shí)現(xiàn)該接口的任何類(lèi)實(shí)例化的任何對(duì)象。在使用接口作為類(lèi)型一節(jié)中對(duì)此進(jìn)行了討論 。

與實(shí)現(xiàn)的多重繼承一樣,類(lèi)可以繼承其擴(kuò)展的接口中定義的方法的不同實(shí)現(xiàn)(默認(rèn)或靜態(tài))。在這種情況下,編譯器或用戶(hù)必須決定使用哪個(gè)。

覆蓋和隱藏方法

實(shí)例方法

子類(lèi)中具有相同簽名(名稱(chēng),加上數(shù)字和參數(shù)的類(lèi)型)且返回類(lèi)型作為超類(lèi)中的實(shí)例方法的實(shí)例方法將覆蓋超類(lèi)的方法。

子類(lèi)重寫(xiě)方法的能力使類(lèi)可以從行為“足夠接近”的超類(lèi)繼承,然后根據(jù)需要修改行為。覆蓋方法與其覆蓋的方法具有相同的名稱(chēng),數(shù)量和參數(shù)類(lèi)型,并且返回類(lèi)型相同。重寫(xiě)方法還可以返回重寫(xiě)方法返回的類(lèi)型的子類(lèi)型。此子類(lèi)型稱(chēng)為協(xié)變返回類(lèi)型。

覆蓋方法時(shí),可能需要使用@Override注釋?zhuān)撟⑨屩甘揪幾g器打算覆蓋超類(lèi)中的方法。如果由于某種原因,編譯器檢測(cè)到該方法在超類(lèi)之一中不存在,則它將生成錯(cuò)誤。有關(guān)更多信息@Override,請(qǐng)參見(jiàn) Annotations。

靜態(tài)方法

如果子類(lèi)定義的靜態(tài)方法具有與超類(lèi)中的靜態(tài)方法相同的簽名,則子類(lèi)中的方法會(huì)將其隱藏在超類(lèi)中。

隱藏靜態(tài)方法和覆蓋實(shí)例方法之間的區(qū)別具有重要意義:

  • 被調(diào)用的重寫(xiě)實(shí)例方法的版本是子類(lèi)中的版本。
  • 調(diào)用的隱藏靜態(tài)方法的版本取決于是從超類(lèi)還是從子類(lèi)調(diào)用。

考慮一個(gè)包含兩個(gè)類(lèi)的示例。第一個(gè)是Animal,其中包含一個(gè)實(shí)例方法和一個(gè)靜態(tài)方法:

public class Animal {

public static void testClassMethod() {

System.out.println('The static method in Animal');

}

public void testInstanceMethod() {

System.out.println('The instance method in Animal');

}

}

第二類(lèi)是的子類(lèi)Animal,稱(chēng)為Cat:

public class Cat extends Animal {

public static void testClassMethod() {

System.out.println('The static method in Cat');

}

public void testInstanceMethod() {

System.out.println('The instance method in Cat');

}

public static void main(String[] args) {

Cat myCat = new Cat();

Animal myAnimal = myCat;

Animal.testClassMethod();

myAnimal.testInstanceMethod();

}

}

該Cat班將覆蓋實(shí)例方法Animal,并隱藏了靜態(tài)方法Animal。main此類(lèi)中的方法創(chuàng)建類(lèi)的實(shí)例,Cat并testClassMethod()在類(lèi)和實(shí)例上調(diào)用testInstanceMethod()。

該程序的輸出如下:

The static method in Animal

The instance method in Cat

如所承諾的,被調(diào)用的隱藏靜態(tài)方法的版本是超類(lèi)中的版本,而被調(diào)用的重寫(xiě)實(shí)例方法的版本是子類(lèi)中的版本。

接口方法

接口中的默認(rèn)方法抽象方法像實(shí)例方法一樣被繼承。但是,當(dāng)類(lèi)或接口的超類(lèi)型提供具有相同簽名的多個(gè)默認(rèn)方法時(shí),Java編譯器將遵循繼承規(guī)則來(lái)解決名稱(chēng)沖突。這些規(guī)則由以下兩個(gè)原則驅(qū)動(dòng):

  • 實(shí)例方法優(yōu)于接口默認(rèn)方法。

考慮以下類(lèi)和接口:

public class Horse {

public String identifyMyself() {

return 'I am a horse.';

}

}

public interface Flyer {

default public String identifyMyself() {

return 'I am able to fly.';

}

}

public interface Mythical {

default public String identifyMyself() {

return 'I am a mythical creature.';

}

}

public class Pegasus extends Horse implements Flyer, Mythical {

public static void main(String... args) {

Pegasus myApp = new Pegasus();

System.out.println(myApp.identifyMyself());

}

}

該方法Pegasus.identifyMyself返回字符串I am a horse.

  • 已被其他候選項(xiàng)覆蓋的方法將被忽略。當(dāng)超類(lèi)型共享一個(gè)共同祖先時(shí),就會(huì)出現(xiàn)這種情況。

考慮以下接口和類(lèi):

public interface Animal {

default public String identifyMyself() {

return 'I am an animal.';

}

}

public interface EggLayer extends Animal {

default public String identifyMyself() {

return 'I am able to lay eggs.';

}

}

public interface FireBreather extends Animal { }

public class Dragon implements EggLayer, FireBreather {

public static void main (String... args) {

Dragon myApp = new Dragon();

System.out.println(myApp.identifyMyself());

}

}

該方法Dragon.identifyMyself返回字符串I am able to lay eggs.

如果兩個(gè)或多個(gè)獨(dú)立定義的默認(rèn)方法發(fā)生沖突,或者默認(rèn)方法與抽象方法發(fā)生沖突,則Java編譯器將產(chǎn)生編譯器錯(cuò)誤。您必須顯式重寫(xiě)超類(lèi)型方法。

考慮有關(guān)現(xiàn)在可以飛行的計(jì)算機(jī)控制汽車(chē)的示例。您有兩個(gè)接口(OperateCar和FlyCar)提供相同方法(startEngine)的默認(rèn)實(shí)現(xiàn):

public interface OperateCar {

// ...

default public int startEngine(EncryptedKey key) {

// Implementation

}

}

public interface FlyCar {

// ...

default public int startEngine(EncryptedKey key) {

// Implementation

}

}

同時(shí)實(shí)現(xiàn)這兩個(gè)方法OperateCar且FlyCar必須重寫(xiě)該方法的類(lèi)startEngine。您可以使用super關(guān)鍵字調(diào)用任何默認(rèn)實(shí)現(xiàn)。

public class FlyingCar implements OperateCar, FlyCar {

// ...

public int startEngine(EncryptedKey key) {

FlyCar.super.startEngine(key);

OperateCar.super.startEngine(key);

}

}

前面的名稱(chēng)super(在此示例中為FlyCar或OperateCar)必須引用直接超級(jí)接口,該超級(jí)接口定義或繼承了所調(diào)用方法的默認(rèn)值。這種形式的方法調(diào)用不限于區(qū)分包含相同簽名的默認(rèn)方法的多個(gè)已實(shí)現(xiàn)接口。您可以使用super關(guān)鍵字在類(lèi)和接口中調(diào)用默認(rèn)方法。

從類(lèi)繼承的實(shí)例方法可以覆蓋抽象接口方法??紤]以下接口和類(lèi):

public interface Mammal {

String identifyMyself();

}

public class Horse {

public String identifyMyself() {

return 'I am a horse.';

}

}

public class Mustang extends Horse implements Mammal {

public static void main(String... args) {

Mustang myApp = new Mustang();

System.out.println(myApp.identifyMyself());

}

}

該方法Mustang.identifyMyself返回字符串I am a horse.。類(lèi)從該類(lèi)Mustang繼承該方法identifyMyself,該類(lèi)Horse將重寫(xiě)接口中同名的抽象方法Mammal。

注意:接口中的靜態(tài)方法永遠(yuǎn)不會(huì)被繼承。

修飾符

覆蓋方法的訪問(wèn)說(shuō)明符可以比覆蓋方法允許更多但不能更少的訪問(wèn)。例如,超類(lèi)中的受保護(hù)實(shí)例方法可以在子類(lèi)中公開(kāi),但不能私有。

如果嘗試將超類(lèi)中的實(shí)例方法更改為子類(lèi)中的靜態(tài)方法,并且相反,則將遇到編譯時(shí)錯(cuò)誤。

概括

下表總結(jié)了在定義具有與超類(lèi)中的方法相同的簽名的方法時(shí)發(fā)生的情況。

Defining a Method with the Same Signature as a Superclass's Method

Superclass Instance Method

Superclass Static Method

Subclass Instance Method

Overrides

Generates a compile-time error

Subclass Static Method

Generates a compile-time error

Hides

注意: 在子類(lèi)中,您可以重載從超類(lèi)繼承的方法。這樣的重載方法既不會(huì)隱藏也不會(huì)覆蓋超類(lèi)實(shí)例方法,它們是子類(lèi)獨(dú)有的新方法。

多態(tài)性

字典中的多態(tài)性定義是指生物學(xué)中的一種原理,其中生物或物種可以具有許多不同的形式或階段。該原理也可以應(yīng)用于面向?qū)ο蟮木幊毯蚃ava語(yǔ)言之類(lèi)的語(yǔ)言。一個(gè)類(lèi)的子類(lèi)可以定義自己的獨(dú)特行為,但可以共享父類(lèi)的某些相同功能。

可以通過(guò)對(duì)該Bicycle類(lèi)進(jìn)行較小的修改來(lái)證明多態(tài)性。例如,printDescription可以將一個(gè)方法添加到類(lèi)中,以顯示當(dāng)前存儲(chǔ)在實(shí)例中的所有數(shù)據(jù)。

public void printDescription(){

System.out.println('\nBike is ' + 'in gear ' + this.gear

+ ' with a cadence of ' + this.cadence +

' and travelling at a speed of ' + this.speed + '. ');

}

要演示Java語(yǔ)言中的多態(tài)功能,請(qǐng)Bicycle使用MountainBike和擴(kuò)展RoadBike該類(lèi)。為MountainBike,添加的字段suspension,該字段的String值指示自行車(chē)是否具有前減震器Front?;蛘?,自行車(chē)具有前后減震器Dual。

這是更新的類(lèi):

public class MountainBike extends Bicycle {

private String suspension;

public MountainBike(

int startCadence,

int startSpeed,

int startGear,

String suspensionType){

super(startCadence,

startSpeed,

startGear);

this.setSuspension(suspensionType);

}

public String getSuspension(){

return this.suspension;

}

public void setSuspension(String suspensionType) {

this.suspension = suspensionType;

}

public void printDescription() {

super.printDescription();

System.out.println('The ' + 'MountainBike has a' +

getSuspension() + ' suspension.');

}

}

請(qǐng)注意重寫(xiě)的printDescription方法。除了之前提供的信息外,有關(guān)懸架的其他數(shù)據(jù)也包含在輸出中。

接下來(lái),創(chuàng)建RoadBike類(lèi)。由于公路或賽車(chē)自行車(chē)的輪胎很稀薄,因此請(qǐng)?zhí)砑右粋€(gè)屬性以跟蹤輪胎的寬度。這是RoadBike課程:

public class RoadBike extends Bicycle{

// In millimeters (mm)

private int tireWidth;

public RoadBike(int startCadence,

int startSpeed,

int startGear,

int newTireWidth){

super(startCadence,

startSpeed,

startGear);

this.setTireWidth(newTireWidth);

}

public int getTireWidth(){

return this.tireWidth;

}

public void setTireWidth(int newTireWidth){

this.tireWidth = newTireWidth;

}

public void printDescription(){

super.printDescription();

System.out.println('The RoadBike' + ' has ' + getTireWidth() +

' MM tires.');

}

}

請(qǐng)?jiān)俅巫⒁猓損rintDescription方法已被覆蓋。這次,顯示有關(guān)輪胎寬度的信息。

總之,有三大類(lèi):Bicycle,MountainBike,和RoadBike。這兩個(gè)子類(lèi)重寫(xiě)該printDescription方法并打印唯一信息。

這是一個(gè)創(chuàng)建三個(gè)Bicycle變量的測(cè)試程序。每個(gè)變量都分配給三個(gè)自行車(chē)類(lèi)別之一。然后打印每個(gè)變量。

public class TestBikes {

public static void main(String[] args){

Bicycle bike01, bike02, bike03;

bike01 = new Bicycle(20, 10, 1);

bike02 = new MountainBike(20, 10, 5, 'Dual');

bike03 = new RoadBike(40, 20, 8, 23);

bike01.printDescription();

bike02.printDescription();

bike03.printDescription();

}

}

以下是測(cè)試程序的輸出:

自行車(chē)的檔位為1,節(jié)奏為20,行駛速度為10。

自行車(chē)以20的節(jié)奏進(jìn)入5檔,并以10的速度行駛。

MountainBike具有雙重懸掛。

自行車(chē)的檔位為40,節(jié)奏為20,行駛速度為20。

RoadBike有23毫米的輪胎。

Java虛擬機(jī)(JVM)為每個(gè)變量中引用的對(duì)象調(diào)用適當(dāng)?shù)姆椒?。它不?huì)調(diào)用由變量類(lèi)型定義的方法。此行為稱(chēng)為虛擬方法調(diào)用,它說(shuō)明了Java語(yǔ)言中重要的多態(tài)性功能的一個(gè)方面。

隱藏字段

在類(lèi)中,與超類(lèi)中的字段具有相同名稱(chēng)的字段將隱藏超類(lèi)的字段,即使它們的類(lèi)型不同。在子類(lèi)中,不能通過(guò)其簡(jiǎn)單名稱(chēng)引用超類(lèi)中的字段。而是必須通過(guò)super下一節(jié)中介紹的來(lái)訪問(wèn)該字段。一般來(lái)說(shuō),我們不建議隱藏字段,因?yàn)檫@會(huì)使代碼難以閱讀。

使用超級(jí)關(guān)鍵字

訪問(wèn)父類(lèi)成員

如果您的方法覆蓋了其超類(lèi)的方法之一,則可以使用關(guān)鍵字調(diào)用被覆蓋的方法super。您也可以使用它super來(lái)引用隱藏字段(盡管不建議使用隱藏字段)??紤]這個(gè)類(lèi)Superclass:

public class Superclass {

public void printMethod() {

System.out.println('Printed in Superclass.');

}

}

這是一個(gè)名為的子類(lèi),該子類(lèi)Subclass將覆蓋printMethod():

public class Subclass extends Superclass {

// overrides printMethod in Superclass

public void printMethod() {

super.printMethod();

System.out.println('Printed in Subclass');

}

public static void main(String[] args) {

Subclass s = new Subclass();

s.printMethod();

}

}

在其中Subclass,簡(jiǎn)單名稱(chēng)printMethod()指的是在中聲明的名稱(chēng),而在中聲明的名稱(chēng)將被Subclass覆蓋Superclass。因此,要引用printMethod()繼承自Superclass,Subclass必須使用限定名稱(chēng),super如下所示。編譯并執(zhí)行將Subclass打印以下內(nèi)容:

Printed in Superclass.

Printed in Subclass

子類(lèi)構(gòu)造函數(shù)

下面的示例說(shuō)明如何使用super關(guān)鍵字來(lái)調(diào)用超類(lèi)的構(gòu)造函數(shù)?;叵胍幌略?Bicycle 示例MountainBike的一個(gè)子類(lèi)Bicycle。以下是MountainBike(子類(lèi))構(gòu)造函數(shù),該構(gòu)造函數(shù)調(diào)用超類(lèi)構(gòu)造函數(shù),然后添加其自身的初始化代碼:

public MountainBike(int startHeight,

int startCadence,

int startSpeed,

int startGear) {

super(startCadence, startSpeed, startGear);

seatHeight = startHeight;

}

父類(lèi)構(gòu)造函數(shù)的調(diào)用必須是子類(lèi)構(gòu)造函數(shù)的第一行。

調(diào)用超類(lèi)構(gòu)造函數(shù)的語(yǔ)法是

super();

或者:

super(parameter list);

使用super(),將調(diào)用超類(lèi)無(wú)參數(shù)構(gòu)造函數(shù)。使用super(parameter list),將調(diào)用具有匹配參數(shù)列表的超類(lèi)構(gòu)造函數(shù)。

注意: 如果構(gòu)造函數(shù)未顯式調(diào)用超類(lèi)構(gòu)造函數(shù),則Java編譯器會(huì)自動(dòng)將調(diào)用插入到超類(lèi)的無(wú)參數(shù)構(gòu)造函數(shù)中。如果超類(lèi)沒(méi)有無(wú)參數(shù)構(gòu)造函數(shù),則會(huì)出現(xiàn)編譯時(shí)錯(cuò)誤。Object 確實(shí)有這樣的構(gòu)造函數(shù),所以如果Object是唯一的超類(lèi),就沒(méi)有問(wèn)題。

如果子類(lèi)構(gòu)造函數(shù)顯式或隱式調(diào)用其超類(lèi)的構(gòu)造函數(shù),則您可能會(huì)認(rèn)為將調(diào)用整個(gè)構(gòu)造函數(shù)鏈,一直返回到的構(gòu)造函數(shù)Object。實(shí)際上就是這種情況。這稱(chēng)為構(gòu)造函數(shù)鏈接,當(dāng)有很長(zhǎng)的一類(lèi)類(lèi)下降時(shí),您需要意識(shí)到這一點(diǎn)。

作為超類(lèi)的對(duì)象

Object類(lèi),在java.lang包裝,坐鎮(zhèn)類(lèi)層次結(jié)構(gòu)樹(shù)的頂端。每個(gè)類(lèi)都是該類(lèi)的直接或間接后代Object。您使用或編寫(xiě)的每個(gè)類(lèi)都繼承的實(shí)例方法Object。您不需要使用任何這些方法,但是,如果您選擇使用這些方法,則可能需要使用特定于您的類(lèi)的代碼來(lái)覆蓋它們。Object本節(jié)將討論從中繼承的方法:

  • protected Object clone() throws CloneNotSupportedException
    創(chuàng)建并返回此對(duì)象的副本。
  • public boolean equals(Object obj)
    指示其他某個(gè)對(duì)象是否“等于”該對(duì)象。
  • protected void finalize() throws Throwable
    當(dāng)垃圾
    回收確定不再有對(duì)該對(duì)象的引用時(shí),由垃圾回收器在對(duì)象上調(diào)用
  • public final Class getClass()
    返回對(duì)象的運(yùn)行時(shí)類(lèi)。
  • public int hashCode()
    返回對(duì)象的哈希碼值。
  • public String toString()
    返回對(duì)象的字符串表示形式。

的notify,notifyAll和wait方法Object都在一個(gè)程序,它在后面的課程中討論,并不會(huì)在這里介紹的同步獨(dú)立運(yùn)行的線(xiàn)程的活動(dòng)中發(fā)揮作用。這些方法有五種:

  • public final void notify()
  • public final void notifyAll()
  • public final void wait()
  • public final void wait(long timeout)
  • public final void wait(long timeout, int nanos)

注意: 這些方法,尤其是方法,在某些方面有一些微妙的方面clone。

clone()方法

如果一個(gè)類(lèi)或其超類(lèi)之一實(shí)現(xiàn)了Cloneable接口,則可以使用該clone()方法從現(xiàn)有對(duì)象創(chuàng)建副本。要?jiǎng)?chuàng)建克隆,請(qǐng)編寫(xiě):

aCloneableObject .clone();

Object此方法的實(shí)現(xiàn)檢查是否clone()調(diào)用了其的對(duì)象實(shí)現(xiàn)了該Cloneable接口。如果對(duì)象不存在,則該方法將引發(fā)CloneNotSupportedException異常。異常處理將在以后的課程中介紹。目前,您需要知道clone()必須聲明為

protected Object clone() throws CloneNotSupportedException

或者:

public Object clone() throws CloneNotSupportedException

如果您要編寫(xiě)一種clone()方法來(lái)覆蓋中的方法Object。

如果clone()調(diào)用了該對(duì)象的對(duì)象確實(shí)實(shí)現(xiàn)了該Cloneable接口,則Object該clone()方法的實(shí)現(xiàn)將創(chuàng)建一個(gè)與原始對(duì)象相同類(lèi)的對(duì)象,并將新對(duì)象的成員變量初始化為具有與原始對(duì)象的相應(yīng)成員變量相同的值。

使您的類(lèi)可克隆的最簡(jiǎn)單方法是添加implements Cloneable到類(lèi)的聲明中。然后您的對(duì)象可以調(diào)用該clone()方法。

對(duì)于一些類(lèi),默認(rèn)行為Object的clone()方法工作得很好。但是,如果對(duì)象包含對(duì)外部對(duì)象的引用(例如)ObjExternal,則可能需要重寫(xiě)clone()以獲取正確的行為。否則,ObjExternal一個(gè)對(duì)象所做的更改也將在其克隆中可見(jiàn)。這意味著原始對(duì)象及其克隆不是獨(dú)立的,clone()要使它們分離,必須重寫(xiě)以克隆對(duì)象 ObjExternal。然后,原始對(duì)象引用ObjExternal和克隆引用的克隆ObjExternal,從而使對(duì)象及其克隆真正獨(dú)立。

equals()方法

該equals()方法比較兩個(gè)對(duì)象是否相等,true如果相等則返回。該類(lèi)中equals()提供的方法Object使用身份運(yùn)算符(==)確定兩個(gè)對(duì)象是否相等。對(duì)于原始數(shù)據(jù)類(lèi)型,這將給出正確的結(jié)果。但是,對(duì)于對(duì)象,則不是。所equals()提供的方法Object測(cè)試對(duì)象引用是否相等,即所比較的對(duì)象是否是完全相同的對(duì)象。

要測(cè)試兩個(gè)對(duì)象在等效性上是否相等(包含相同的信息),必須重寫(xiě)該equals()方法。這是Book重寫(xiě)的類(lèi)的示例equals():

public class Book {

...

public boolean equals(Object obj) {

if (obj instanceof Book)

return ISBN.equals((Book)obj.getISBN());

else

return false;

}

}

考慮以下代碼,該代碼測(cè)試Book該類(lèi)的兩個(gè)實(shí)例是否相等:

// Swing Tutorial, 2nd edition

Book firstBook = new Book('0201914670');

Book secondBook = new Book('0201914670');

if (firstBook.equals(secondBook)) {

System.out.println('objects are equal');

} else {

System.out.println('objects are not equal');

}

該程序objects are equal即使顯示firstBook并secondBook引用兩個(gè)不同的對(duì)象。之所以認(rèn)為它們相等,是因?yàn)樗容^的對(duì)象包含相同的ISBN號(hào)。

equals()如果身份運(yùn)算符不適合您的類(lèi),則應(yīng)始終覆蓋該方法。

注意: 如果您覆蓋equals(),則還必須覆蓋hashCode()。

finalize()方法

的Object類(lèi)提供的回調(diào)方法,finalize()即可以在物體上時(shí),它變?yōu)槔{(diào)用。Object的實(shí)現(xiàn)finalize()不執(zhí)行任何操作-您可以重寫(xiě)finalize()以進(jìn)行清理,例如釋放資源。

該finalize()方法可以由系統(tǒng)自動(dòng)調(diào)用,但是何時(shí)調(diào)用,即使調(diào)用,也不確定。因此,您不應(yīng)依賴(lài)此方法為您進(jìn)行清理。例如,如果您在執(zhí)行I / O之后沒(méi)有在代碼中關(guān)閉文件描述符,而您希望finalize()為您關(guān)閉它們,則文件描述符可能用完了。

getClass()方法

您不能覆蓋getClass。

該getClass()方法返回一個(gè)Class對(duì)象,該對(duì)象具有可用于獲取有關(guān)類(lèi)的信息的方法,例如其名稱(chēng)(getSimpleName()),其超類(lèi)(getSuperclass())及其實(shí)現(xiàn)的接口(getInterfaces())。例如,以下方法獲取并顯示對(duì)象的類(lèi)名稱(chēng):

void printClassName(Object obj) {

System.out.println('The object's' + ' class is ' +

obj.getClass().getSimpleName());

}

程序包中的 Class類(lèi)java.lang具有大量方法(超過(guò)50種)。例如,您可以測(cè)試該類(lèi)是注解(isAnnotation()),接口(isInterface())還是枚舉(isEnum())。您可以看到對(duì)象的字段是(getFields())或?qū)ο蟮姆椒ㄊ牵╣etMethods()),依此類(lèi)推。

hashCode()方法

返回的值hashCode()是對(duì)象的哈希碼,它是對(duì)象的內(nèi)存地址(十六進(jìn)制)。

根據(jù)定義,如果兩個(gè)對(duì)象相等,則它們的哈希碼必須相等。如果您重寫(xiě)此equals()方法,則會(huì)更改兩個(gè)對(duì)象的相等方式,并且Object的實(shí)現(xiàn)hashCode()不再有效。因此,如果您覆蓋該equals()方法,則還必須覆蓋該hashCode()方法。

toString()方法

您應(yīng)該始終考慮toString()在類(lèi)中重寫(xiě)該方法。

所述Object的toString()方法返回String的對(duì)象,這是對(duì)于調(diào)試是非常有用的表示。String對(duì)象的表示形式完全取決于對(duì)象,這就是為什么需要toString()在類(lèi)中進(jìn)行覆蓋的原因。

您可以結(jié)合使用toString()和System.out.println()來(lái)顯示對(duì)象的文本表示形式,例如的實(shí)例Book:

System.out.println(firstBook.toString());

對(duì)于正確覆蓋的toString()方法,它將打印出有用的內(nèi)容,例如:

國(guó)際標(biāo)準(zhǔn)書(shū)號(hào)(ISBN):0201914670;Swing教程;GUI構(gòu)造指南,第二版

編寫(xiě)Final類(lèi)和方法

您可以將某些或所有類(lèi)的方法聲明為final。您可以final在方法聲明中使用關(guān)鍵字來(lái)指示該方法不能被子類(lèi)覆蓋。該Object班做這個(gè),它的一些方法final。

如果某個(gè)方法的實(shí)現(xiàn)不應(yīng)該更改并且對(duì)于對(duì)象的一致?tīng)顟B(tài)至關(guān)重要,則可能希望將其定型。例如,您可能想使getFirstPlayer此類(lèi)中的方法成為ChessAlgorithmfinal:

class ChessAlgorithm {

enum ChessPlayer { WHITE, BLACK }

...

final ChessPlayer getFirstPlayer() {

return ChessPlayer.WHITE;

}

...

}

從構(gòu)造函數(shù)調(diào)用的方法通常應(yīng)聲明為final。如果構(gòu)造函數(shù)調(diào)用了非最終方法,則子類(lèi)可能會(huì)重新定義該方法,從而產(chǎn)生令人驚訝或不良的結(jié)果。

注意,您也可以聲明整個(gè)類(lèi)的final。聲明為final的類(lèi)不能被子類(lèi)化。例如,當(dāng)創(chuàng)建一個(gè)不可變的類(lèi)(例如String該類(lèi))時(shí),這特別有用

抽象方法和類(lèi)

一個(gè)抽象類(lèi)是聲明的類(lèi)abstract-它可能會(huì)或可能不包括抽象方法。抽象類(lèi)不能被實(shí)例化,但是可以被子類(lèi)化。

一個(gè)抽象方法是沒(méi)有實(shí)現(xiàn)聲明(沒(méi)有括號(hào),并且隨后是分號(hào)),像這樣的方法:

abstract void moveTo(double deltaX,double deltaY);

如果一個(gè)類(lèi)包含抽象方法,則必須聲明該類(lèi)本身abstract,如:

public abstract class GraphicObject {

// declare fields

// declare nonabstract methods

abstract void draw();

}

當(dāng)抽象類(lèi)被子類(lèi)化時(shí),該子類(lèi)通常為其父類(lèi)中的所有抽象方法提供實(shí)現(xiàn)。但是,如果沒(méi)有,則還必須聲明子類(lèi)abstract。

注: 方法在接口(見(jiàn) 接口部分)未聲明為默認(rèn)或靜態(tài)的含蓄抽象的,所以abstract修改不與接口方法使用。(可以使用,但這不是必需的。)

抽象類(lèi)與接口的比較

抽象類(lèi)類(lèi)似于接口。您無(wú)法實(shí)例化它們,它們可能包含使用或不使用實(shí)現(xiàn)聲明的方法的混合。但是,使用抽象類(lèi),您可以聲明非靜態(tài)和最終字段,并定義公共,受保護(hù)的和私有的具體方法。使用接口時(shí),所有字段都自動(dòng)是公共的,靜態(tài)的和最終的,并且您聲明或定義的所有方法(作為默認(rèn)方法)都是公共的。此外,無(wú)論是否抽象,您都只能擴(kuò)展一個(gè)類(lèi),而您可以實(shí)現(xiàn)任意數(shù)量的接口。

您應(yīng)該使用哪個(gè)抽象類(lèi)或接口?

  • 如果以下任何一種情況適用于您的情況,請(qǐng)考慮使用抽象類(lèi):您想在幾個(gè)緊密相關(guān)的類(lèi)之間共享代碼。您期望擴(kuò)展您的抽象類(lèi)的類(lèi)具有許多公共方法或字段,或者需要除public之外的訪問(wèn)修飾符(例如,protected和private)。您要聲明非靜態(tài)或非最終字段。這使您能夠定義一些方法,這些方法可以訪問(wèn)和修改它們所屬對(duì)象的狀態(tài)。
  • 如果以下任何一種情況適用于您的情況,請(qǐng)考慮使用接口:您期望不相關(guān)的類(lèi)將實(shí)現(xiàn)您的接口。例如,接口 ComparableCloneable由許多不相關(guān)的類(lèi)實(shí)現(xiàn)。您想指定特定數(shù)據(jù)類(lèi)型的行為,但不關(guān)心誰(shuí)實(shí)現(xiàn)了它的行為。您想利用類(lèi)型的多重繼承。

JDK中的抽象類(lèi)的一個(gè)示例是 AbstractMap,它是Collections Framework的一部分。它的子類(lèi)(包括HashMap,TreeMap,和ConcurrentHashMap)共享許多方法(包括get,put,isEmpty,containsKey,和containsValue),其AbstractMap定義。

在JDK的類(lèi)的例子,它實(shí)現(xiàn)幾個(gè)接口是 HashMap,它實(shí)現(xiàn)了接口Serializable,Cloneable和Map<K, V>。通過(guò)閱讀此接口列表,您可以推斷出HashMap(可以實(shí)例化該類(lèi)的開(kāi)發(fā)人員或公司的)實(shí)例可以被克隆,并且可以序列化(這意味著可以將其轉(zhuǎn)換為字節(jié)流;請(qǐng)參見(jiàn)“序列化對(duì)象”部分)。 ),并具有地圖功能。此外,該Map<K, V>接口已通過(guò)許多默認(rèn)方法進(jìn)行了增強(qiáng),例如,merge并且forEach不必定義實(shí)現(xiàn)此接口的較早的類(lèi)。

注意,許多軟件庫(kù)同時(shí)使用抽象類(lèi)和接口。在HashMap類(lèi)實(shí)現(xiàn)多個(gè)接口,并且還擴(kuò)展了抽象類(lèi)AbstractMap。

一個(gè)抽象類(lèi)的例子

在面向?qū)ο蟮睦L圖應(yīng)用程序中,您可以繪制圓形,矩形,直線(xiàn),貝塞爾曲線(xiàn)和許多其他圖形對(duì)象。這些對(duì)象都有共同的某些狀態(tài)(例如:位置,方向,線(xiàn)條顏色,填充顏色)和行為(例如:moveTo,旋轉(zhuǎn),調(diào)整大小,繪制)。所有圖形對(duì)象的某些狀態(tài)和行為都是相同的(例如:position,fill color和moveTo)。其他的則需要不同的實(shí)現(xiàn)(例如,調(diào)整大小或繪制)。所有GraphicObject的人都必須能夠畫(huà)畫(huà)或調(diào)整自己的大小。他們只是在做事方式上有所不同。對(duì)于抽象超類(lèi)來(lái)說(shuō),這是一個(gè)完美的情況。您可以利用相似之處,并聲明所有圖形對(duì)象都可以從同一個(gè)抽象父對(duì)象(例如GraphicObject)繼承,如圖所示。 下圖。

從GraphicObject繼承的Rectangle,Line,Bezier和Circle類(lèi)

首先,您聲明一個(gè)抽象類(lèi),GraphicObject以提供由所有子類(lèi)完全共享的成員變量和方法,例如當(dāng)前位置和moveTo方法。GraphicObject還為方法(例如draw或)聲明了抽象方法,這些方法resize需要由所有子類(lèi)實(shí)現(xiàn),但必須以不同的方式實(shí)現(xiàn)。本GraphicObject類(lèi)可以是這個(gè)樣子:

abstract class GraphicObject {

int x, y;

...

void moveTo(int newX, int newY) {

...

}

abstract void draw();

abstract void resize();

}

的每個(gè)非抽象子類(lèi)GraphicObject,例如Circle和Rectangle,必須提供draw和resize方法的實(shí)現(xiàn):

class Circle extends GraphicObject {

void draw() {

...

}

void resize() {

...

}

}

class Rectangle extends GraphicObject {

void draw() {

...

}

void resize() {

...

}

}

當(dāng)抽象類(lèi)實(shí)現(xiàn)接口時(shí)

在上的小節(jié)中 Interfaces,指出實(shí)現(xiàn)接口的類(lèi)必須實(shí)現(xiàn)接口的所有方法。但是,可以定義一個(gè)不實(shí)現(xiàn)接口所有方法的類(lèi),前提是該類(lèi)聲明為abstract。例如,

abstract class X implements Y {

// implements all but one method of Y

}

class XX extends X {

// implements the remaining method in Y

}

在這種情況下,classX必須是abstract因?yàn)樗鼪](méi)有完全實(shí)現(xiàn)Y,但是classXX實(shí)際上卻實(shí)現(xiàn)了Y。

類(lèi)成員

抽象類(lèi)可能具有static字段和static方法。您可以AbstractClass.staticMethod()像使用任何其他類(lèi)一樣將這些靜態(tài)成員與類(lèi)引用一起使用(例如)。

繼承摘要

除了Object該類(lèi)外,一類(lèi)僅具有一個(gè)直接的超類(lèi)。一個(gè)類(lèi)從其所有超類(lèi)(無(wú)論是直接的還是間接的)繼承字段和方法。子類(lèi)可以覆蓋其繼承的方法,也可以隱藏其繼承的字段或方法。(請(qǐng)注意,隱藏字段通常是不好的編程習(xí)慣。)

“覆蓋和隱藏方法”部分中的表 顯示了聲明與超類(lèi)中的方法具有相同簽名的方法的效果。

本Object類(lèi)是類(lèi)層次結(jié)構(gòu)的頂部。所有類(lèi)都是該類(lèi)的后代,并從該類(lèi)繼承方法。從繼承的有用的方法Object包括toString(),equals(),clone(),和getClass()。

您可以通過(guò)final在類(lèi)的聲明中使用關(guān)鍵字來(lái)防止類(lèi)被子類(lèi)化。同樣,可以通過(guò)將方法聲明為最終方法來(lái)防止方法被子類(lèi)覆蓋。

抽象類(lèi)只能被子類(lèi)化。它不能被實(shí)例化。抽象類(lèi)可以包含抽象方法,即已聲明但未實(shí)現(xiàn)的方法。然后,子類(lèi)提供抽象方法的實(shí)現(xiàn)。

問(wèn)題與練習(xí):繼承

問(wèn)題

1.考慮以下兩類(lèi):

public class ClassA {

public void methodOne(int i) {

}

public void methodTwo(int i) {

}

public static void methodThree(int i) {

}

public static void methodFour(int i) {

}

}

public class ClassB extends ClassA {

public static void methodOne(int i) {

}

public void methodTwo(int i) {

}

public void methodThree(int i) {

}

public static void methodFour(int i) {

}

}

一個(gè)。哪個(gè)方法會(huì)覆蓋超類(lèi)中的方法?
b。哪個(gè)方法在超類(lèi)中隱藏了一個(gè)方法?
C。其他方法有什么作用?
2.考慮
Card, Deck以及 DisplayDeck類(lèi)你寫(xiě)的 問(wèn)題和練習(xí)班。Object這些類(lèi)應(yīng)重寫(xiě)哪些方法?

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多