Java由淺入深刨析繼承
茫茫人海千千萬(wàn)萬(wàn),感謝這一秒你看到這里。希望我的面試題系列能對(duì)你的有所幫助!共勉!
愿你在未來(lái)的日子,保持熱愛(ài),奔赴山海!
Java基礎(chǔ)知識(shí)(繼承)
繼承
繼承的介紹
繼承是java面向?qū)ο缶幊碳夹g(shù)的一塊基石,因?yàn)樗试S創(chuàng)建分等級(jí)層次的類。描述的是事物之間的所屬關(guān)系,這種關(guān)系是:is-a
的關(guān)系。
繼承:就是子類繼承父類的屬性和行為,使得子類對(duì)象(實(shí)例)可以直接具有與父類相同的屬性、相同的行為。子類可以直接訪問(wèn)父類中的非私有的屬性和行為。
生活中的繼承
兔子和長(zhǎng)頸鹿屬于食草動(dòng)物類,老虎和獅子屬于食肉動(dòng)物類。而食草動(dòng)物和食肉動(dòng)物又是屬于動(dòng)物類。
那是不是兔子、長(zhǎng)頸鹿、老虎、獅子都屬于動(dòng)物類呢?答案是沒(méi)錯(cuò)滴!雖然食草動(dòng)物和食肉動(dòng)物都是屬于動(dòng)物,但是兩者的屬性和行為上有差別,所以子類會(huì)具有父類的一般特性也會(huì)具有自身的特性。我們就可以再多個(gè)類中存在相同屬性和行為時(shí),我們可以將這些內(nèi)容抽取到單獨(dú)一個(gè)類中,那么多個(gè)類無(wú)需再定義這些屬性和行為,只要繼承那一個(gè)類即可。
繼承的好處
- 提高代碼的復(fù)用性(減少代碼冗余,相同代碼重復(fù)利用)。
- 使類與類之間產(chǎn)生了關(guān)系。
- 子類擁有父類非 private 的屬性、方法。
- 子類可以擁有自己的屬性和方法,即子類可以對(duì)父類進(jìn)行擴(kuò)展。
- 子類可以用自己的方式實(shí)現(xiàn)父類的方法。
- 提高了類之間的耦合性(繼承的缺點(diǎn),耦合度高就會(huì)造成代碼之間的聯(lián)系越緊密,代碼獨(dú)立性越差)。
- Java 的繼承是單繼承,但是可以多重繼承,單繼承就是一個(gè)子類只能繼承一個(gè)父類,多重繼承就是,例如 B 類繼承 A 類,C 類繼承 B 類,所以按照關(guān)系就是 B 類是 C 類的父類,A 類是 B 類的父類,這是 Java 繼承區(qū)別于 C++ 繼承的一個(gè)特性。
繼承的格式
在Java當(dāng)中會(huì)通過(guò)extends
關(guān)鍵字可以申明一個(gè)類是從另外一個(gè)類繼承而來(lái)的,一般形式如下:
class 父類 {
}
class 子類 extends 父類 {
}
需要注意一點(diǎn): Java 不支持多繼承,但支持多重繼承。就如下:
class A {
}
class B extends A { (對(duì)的)
}class C extends A, B { (錯(cuò)的)
}class C extends B { (對(duì)的)
}
頂層父類是Object類。所有的類默認(rèn)繼承Object,作為父類。
繼承的demo
編寫(xiě)一個(gè)父類極其對(duì)應(yīng)的子類信息
結(jié)構(gòu)如下:
代碼如下:
父類Person:
package com.nz.pojo; public class Person { private String name ; private int age ; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
子類Student沒(méi)有額外的屬性和方法:
package com.nz.pojo; /** * 繼承了Person特有的name, age, * 沒(méi)有額外的獨(dú)有屬性和方法 */ public class Student extends Person{ }
子類Teacher多了一個(gè)工資的屬性和獨(dú)有的教書(shū)方法:
package com.nz.pojo; /** * 繼承了Person特有的name, age, * 多了自己獨(dú)有的工資屬性還有獨(dú)有的教書(shū)方法 */ public class Teacher extends Person{ // 工資 private double salary ; // 特有方法 public void teach(){ System.out.println("老師在認(rèn)真教書(shū)!"); } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } }
編寫(xiě)測(cè)試代碼:
package com.nz; import com.nz.pojo.Student; import com.nz.pojo.Teacher; public class InheritDemo { public static void main(String[] args) { Teacher teacher = new Teacher(); teacher.setName("最愛(ài)吃魚(yú)罐頭"); teacher.setAge(18); teacher.setSalary(1999.99); System.out.println(teacher.getName()); System.out.println(teacher.getAge()); System.out.println(teacher.getSalary()); teacher.teach(); Student student = new Student(); student.setName("罐頭"); student.setAge(12); //student.setSalary(1999.99); // student沒(méi)有工資屬性,報(bào)錯(cuò)! System.out.println(student.getName()); System.out.println(student.getAge()); } }
結(jié)果如下:
最愛(ài)吃魚(yú)罐頭
18
1999.99
老師在認(rèn)真教書(shū)!
罐頭
12
從結(jié)果來(lái)看,子類繼承父類,就可以直接得到父類的成員變量和方法。而子類可以編寫(xiě)一些特有的屬性和方法,但是是否可以繼承所有成分呢?
子類不能繼承的內(nèi)容
并不是父類的所有內(nèi)容都可以給子類繼承的:
super 與 this 關(guān)鍵字
這里先將這兩個(gè)關(guān)鍵字,super和this在繼承關(guān)系中,運(yùn)用比較頻繁。
- super關(guān)鍵字:我們可以通過(guò)super關(guān)鍵字來(lái)實(shí)現(xiàn)對(duì)父類成員的訪問(wèn),用來(lái)引用當(dāng)前對(duì)象的父類。
- this關(guān)鍵字:指向自己本類的引用。
super和this完整的用法如下:
this.成員變量 -- 本類的
super.成員變量 -- 父類的this.成員方法名() -- 本類的
super.成員方法名() -- 父類的
- 具體演示,創(chuàng)建測(cè)試InheritDemo2:
package com.nz; public class InheritDemo2 { public static void main(String[] args) { Animal a = new Animal(); a.eat(); Cat cat = new Cat(); cat.eatFish(); } } class Animal { void eat() { System.out.println("animal : eat"); } } class Cat extends Animal { void eat() { System.out.println("cat : eat"); } void eatFish() { this.eat(); // this 調(diào)用自己的方法 super.eat(); // super 調(diào)用父類方法 } }
調(diào)用結(jié)果如下:
animal : eat
cat : eat
animal : eat
- 注意:
子類的每個(gè)構(gòu)造方法中均有默認(rèn)的super(),調(diào)用父類的空參構(gòu)造。手動(dòng)調(diào)用父類構(gòu)造會(huì)覆蓋默認(rèn)的super()。
super() 和 this() 都必須是在構(gòu)造方法的第一行,所以不能同時(shí)出現(xiàn)。
構(gòu)造器不能被繼承
- 子類不能繼承父類的構(gòu)造器(構(gòu)造方法或者構(gòu)造函數(shù)),它只是調(diào)用(隱式或顯式)。因?yàn)樽宇愑凶约旱臉?gòu)造器。值得注意的是子類可以繼承父類的私有成員(成員變量,方法),只是子類無(wú)法直接訪問(wèn)而已,可以通過(guò)
getter/setter
方法訪問(wèn)父類的private成員變量。 - 如果父類的構(gòu)造器帶有參數(shù),則必須在子類的構(gòu)造器中顯式地通過(guò)
super
關(guān)鍵字調(diào)用父類的構(gòu)造器并配以適當(dāng)?shù)膮?shù)列表。 - 如果父類構(gòu)造器沒(méi)有參數(shù),則在子類的構(gòu)造器中不需要使用
super
關(guān)鍵字調(diào)用父類構(gòu)造器,系統(tǒng)會(huì)自動(dòng)調(diào)用父類的無(wú)參構(gòu)造器。 - 演示過(guò)程:
package com.nz; public class InheritDemo3 { public static void main(String[] args) { System.out.println("------Teacher 類繼承------"); Teacher teacher = new Teacher(); Teacher teacher2 = new Teacher("張三"); System.out.println("------Student 類繼承------"); Student student = new Student(); Student student2 = new Student("張三三"); } } // 父類 class Person { private String name; Person(){ System.out.println("調(diào)用了父類的無(wú)參構(gòu)造器: Person()"); } Person(String name) { System.out.println("調(diào)用了父類的帶參構(gòu)造器: Person(String name)"); this.name = name; } } // Teacher子類繼承Person class Teacher extends Person{ private String name; Teacher(){ // 自動(dòng)調(diào)用父類的無(wú)參數(shù)構(gòu)造器 因?yàn)闀?huì)有默認(rèn)super(); System.out.println("Teacher"); } public Teacher(String name){ super("最愛(ài)吃魚(yú)罐頭"); // 調(diào)用父類中帶有參數(shù)的構(gòu)造器 System.out.println("Teacher(String name):"+name); this.name = name; } } // Student子類繼承Person class Student extends Person{ private String name; Student(){ super("heihei"); // 調(diào)用父類中帶有參數(shù)的構(gòu)造器 System.out.println("SubClass2"); } public Student(String name){ // 自動(dòng)調(diào)用父類的無(wú)參數(shù)構(gòu)造器 System.out.println("Student(String name):"+name); this.name = name; } }
結(jié)果如下:
------Teacher 類繼承------
調(diào)用了父類的無(wú)參構(gòu)造器: Person()
Teacher
調(diào)用了父類的帶參構(gòu)造器: Person(String name)
Teacher(String name):張三
------Student 類繼承------
調(diào)用了父類的帶參構(gòu)造器: Person(String name)
SubClass2
調(diào)用了父類的無(wú)參構(gòu)造器: Person()
Student(String name):張三三
final修飾的類不能被繼承
final 關(guān)鍵字主要用在三個(gè)地方:變量、方法、類。
- 修飾類:表示該類不能被繼承;
- 修飾方法:表示方法不能被重寫(xiě);
- 修飾變量:表示變量只能一次賦值以后值不能被修改(常量)。
final 的特點(diǎn):
- 對(duì)于一個(gè) final 變量,如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始 化之后便不能更改;如果是引用類型的變量,則在對(duì)其初始化之后便不 能再讓其指向另一個(gè)對(duì)象。
- 當(dāng)用 final 修飾一個(gè)類時(shí),表明這個(gè)類不能被繼承。final 類中的所有成員 方法都會(huì)被隱式地指定為 final 方法。
- 使用 final 方法的原因有兩個(gè)。第一個(gè)原因是把方法鎖定,以防任何繼承 類修改它的含義;第二個(gè)原因是效率。在早期的 Java 實(shí)現(xiàn)版本中,會(huì)將 final 方法轉(zhuǎn)為內(nèi)嵌調(diào)用。但是如果方法過(guò)于龐大,可能看不到內(nèi)嵌調(diào)用 帶來(lái)的任何性能提升(現(xiàn)在的 Java 版本已經(jīng)不需要使用 final方法進(jìn)行這些優(yōu)化了)。類中所有的 private 方法都隱式地指定為 final。
我們測(cè)試下修飾類后到底能不能繼承:
package com.nz; public class InheritDemo4 { } // 父類 final class Fu { private String name; } //class Zi extends Fu{ // Cannot inherit from final 'com.nz.Fu' 會(huì)顯示沒(méi)辦法繼承Fu //}
結(jié)果:可以看出來(lái)在被final修飾的Fu類沒(méi)辦法繼承,而且在編譯期間就會(huì)報(bào)錯(cuò)了,沒(méi)辦法通過(guò)運(yùn)行。
方法重寫(xiě)
介紹
子類中出現(xiàn)與父類一模一樣的方法時(shí)(返回值類型,方法名和參數(shù)列表都相同),會(huì)出現(xiàn)覆蓋效果,也稱為重寫(xiě)或者復(fù)寫(xiě)。聲明不變,重新實(shí)現(xiàn)。
使用場(chǎng)景與案例
發(fā)生在子父類之間的關(guān)系。 子類繼承了父類的方法,但是子類覺(jué)得父類的這方法不足以滿足自己的需求,子類重新寫(xiě)了一個(gè)與父類同名的方法,以便覆蓋父類的該方法。
寫(xiě)個(gè)測(cè)試案例:
package com.nz; public class InheritDemo5 { public static void main(String[] args) { // 創(chuàng)建子類對(duì)象 Cat lanMao = new Cat(); // 調(diào)用父類繼承而來(lái)的方法 lanMao.run(); // 調(diào)用子類重寫(xiě)的方法 lanMao.sing(); } } class Animal{ public void sing(){ System.out.println("動(dòng)物都可以唱歌!"); } public void run(){ System.out.println("動(dòng)物都可以跑!"); } } class Cat extends Animal { public void sing(){ System.out.println("我們一起學(xué)貓叫,一起喵喵喵!讓我們一起撒個(gè)嬌"); } }
運(yùn)行結(jié)果:
動(dòng)物都可以跑!
我們一起學(xué)貓叫,一起喵喵喵!讓我們一起撒個(gè)嬌
可以看出,藍(lán)貓調(diào)用了重寫(xiě)后的sing方法。
@Override重寫(xiě)注解
- @Override:注解,重寫(xiě)注解校驗(yàn)!
- 這個(gè)注解標(biāo)記的方法,就說(shuō)明這個(gè)方法必須是重寫(xiě)父類的方法,否則編譯階段報(bào)錯(cuò)。
- 建議重寫(xiě)都加上這個(gè)注解,一方面可以提高代碼的可讀性,一方面可以防止重寫(xiě)出錯(cuò)!
加上后的子類代碼形式如下:
class Cat extends Animal { // 聲明不變,重新實(shí)現(xiàn) // 方法名稱與父類全部一樣,只是方法體中的功能重寫(xiě)了! @Override public void sing(){ System.out.println("我們一起學(xué)貓叫,一起喵喵喵!讓我們一起撒個(gè)嬌"); } }
注意事項(xiàng)
- 方法重寫(xiě)是發(fā)生在子父類之間的關(guān)系。
- 子類方法覆蓋父類方法,必須要保證權(quán)限大于等于父類權(quán)限。
- 子類方法覆蓋父類方法,返回值類型、函數(shù)名和參數(shù)列表都要一模一樣。、
完結(jié)
相信各位看官看到這里,都對(duì)Java繼承有了一定的了解吧,繼承在Java的特性里還是占據(jù)比較大得多作用,他還有很多特點(diǎn):
- 高代碼的復(fù)用性(減少代碼冗余,相同代碼重復(fù)利用)。
- 使類與類之間產(chǎn)生了關(guān)系。
- 子類擁有父類非 private 的屬性、方法。
- 子類可以擁有自己的屬性和方法,即子類可以對(duì)父類進(jìn)行擴(kuò)展,可以用自己的方式實(shí)現(xiàn)父類的方法。
- 提高了類之間的耦合性(繼承的缺點(diǎn),耦合度高就會(huì)造成代碼之間的聯(lián)系越緊密,代碼獨(dú)立性越差)。
讓我們也一起加油吧!本人不才,如有什么缺漏、錯(cuò)誤的地方,也歡迎各位人才大佬評(píng)論中批評(píng)指正!
學(xué)到這里,今天的世界打烊了,晚安!雖然這篇文章完結(jié)了,但是我還在,永不完結(jié)。我會(huì)努力保持寫(xiě)文章。來(lái)日方長(zhǎng),何懼車遙馬慢!
感謝各位看到這里!愿你韶華不負(fù),青春無(wú)悔!
到此這篇關(guān)于Java由淺入深刨析繼承的文章就介紹到這了,更多相關(guān)Java 繼承內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java 程序里transient關(guān)鍵字使用方法示例
這篇文章主要為大家介紹了Java 程序里transient關(guān)鍵字使用方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11Java實(shí)戰(zhàn)項(xiàng)目 醫(yī)院預(yù)約掛號(hào)系統(tǒng)
本文是一個(gè)Java語(yǔ)言編寫(xiě)的實(shí)戰(zhàn)項(xiàng)目,是一個(gè)醫(yī)院預(yù)約掛號(hào)系統(tǒng),主要用到了jdbc+jsp+mysql+ajax等技術(shù),技術(shù)含量比較高,感興趣的童鞋跟著小編往下看吧2021-09-09java開(kāi)發(fā)RocketMQ之NameServer路由管理源碼分析
這篇文章主要為大家介紹了java開(kāi)發(fā)中RocketMQ之NameServer路由管理源碼分析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2021-11-11詳解context root修改無(wú)效web修改項(xiàng)目路徑(eclipse)
這篇文章主要介紹了詳解context root修改無(wú)效web修改項(xiàng)目路徑(eclipse)的相關(guān)資料,需要的朋友可以參考下2017-04-04Java反射機(jī)制的學(xué)習(xí)總結(jié)
總的來(lái)說(shuō),java反射機(jī)制是一個(gè)很好用的東西,用它可以解決很多死的東西,因?yàn)榉瓷錂C(jī)制的靈活行很大,有了他,我們就不要花太多的時(shí)間來(lái)寫(xiě)操做數(shù)據(jù)庫(kù)的代碼了,而是方法更多的時(shí)間在項(xiàng)目的邏輯功能上,這個(gè)可以很大的減少開(kāi)發(fā)時(shí)間,而且代碼的可讀性好2013-09-09