Java由淺入深刨析繼承
茫茫人海千千萬萬,感謝這一秒你看到這里。希望我的面試題系列能對你的有所幫助!共勉!
愿你在未來的日子,保持熱愛,奔赴山海!
Java基礎知識(繼承)
繼承
繼承的介紹
繼承是java面向?qū)ο缶幊碳夹g的一塊基石,因為它允許創(chuàng)建分等級層次的類。描述的是事物之間的所屬關系,這種關系是:is-a 的關系。
繼承:就是子類繼承父類的屬性和行為,使得子類對象(實例)可以直接具有與父類相同的屬性、相同的行為。子類可以直接訪問父類中的非私有的屬性和行為。
生活中的繼承

兔子和長頸鹿屬于食草動物類,老虎和獅子屬于食肉動物類。而食草動物和食肉動物又是屬于動物類。
那是不是兔子、長頸鹿、老虎、獅子都屬于動物類呢?答案是沒錯滴!雖然食草動物和食肉動物都是屬于動物,但是兩者的屬性和行為上有差別,所以子類會具有父類的一般特性也會具有自身的特性。我們就可以再多個類中存在相同屬性和行為時,我們可以將這些內(nèi)容抽取到單獨一個類中,那么多個類無需再定義這些屬性和行為,只要繼承那一個類即可。
繼承的好處
- 提高代碼的復用性(減少代碼冗余,相同代碼重復利用)。
- 使類與類之間產(chǎn)生了關系。
- 子類擁有父類非 private 的屬性、方法。
- 子類可以擁有自己的屬性和方法,即子類可以對父類進行擴展。
- 子類可以用自己的方式實現(xiàn)父類的方法。
- 提高了類之間的耦合性(繼承的缺點,耦合度高就會造成代碼之間的聯(lián)系越緊密,代碼獨立性越差)。
- Java 的繼承是單繼承,但是可以多重繼承,單繼承就是一個子類只能繼承一個父類,多重繼承就是,例如 B 類繼承 A 類,C 類繼承 B 類,所以按照關系就是 B 類是 C 類的父類,A 類是 B 類的父類,這是 Java 繼承區(qū)別于 C++ 繼承的一個特性。
繼承的格式
在Java當中會通過extends關鍵字可以申明一個類是從另外一個類繼承而來的,一般形式如下:
class 父類 {
}
class 子類 extends 父類 {
}
需要注意一點: Java 不支持多繼承,但支持多重繼承。就如下:
class A {
}
class B extends A { (對的)
}class C extends A, B { (錯的)
}class C extends B { (對的)
}

頂層父類是Object類。所有的類默認繼承Object,作為父類。
繼承的demo
編寫一個父類極其對應的子類信息
結構如下:

