相關文章:html
在《面向對象再探究》這篇文章中已經籠統的介紹過繼承的概念了,下面就來具體介紹繼承的使用等相關問題。java
以Animal
類和Dog
類例子,下文都會圍繞該例展開。oracle
public class Animal { private String name; private int age; public Animal(String name, int age) { this.name = name; this.age = age; } public Animal() { } public void say() { System.out.println("我是" + name + ",今年" + age + "歲了"); } //getters and setters ... }
public class Dog extends Animal { private String address; public Dog(String name, int age, String address) { super(name, age); this.address = address; } public Dog() { } public void say() { System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "歲了,家住" + address + ",汪汪汪..."); } public void watchDoor() { System.out.println("我在" + address +"看門..."); } //getters and setters ... }
Dog
類繼承Animal
類,Animal
類有name
、age
屬性和say()
方法,Dog
類增長了address
屬性和watchDoor()
方法。this
在現實生活中有許多繼承的例子,好比「子承父業」、「繼承父母財產」、「繼承某人意志」等,這些都是在強調一個體獲得另外一個體的東西,他們之間存在「繼承關係」。設計
在Java中,繼承是類和類之間的關係。在《面向對象再探究》這篇文章中舉了動物Animal
類和狗Dog
類、貓Cat
類、兔子Rabbit
類的例子並寫了代碼,這裏直接拿來用再也不列出,請移步此文章。code
咱們能夠說狗、貓、兔子是動物,但不能夠說動物是狗、貓、兔子。動物廣泛有眼睛、耳朵等屬性,有跑、吃、叫等行爲。狗顯然也具備這些屬性和行爲,可是狗也具備一些它特有的屬性和行爲,好比靈敏的鼻子、看門等。htm
在這個例子中,Animal
類是父類,Dog
類、Cat
類、Rabbit
類是子類。子類和父類存在繼承關係,能夠說:子類「是」父類,該關係是繼承的一個明顯特徵。對象
下面是關於繼承的幾個Q&A:繼承
Q1: 何時須要用到繼承?教程
A1: 我的認爲可從如下兩點出發:
Q2: 怎樣使用繼承?
A2: 子類使用extends
關鍵字繼承父類,也只有使用了該關鍵字後,才存在繼承關係及「父子類」:
public class Animal {//父類 //屬性和方法 }
public class Dog extends Animal {//子類繼承父類 //屬性和方法 }
Q3: 在具體開發中,是先編寫父類,而後擴展出子類,仍是先編寫子類,而後抽象出父類?
A3: 我的認爲不能一律而論。若是你的系統設計很是好,能夠先寫好父類,而後擴展子類。若是你沒設計好,或者考慮不周,那麼後期可能會出現許多類有重複代碼,這時候能夠考慮抽取父類。
Q4: 父類和子類在內容上有什麼區別?
A4: 一般,咱們將更通用的一些屬性和方法放到父類中,好比狗、貓、兔子都具備的屬性和方法會方法動物類中。子類中是更加特別的屬性和方法,好比狗的看門行爲、貓的抓老鼠行爲。因爲子類繼承了父類,因此子類中只須要編寫和父類的不一樣之處。
因此,子類每每會比父類擁有更加豐富的屬性和方法。
Q5: 子類繼承的父類的哪些東西?
A5: 這裏先給出結論,下文再詳細介紹。子類繼承了父類的非私有private
的成員變量、方法、嵌套類,子類不繼承父類的構造器,可是子類能夠調用父類的構造器。
Q6: Java中能夠繼承多個類嗎?
A6: Java中的繼承是單繼承,只能繼承一個類。
有時子類從父類繼承獲得的方法不必定適用,這時子類能夠重寫父類的方法。如Dog
類重寫了其父類的say()
方法。
注意要和重載加以區分。
簡單來講,重寫涉及到的是兩個類的同名方法,重載涉及到的是一個類的同名方法。關於重載介紹請移步這裏。
前面提到:子類是對父類的擴展,子類內容比父類更加豐富。因此一般子類都會有本身的屬性和方法,好比Dog
類的address
屬性和watchDoor()
方法。
子類不繼承父類的私有成員,可是若是父類有能訪問其私有成員變量的public
或protected
的方法(好比getter方法),那麼子類能夠經過繼承這些方法來使用父類的私有方法(Java官方教程)。
下面用上面的代碼例子解釋:
Animal
類有私有成員變量、和公有方法say()
。say()
直接訪問本類的私有成員變量,沒毛病!
public class Animal { private String name; private int age; public void say() { System.out.println("我是" + name + ",今年" + age + "歲了"); } //其餘代碼... }
如今Dog
類繼承Anima
類
public class Dog extends Animal { private String address; public void say() {//name和age報紅 System.out.println("我叫" + name + ",今年" + age + "歲了,家住" + address + ",汪汪汪..."); } //其餘代碼... }
請注意Dog
類的say()
方法,直接訪問了name
和age
屬性,若是子類繼承了父類的私有成員,那麼這樣寫是沒問題的,但事實是name
和age
報紅了,說明子類沒有繼承父類的私有成員。
雖然子類沒有繼承父類的私有成員,可是咱們能夠經過父類的公有方法使用其私有成員變量,代碼改動以下:
public class Dog extends Animal { private String address; public void say() { System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "歲了,家住" + address + ",汪汪汪..."); } //其餘代碼... }
使用super.xxx()
能夠調用父類的方法,因爲getName()
是父類公有方法,且能訪問父類的私有成員變量name
,因此子類調用getName()
方法可使用name
變量。
子類沒有繼承父類的私有成員變量,固然不能直接賦值。一般有兩種方法:調用父類的公有setter方法或調用父類的構造器。本質上仍是子類經過使用父類提供的公有方法(setter或構造器)使用其私有成員變量。
public class Dog extends Animal { private String address; public void setName(String name) { super.setName(name); //注意super } public void setAge(int age) { super.setAge(age); } public void say() { System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "歲了,家住" + address + ",汪汪汪..."); } //其餘代碼... }
Dog
類的兩個setter方法調用了Animal
類的兩個setter方法,因爲子類的setter方法名和父類的setter方法名取得同樣(重寫了),因此必定要使用super
關鍵字加以區分,不然就成遞歸了。
public class Dog extends Animal { private String address; public Dog(String name, int age, String address) { super(name, age); //調用父類構造器 this.address = address; } public Dog() { } public void say() { System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "歲了,家住" + address + ",汪汪汪..."); } //其餘代碼... }
public class Animal { private String name; private int age; public Animal(String name, int age) { this.name = name; this.age = age; } //其餘代碼... }
子類使用super()
語句調用父類構造器,該語句必須是子類構造器的第一行代碼。
若是子類構造器沒有顯式調用父類構造器,則會默認調用父類的無參構造器。因此若是父類沒有無參構造器,而子類又沒有顯式調用父類的其餘構造器,則會報錯。
若有錯誤,還請指正。