一、繼承(extends)
1.1、繼承是什么
繼承就是 Java 允許我們用 extends 關(guān)鍵字,讓一個(gè)類與另一個(gè)類建立起一種父子關(guān)系;
被繼承的類稱為父類(基類、超類),繼承父類的類都稱為子類(派生類) ,當(dāng)子類繼承父類后,就可以直接使用父類公共的屬性和方法了
當(dāng)子類繼承父類后,就可以直接使用父類公共的屬性和方法了
2.2、繼承的用處
來(lái)看看下面兩個(gè)類
- 可以看到,一個(gè)是學(xué)生類,一個(gè)是老師類;他們之間都有著相同的特征:成員變量、方法;
- 這樣的話,重復(fù)代碼又多了,是一種很不好的現(xiàn)象。
我們使用繼承,來(lái)優(yōu)化代碼
這樣減少代碼冗余,提高了代碼的復(fù)用性,增強(qiáng)類的功能擴(kuò)展性。
2.3、繼承的語(yǔ)法
? 修飾符 class 子類名 extends 父類名
//父類:定義了一個(gè)公用方法ports
public class People {
public void ports(){
System.out.println("父類方法被調(diào)用!");
}
}
//子類:使用extends繼承了來(lái)自父類的people類
public class Student extends People{
}
public class ExtendsTest01 {
public static void main(String[] args) {
//創(chuàng)建student子類對(duì)象
Student s = new Student();
//由于student類繼承了people類,所以子類可以調(diào)用父類的公用方法
s.ports();
}
2.4、繼承的設(shè)計(jì)規(guī)范
子類們相同特征:共性屬性,共性方法;都放在父類中定義;
子類獨(dú)有的屬性,方法;應(yīng)該定義在子類自己里面。
// 人類:父類
// 包含了子類相同的屬性和行為
public class People {
// 1.定義需求中子類們相同的屬性
private String name;
private int age;
// 2.提供屬性對(duì)應(yīng)的getter,setter方法,暴露其取值和賦值
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;
}
// 3.定義子類們相同的行為方法:查看課表
public void queryCourse(){
System.out.println(name+"查看了課表");
}
}
//學(xué)生類:子類繼承People02父類得到屬性和行為
public class Student extends People{
// 1.定義學(xué)生子類自己獨(dú)有的屬性
private String className;
// 2.提供屬性的getter和setter方法,暴露其取值和賦值
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
// 3.定義子類自己獨(dú)有的行為方法:填寫(xiě)聽(tīng)課反饋
public void writeInfo(){
System.out.println(className+"的"+getName()+"對(duì)老師給出極高的評(píng)價(jià)!");
}
}
//教師類:子類 繼承父類得到屬性和行為
public class Teacher extends People{
// 1.定義子類自己的獨(dú)有屬性
private String departmentName;
// 2.提供屬性對(duì)應(yīng)的getter,setter方法,暴露其取值和賦值
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
// 3.定義子類自己獨(dú)有的行為方法:發(fā)布問(wèn)題
public void problem(){
System.out.println(departmentName+"的"+getName()+"老師問(wèn):這節(jié)課教的怎么樣?");
}
}
//繼承測(cè)試類
public class ExtendsTest {
public static void main(String[] args) {
// 1.創(chuàng)建學(xué)生對(duì)象
Student02 s = new Student02();
// 1.1調(diào)用父類行為方法寫(xiě)入學(xué)生信息
s.setName("海綿寶寶");
s.setAge(36);
// 1.2調(diào)用學(xué)生類自己的方法寫(xiě)入所在班級(jí)
s.setClassName("19級(jí)比奇堡駕校一班");
// 1.3調(diào)用父類的行為方法:查看課表
s.queryCourse();
System.out.println("---------------");
// 2.創(chuàng)建教師對(duì)象
Teacher02 t = new Teacher02();
// 2.1調(diào)用父類行為寫(xiě)入教師信息
t.setName("泡芙");
t.setAge(55);
// 2.2調(diào)用教師類自己的方法寫(xiě)入部門(mén)名稱
t.setDepartmentName("比奇堡駕校金牌教練組");
// 2.3調(diào)用父類的行為方法:查看課表
t.queryCourse();
System.out.println("---------------");
// 3.調(diào)用教師子類自己獨(dú)有的方法:problem 發(fā)布問(wèn)題
t.problem();
// 4.調(diào)用學(xué)生子類自己獨(dú)有的方法:writeInfo 填寫(xiě)反饋
s.writeInfo();
}
}
控制臺(tái)輸出結(jié)果:
2.5、繼承的特點(diǎn)
子類可以繼承父類的屬性和行為,但是子類不能繼承父類的構(gòu)造器;
java 是單繼承模式:一個(gè)類 只能繼承一個(gè)直接父類;
- 比如你,只能有一個(gè)親爸,不可能隔壁的老王叔、老楊叔 … 都是你的親爸吧? 那從倫理角度看,肯定是不支持
- 從 Java 的角度的角度看,多繼承會(huì)造成代碼二義性,因此不支持
Java 不支持多繼承,但是支持多層繼承;
- 就是你 不可以繼承多個(gè)爸爸;但是你可以繼承你爸的,你爸可以繼承你爺爺?shù)模鄬永^承;
- 子類A 繼承父類B;父類B 可以繼承父類 C
Java 中所有的類都是 Object 類的子類。
- java 中所有的類,要么是直接繼承了 Object 類,要么默認(rèn)繼承了 Object 類,要么間接繼承了 Object 類;
二、繼承中成員訪問(wèn)的特點(diǎn)
2.1、繼承中變量訪問(wèn)的特點(diǎn)
在子類方法中訪問(wèn)一個(gè)變量,采用的是就近原則。
- 子類局部范圍找
- 子類成員范圍找
- 父類成員范圍找
- 如果都沒(méi)有就報(bào)錯(cuò)(不考慮父親的父親…)
class Fu {
int num = 10;
}
class Zi extends Fu{
//int num = 20;
public void show(){
//num = 30;
System.out.println(num);
}
}
public class Demo1 {
public static void main(String[] args) {
Zi z = new Zi()?
z.show()? // 輸出10
}
}
2.2、super
this & super 關(guān)鍵字:
- this:代表本類對(duì)象的引用
- super:代表父類存儲(chǔ)空間的標(biāo)識(shí)(可以理解為父類對(duì)象引用)
在子類方法中,如果想要明確訪問(wèn)父類中成員時(shí),借助super關(guān)鍵字即可。
this 和 super 的使用分別
- 成員變量:
- this. 成員變量 - 訪問(wèn)本類成員變量
- super. 成員變量 - 訪問(wèn)父類成員變量
- 成員方法:
- this. 成員方法 - 訪問(wèn)本類成員方法
- super. 成員方法 - 訪問(wèn)父類成員方法
- 構(gòu)造方法:
- this(…) - 訪問(wèn)本類構(gòu)造方法
- super(…) - 訪問(wèn)父類構(gòu)造方法
2.3、繼承中構(gòu)造方法訪問(wèn)的特點(diǎn)
注意:子類中所有的構(gòu)造方法默認(rèn)都會(huì)訪問(wèn)父類中無(wú)參的構(gòu)造方法。
子類會(huì)繼承父類中的數(shù)據(jù),可能還會(huì)使用父類的數(shù)據(jù)。所以,子類初始化之前,一定要先完成父類數(shù)據(jù)的初始化。
//父類,Animal類
class Animal {
//構(gòu)造函數(shù)
public Animal() {
System.out.println("Animal類的無(wú)參數(shù)構(gòu)造函數(shù)執(zhí)行");
}
}
//子類,Cat類
class Cat extends Animal{
//構(gòu)造函數(shù)
public Cat() {
// super(); // 注意子類構(gòu)造方法中默認(rèn)會(huì)調(diào)用基類的無(wú)參構(gòu)造方法:super(),
// 用戶沒(méi)有寫(xiě)時(shí),編譯器會(huì)自動(dòng)添加,而且super()必須是子類構(gòu)造方法中第一條語(yǔ)句,
// 并且只能出現(xiàn)一次
System.out.println("Cat類的無(wú)參數(shù)構(gòu)造函數(shù)執(zhí)行");
}
}
//執(zhí)行代碼
public static void main(String[] args) {
Cat cat = new Cat();
}
//輸出結(jié)果
Animal類的無(wú)參數(shù)構(gòu)造函數(shù)執(zhí)行
Cat類的無(wú)參數(shù)構(gòu)造函數(shù)執(zhí)行
在子類構(gòu)造方法中,并沒(méi)有寫(xiě)任何關(guān)于基類構(gòu)造的代碼,但是在構(gòu)造子類對(duì)象時(shí),先執(zhí)行基類的構(gòu)造方法,然后執(zhí)行子類的構(gòu)造方法,因?yàn)椋?*子類對(duì)象中成員是有兩部分組成的,基類繼承下來(lái)的以及子類新增加的部分 。父子父子肯定是先有父再有子,所以在構(gòu)造子類對(duì)象時(shí)候 ,先要調(diào)用基類的構(gòu)造方法,將從基類繼承下來(lái)的成員構(gòu)造完整,然后再調(diào)用子類自己的構(gòu)造方法,將子類自己新增加的成員初始化完整 **
問(wèn)題:如果父類中沒(méi)有無(wú)參構(gòu)造方法,只有帶參構(gòu)造方法,該怎么辦呢?
- 通過(guò)使用
super
關(guān)鍵字去顯示的調(diào)用父類的帶參構(gòu)造方法 - 子類通過(guò)
this
去調(diào)用本類的其他構(gòu)造方法,本類其他構(gòu)造方法再通過(guò)super
去手動(dòng)調(diào)用父類的帶參的構(gòu)造方法
我們看下面這個(gè)例子:
public class MyTest {
public static void main(String[] args) {
Cat c1 = new Cat(3);
System.out.println("名字:" + c1.getName());
System.out.println("年齡:" + c1.getAge());
}
}
//父類,Animal類
class Animal {
//私有屬性:名字
private String name;
//setter and getter
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
//構(gòu)造函數(shù)
public Animal() {
}
public Animal(String name) {
this.name = name;
}
}
//子類,Cat類
class Cat extends Animal{
//私有字段:年齡
private int age;
//setter and getter
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
//構(gòu)造函數(shù)
public Cat() {
}
public Cat(int age) {
this.age = age;
}
}
輸出結(jié)果
名字:null
年齡:3
因?yàn)?code>c1對(duì)象沒(méi)有給name
賦值,所以是null
了
那么我們給Cat
加一個(gè)構(gòu)造方法,給name
和age
都賦值。如下:
public Cat(String name, int age) {
this.name = name; //報(bào)錯(cuò)
this.age = age
}
顯然這樣做是會(huì)報(bào)錯(cuò)的,因?yàn)?code>name已經(jīng)被父類封裝成private
的了,不能直接訪問(wèn),可能有的人會(huì)這樣做:
public Cat(String name, int age) {
setName(name); // 因?yàn)楦割惖膕etName()方法是public的
this.age = age;
}
顯然這樣做的確可以做到給父類的name
賦值,但這樣做是不建議的,我們?cè)跇?gòu)造方法中通常只調(diào)用構(gòu)造方法,不會(huì)去調(diào)用實(shí)例方法,況且當(dāng)不止一個(gè)變量時(shí),用set
方法時(shí),我們就要調(diào)用好多個(gè)實(shí)例方法去完成多個(gè)變量的賦值。這時(shí)候?yàn)槭裁床豢紤]使用super()
方法呢?如下:
public Cat(String name, int age) {
super(name);
this.age = age;
}
注意: this(…)super(…) 必須放在構(gòu)造方法的第一行有效語(yǔ)句,并且二者不能共存
2.4、繼承中成員方法的特點(diǎn)
成員方法名字不同
public class Base {
public void methodA(){
System.out.println("Base中的methodA()");
}
}
public class Derived extends Base{
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
methodB(); // 訪問(wèn)子類自己的methodB()
methodA(); // 訪問(wèn)父類繼承的methodA()
// methodD(); // 編譯失敗,在整個(gè)繼承體系中沒(méi)有發(fā)現(xiàn)方法methodD()
}
}
所以說(shuō),成員方法沒(méi)有同名時(shí),在子類方法中或者通過(guò)子類對(duì)象訪問(wèn)方法時(shí),則優(yōu)先訪問(wèn)自己的,自己沒(méi)有時(shí)再到父類中找,如果父類中也沒(méi)有則報(bào)錯(cuò)。
成員方法名字相同
public class Base {
public void methodA(){
System.out.println("Base中的methodA()");
}
public void methodB(){
System.out.println("Base中的methodB()");
}
}
public class Derived extends Base{
public void methodA(int a) {
System.out.println("Derived中的method(int)方法");
}
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
methodA(); // 沒(méi)有傳參,訪問(wèn)父類中的methodA()
methodA(20); // 傳遞int參數(shù),訪問(wèn)子類中的methodA(int)
methodB(); // 直接訪問(wèn),則永遠(yuǎn)訪問(wèn)到的都是子類中的methodB(),基類的無(wú)法訪問(wèn)到
}
}
@Test
public void test() {
Derived d = new Derived();
d.methodC();
}
輸出結(jié)果:
Base中的methodA()
Derived中的method(int)方法
Derived中的methodB()方法
說(shuō)明:
- 通過(guò)子類對(duì)象訪問(wèn)父類與子類中不同名方法時(shí),優(yōu)先在子類中找,找到則訪問(wèn),否則在父類中找,找到則訪問(wèn),否則編譯報(bào)錯(cuò)。
- 通過(guò)派生類對(duì)象訪問(wèn)父類與子類同名方法時(shí),如果父類和子類同名方法的參數(shù)列表不同(重載),根據(jù)調(diào)用方法適傳遞的參數(shù)選擇合適的方法訪問(wèn),如果沒(méi)有則報(bào)錯(cuò);
那么問(wèn)題來(lái)了,如果子類中存在與父類中相同的成員時(shí),那如何在子類中訪問(wèn)父類相同名稱的成員呢?
使用 super 關(guān)鍵字
由于設(shè)計(jì)不好,或者因場(chǎng)景需要,子類和父類中可能會(huì)存在相同名稱的成員,如果要在子類方法中訪問(wèn)父類同名成員時(shí),該如何操作?直接訪問(wèn)是無(wú)法做到的,Java 提供了 super 關(guān)鍵字,該關(guān)鍵字主要作用:在子類方法中訪問(wèn)父類的成員。
public class Base {
int a;
int b;
public void methodA(){
System.out.println("Base中的methodA()");
}
public void methodB(){
System.out.println("Base中的methodB()");
}
}
public class Derived extends Base{
int a; // 與父類中成員變量同名且類型相同
char b; // 與父類中成員變量同名但類型不同
// 與父類中methodA()構(gòu)成重載
public void methodA(int a) {
System.out.println("Derived中的method()方法");
}
// 與基類中methodB()構(gòu)成重寫(xiě)(即原型一致,重寫(xiě)后序詳細(xì)介紹)
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
// 對(duì)于同名的成員變量,直接訪問(wèn)時(shí),訪問(wèn)的都是子類的
a = 100; // 等價(jià)于: this.a = 100;
b = 101; // 等價(jià)于: this.b = 101;
// 注意:this是當(dāng)前對(duì)象的引用
// 訪問(wèn)父類的成員變量時(shí),需要借助super關(guān)鍵字
// super是獲取到子類對(duì)象中從基類繼承下來(lái)的部分
super.a = 200;
super.b = 201;
// 父類和子類中構(gòu)成重載的方法,直接可以通過(guò)參數(shù)列表區(qū)分清訪問(wèn)父類還是子類方法
methodA(); // 沒(méi)有傳參,訪問(wèn)父類中的methodA()
methodA(20); // 傳遞int參數(shù),訪問(wèn)子類中的methodA(int)
// 如果在子類中要訪問(wèn)重寫(xiě)的基類方法,則需要借助super關(guān)鍵字
methodB(); // 直接訪問(wèn),則永遠(yuǎn)訪問(wèn)到的都是子類中的methodA(),基類的無(wú)法訪問(wèn)到
super.methodB(); // 訪問(wèn)基類的methodB()
}
}
2.5、super和this
super 和this 都可以在成員方法中用來(lái)訪問(wèn):成員變量和調(diào)用其他的成員函數(shù),都可以作為構(gòu)造方法的第一條語(yǔ)句,那他們之間有什么區(qū)別呢?
相同點(diǎn)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-859730.html
- 都是 Java 中的關(guān)鍵字
- 只能在類的非靜態(tài)方法中使用,用來(lái)訪問(wèn)非靜態(tài)成員方法和字段
- 在構(gòu)造方法中調(diào)用時(shí),必須是構(gòu)造方法中的第一條語(yǔ)句,并且不能同時(shí)存在
不同點(diǎn)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-859730.html
- this是當(dāng)前對(duì)象的引用,當(dāng)前對(duì)象即調(diào)用實(shí)例方法的對(duì)象,super 相當(dāng)于是子類對(duì)象中從父類繼承下來(lái)部分成員的引用
- 在非靜態(tài)成員方法中,this 用來(lái)訪問(wèn)本類的方法和屬性,super 用來(lái)訪問(wèn)父類繼承下來(lái)的方法和屬性
- 在構(gòu)造方法中:this(…)用于調(diào)用本類構(gòu)造方法,super(…)用于調(diào)用父類構(gòu)造方法,兩種調(diào)用不能同時(shí)在構(gòu)造方法中出現(xiàn)
- 構(gòu)造方法中一定會(huì)存在super(…)的調(diào)用,用戶沒(méi)有寫(xiě)編譯器也會(huì)增加,但是this(…)用戶不寫(xiě)則沒(méi)有
到了這里,關(guān)于Java面向?qū)ο?3——三大特性之繼承的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!