代碼如下:
父類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沒有額外的屬性和方法:
package com.nz.pojo;
/**
* 繼承了Person特有的name, age,
* 沒有額外的獨有屬性和方法
*/
public class Student extends Person{
}子類Teacher多了一個工資的屬性和獨有的教書方法:
package com.nz.pojo;
/**
* 繼承了Person特有的name, age,
* 多了自己獨有的工資屬性還有獨有的教書方法
*/
public class Teacher extends Person{
// 工資
private double salary ;
// 特有方法
public void teach(){
System.out.println("老師在認真教書!");
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}編寫測試代碼:
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("最愛吃魚罐頭");
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沒有工資屬性,報錯!
System.out.println(student.getName());
System.out.println(student.getAge());
}
}結果如下:
最愛吃魚罐頭
18
1999.99
老師在認真教書!
罐頭
12
從結果來看,子類繼承父類,就可以直接得到父類的成員變量和方法。而子類可以編寫一些特有的屬性和方法,但是是否可以繼承所有成分呢?
子類不能繼承的內(nèi)容
并不是父類的所有內(nèi)容都可以給子類繼承的:
super 與 this 關鍵字
這里先將這兩個關鍵字,super和this在繼承關系中,運用比較頻繁。
- super關鍵字:我們可以通過super關鍵字來實現(xiàn)對父類成員的訪問,用來引用當前對象的父類。
- this關鍵字:指向自己本類的引用。
super和this完整的用法如下:
this.成員變量 -- 本類的
super.成員變量 -- 父類的this.成員方法名() -- 本類的
super.成員方法名() -- 父類的
- 具體演示,創(chuàng)建測試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)用結果如下:
animal : eat
cat : eat
animal : eat
- 注意:
子類的每個構造方法中均有默認的super(),調(diào)用父類的空參構造。手動調(diào)用父類構造會覆蓋默認的super()。
super() 和 this() 都必須是在構造方法的第一行,所以不能同時出現(xiàn)。
構造器不能被繼承
- 子類不能繼承父類的構造器(構造方法或者構造函數(shù)),它只是調(diào)用(隱式或顯式)。因為子類有自己的構造器。值得注意的是子類可以繼承父類的私有成員(成員變量,方法),只是子類無法直接訪問而已,可以通過
getter/setter方法訪問父類的private成員變量。 - 如果父類的構造器帶有參數(shù),則必須在子類的構造器中顯式地通過
super關鍵字調(diào)用父類的構造器并配以適當?shù)膮?shù)列表。 - 如果父類構造器沒有參數(shù),則在子類的構造器中不需要使用
super關鍵字調(diào)用父類構造器,系統(tǒng)會自動調(diào)用父類的無參構造器。 - 演示過程:
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)用了父類的無參構造器: Person()");
}
Person(String name) {
System.out.println("調(diào)用了父類的帶參構造器: Person(String name)");
this.name = name;
}
}
// Teacher子類繼承Person
class Teacher extends Person{
private String name;
Teacher(){
// 自動調(diào)用父類的無參數(shù)構造器 因為會有默認super();
System.out.println("Teacher");
}
public Teacher(String name){
super("最愛吃魚罐頭"); // 調(diào)用父類中帶有參數(shù)的構造器
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ù)的構造器
System.out.println("SubClass2");
}
public Student(String name){ // 自動調(diào)用父類的無參數(shù)構造器
System.out.println("Student(String name):"+name);
this.name = name;
}
}結果如下:
------Teacher 類繼承------
調(diào)用了父類的無參構造器: Person()
Teacher
調(diào)用了父類的帶參構造器: Person(String name)
Teacher(String name):張三
------Student 類繼承------
調(diào)用了父類的帶參構造器: Person(String name)
SubClass2
調(diào)用了父類的無參構造器: Person()
Student(String name):張三三
final修飾的類不能被繼承
final 關鍵字主要用在三個地方:變量、方法、類。
- 修飾類:表示該類不能被繼承;
- 修飾方法:表示方法不能被重寫;
- 修飾變量:表示變量只能一次賦值以后值不能被修改(常量)。
final 的特點:
- 對于一個 final 變量,如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始 化之后便不能更改;如果是引用類型的變量,則在對其初始化之后便不 能再讓其指向另一個對象。
- 當用 final 修飾一個類時,表明這個類不能被繼承。final 類中的所有成員 方法都會被隱式地指定為 final 方法。
- 使用 final 方法的原因有兩個。第一個原因是把方法鎖定,以防任何繼承 類修改它的含義;第二個原因是效率。在早期的 Java 實現(xiàn)版本中,會將 final 方法轉(zhuǎn)為內(nèi)嵌調(diào)用。但是如果方法過于龐大,可能看不到內(nèi)嵌調(diào)用 帶來的任何性能提升(現(xiàn)在的 Java 版本已經(jīng)不需要使用 final方法進行這些優(yōu)化了)。類中所有的 private 方法都隱式地指定為 final。
我們測試下修飾類后到底能不能繼承:
package com.nz;
public class InheritDemo4 {
}
// 父類
final class Fu {
private String name;
}
//class Zi extends Fu{ // Cannot inherit from final 'com.nz.Fu' 會顯示沒辦法繼承Fu
//}結果:可以看出來在被final修飾的Fu類沒辦法繼承,而且在編譯期間就會報錯了,沒辦法通過運行。
方法重寫
介紹
子類中出現(xiàn)與父類一模一樣的方法時(返回值類型,方法名和參數(shù)列表都相同),會出現(xiàn)覆蓋效果,也稱為重寫或者復寫。聲明不變,重新實現(xiàn)。
使用場景與案例
發(fā)生在子父類之間的關系。 子類繼承了父類的方法,但是子類覺得父類的這方法不足以滿足自己的需求,子類重新寫了一個與父類同名的方法,以便覆蓋父類的該方法。
寫個測試案例:
package com.nz;
public class InheritDemo5 {
public static void main(String[] args) {
// 創(chuàng)建子類對象
Cat lanMao = new Cat();
// 調(diào)用父類繼承而來的方法
lanMao.run();
// 調(diào)用子類重寫的方法
lanMao.sing();
}
}
class Animal{
public void sing(){
System.out.println("動物都可以唱歌!");
}
public void run(){
System.out.println("動物都可以跑!");
}
}
class Cat extends Animal {
public void sing(){
System.out.println("我們一起學貓叫,一起喵喵喵!讓我們一起撒個嬌");
}
}運行結果:
動物都可以跑!
我們一起學貓叫,一起喵喵喵!讓我們一起撒個嬌
可以看出,藍貓調(diào)用了重寫后的sing方法。
@Override重寫注解
- @Override:注解,重寫注解校驗!
- 這個注解標記的方法,就說明這個方法必須是重寫父類的方法,否則編譯階段報錯。
- 建議重寫都加上這個注解,一方面可以提高代碼的可讀性,一方面可以防止重寫出錯!
加上后的子類代碼形式如下:
class Cat extends Animal {
// 聲明不變,重新實現(xiàn)
// 方法名稱與父類全部一樣,只是方法體中的功能重寫了!
@Override
public void sing(){
System.out.println("我們一起學貓叫,一起喵喵喵!讓我們一起撒個嬌");
}
}注意事項
- 方法重寫是發(fā)生在子父類之間的關系。
- 子類方法覆蓋父類方法,必須要保證權限大于等于父類權限。
- 子類方法覆蓋父類方法,返回值類型、函數(shù)名和參數(shù)列表都要一模一樣。、
完結
相信各位看官看到這里,都對Java繼承有了一定的了解吧,繼承在Java的特性里還是占據(jù)比較大得多作用,他還有很多特點:
- 高代碼的復用性(減少代碼冗余,相同代碼重復利用)。
- 使類與類之間產(chǎn)生了關系。
- 子類擁有父類非 private 的屬性、方法。
- 子類可以擁有自己的屬性和方法,即子類可以對父類進行擴展,可以用自己的方式實現(xiàn)父類的方法。
- 提高了類之間的耦合性(繼承的缺點,耦合度高就會造成代碼之間的聯(lián)系越緊密,代碼獨立性越差)。
讓我們也一起加油吧!本人不才,如有什么缺漏、錯誤的地方,也歡迎各位人才大佬評論中批評指正!
學到這里,今天的世界打烊了,晚安!雖然這篇文章完結了,但是我還在,永不完結。我會努力保持寫文章。來日方長,何懼車遙馬慢!
感謝各位看到這里!愿你韶華不負,青春無悔!

到此這篇關于Java由淺入深刨析繼承的文章就介紹到這了,更多相關Java 繼承內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java實戰(zhàn)項目 醫(yī)院預約掛號系統(tǒng)
本文是一個Java語言編寫的實戰(zhàn)項目,是一個醫(yī)院預約掛號系統(tǒng),主要用到了jdbc+jsp+mysql+ajax等技術,技術含量比較高,感興趣的童鞋跟著小編往下看吧2021-09-09
java開發(fā)RocketMQ之NameServer路由管理源碼分析
這篇文章主要為大家介紹了java開發(fā)中RocketMQ之NameServer路由管理源碼分析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2021-11-11
詳解context root修改無效web修改項目路徑(eclipse)
這篇文章主要介紹了詳解context root修改無效web修改項目路徑(eclipse)的相關資料,需要的朋友可以參考下2017-04-04

