Java第七課. 物件導向特徵2

裝14發表於2020-12-07

Java第七課. 物件導向特徵2

回顧:

1.封裝:把細節隱藏,提高安全性
    步驟 1:把屬性私有化;  2:提供2個公共的方法設定/獲取
        
2.過載:[同一個類中,方法名相同,引數項不同(個數,資料型別,順序),與返回值無關];

3.構造方法:方法名與類名相同,無返回值型別;(構造方法一定是過載,反之不成立)
	作用: 1. 例項化物件(預設呼叫無參構造);
	     2. 建立物件的同時給屬性直接賦值(呼叫有參構造)
            
4.this 關鍵字: 1.構造方法間的相互呼叫(這種情況下要放第一行);
			  2.指代當前物件;

1. 繼承

1.1 繼承的意義

也是物件導向特徵之一
引入例子:定義學生類  幼兒園,小學生,初中生,大學生會有公共的東西,也有不同的東西

[問題]:太多相同程式碼
[解決問題]:使用繼承.為什麼引入繼承?剛才的案例分析?定義的幼兒園,小學生,大學生都是學生,他們有共同的屬性和方法,如果按照我們剛剛的編碼,程式碼有很多冗餘(相同的程式碼)

可以這麼去處理:定義一個學生類Student,如果一個類(BigStudent)是另外一個類(Student),?可以用BigStudent extends Student,就是大學生是學生,所以大學生繼承學生類,我們稱BigStudent叫做子類(派生類) ,Student是父類(基類)

1.2 extends關鍵字

基本語法:
    [訪問許可權修飾符] [修飾符] 子類名 extends 父類名{
        子類體
    }

由於Java是單親繼承體系,因此在描述類與類的繼承關係時, extends 關
鍵字後面只能是一個名字,而不能是一個列表(後續介面繼承的情況,
 extends 後面可以是一個列表)
    
• Java中的繼承樹根節點為 Object;
• 所有Java中的類都直接或間接繼承自 Object ;
/**
 * 小學生繼承學生類
 * @author Administrator
 * extends:繼承
 */
public class SmallStudent extends Student{

}
學生類(父類):
public class Student extends Object{
	private String stuNo;
	private String stuName;
    
	public String getStuNo() {
		return stuNo;
	}
	public void setStuNo(String stuNo) {
		this.stuNo = stuNo;
	}
	public String getStuName() {
		return stuName;
	}
	public void setStuName(String stuName) {
		this.stuName = stuName;
	}
	
	/**
	 * 學習的方法
	 */
	public void study() {
		System.out.println(stuName+"在學習中~");
	}
	public Student() {
		// TODO Auto-generated constructor stub
	}
}
大學生類(子類):
public class BigStudent extends Student{
    private  String sex;
	@Override  
	public void study() {
		// 呼叫父類的study() 
		super.study();
		System.out.println("邊泡妞邊學習");
	}
	
	public void play() {
		System.out.println("遊戲");
	}
}

小學生類(子類):
public class MinniStudent extends Student{
	
}
測試類:
public class TestMiniStudent {
	public static void main(String[] args) 
        
		MinniStudent student=new MinniStudent();
		student.setStuNo("202001");
		student.setStuName("張三");
		BigStudent bigStudent=new BigStudent();
		bigStudent.setStuNo("202001");
		bigStudent.setStuName("李四");
		bigStudent.study();
	}
}

張三在學習中~
李四在學習中~
邊泡妞邊學習

1.3 繼承的特點

[子類能夠繼承父類的所有的公共的部分(公共的屬性和方法),但是構造方法除外];

miniStudent.setStuNo("202001");
miniStudent.setStuName("張三");2個公開的方法其實是從Student類繼承而來的;

繼承的優點: 減少程式碼的冗餘,方便程式碼的複用(父類定義後,子類繼承父類就可以使用公共部分)
[Java中的類之間只能支援單繼承]:BigStudent繼承了Student,而Student預設繼承了obdanject,這種關係叫做[多層繼承];(A繼承B,B繼承了C,A可能也從C這邊繼承了一些公共的屬性和方法)

在這裡插入圖片描述

extends 除了繼承的含義,還有一個含義: 擴充套件
子類可以擴充套件父類,子類也可以包含自己的特有部分;

1.4 方法的重寫(覆寫)@Override

概念:
發生在繼承關係的子類中,在子類中的某一個方法,方法的修飾符,返回值型別,方法名,引數列表和父類的某一個方法完全一樣,稱為方法的重寫;(構造方法不能被重寫)

jdk1.5新特性:@Override,會幫我們檢查下面的方法是否是重寫,如果不是重寫,那麼就會報錯;
定義一個動物類,動物都會吃,狗類(Dog),繼承動物類,定義一個羊類,繼承動物類,分別重寫dog類和sheep類的吃的方法.定義測試類 ,分別測試dog物件和sheep物件,測試其吃的過程;
/**
 * 自定義動物類
 * @author Administrator
 *
 */
public class Animal {
	//定義私密屬性
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void eat() {
		System.out.println(name+"在吃");
	}
}
public class Dog extends Animal{

	/**
	 * 重寫父類的吃的方法
	 */
	@Override
	public void eat() {
		System.out.println(getName()+"在吃骨頭~");
	}
public class Sheep extends Animal{

	/**
	 * 重寫父類的吃的方法
	 */
	@Override
	public void eat() {
		System.out.println(getName()+"在拱小白菜~");
	}
}

測試類:

public class TestAnimal {

	public static void main(String[] args) {
	//	Animal animal=new Animal("動物");
		
		Dog dog=new Dog();
		dog.setName("旺財");
		dog.eat();
		
		Sheep sheep=new Sheep();
		sheep.setName("喜羊羊");
		sheep.eat();

	}

}

旺財在吃骨頭~
喜洋洋在拱小白菜~

1.5 構造方法與繼承

public class Animal {
	//定義私密屬性
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Animal(String name) {
		//super();//呼叫父類的無參構造
		this.name = name;
		System.out.println("我是父類的帶參構造");
	}
	public Animal() {
		System.out.println("我是父類的無參構造");
	}
	//eat方法
	public void eat() {
		System.out.println(name+"在吃");
	}
}
public class Dog extends Animal{
	/**
	 * 重寫父類的吃的方法
	 */
	@Override
	public void eat() {
		System.out.println(getName()+"在吃骨頭~");
		super.eat();//super.方法名() 呼叫父類的普通方法,普通方法中,這個super.方法名() 放在哪個位置都可以
	}
	
	public Dog() {
		//第一行程式碼
		//super();//呼叫父類的無參構造 這行程式碼寫或者不寫,都會呼叫父類的無參構造
		super("旺財");//顯式呼叫父類中的帶引數構造
		System.out.println("我是子類Dog的無參構造");
	}
}
public class Sheep extends Animal{
	/**
	 * 重寫父類的吃的方法
	 */
	@Override
	public void eat() {
		System.out.println(getName()+"在拱小白菜~");
	}
	public Sheep() {
		super("喜羊羊");
		System.out.println("我是子類sheep的無參構造");

	}
}
public class TestAnimal {

	public static void main(String[] args) {
	//Animal animal=new Animal("動物");
		
		Dog dog=new Dog();//預設呼叫子類的無參構造
		dog.setName("旺財");
		dog.eat();
		
		Sheep sheep=new Sheep();
		sheep.setName("喜洋洋");
		sheep.eat();

	}
}

我是父類的帶參構造
我是子類Dog的無參構造
旺財在吃骨頭~
旺財在吃
我是父類的帶參構造
我是子類sheep的無參構造
喜羊羊在拱小白菜~
[重點]:
當建立一個子類物件的時候,預設會呼叫子類的無引數構造,但是因為存在繼承關係,所以例項化子類的物件時,父類的無參構造先執行(那是因為子類的構造方法,包括有參和無參構造裡面會有預設的super()存在呼叫父類的無參構造),然後再執行子類的構造方法;

解決帶引數報錯:2種方法
1.	子類預設呼叫父類的無參,那就新增個無參;
2.	在子類中指定呼叫父類的某個構造方法,就要用到super;

1.4 super關鍵字

[可以使用super關鍵字來呼叫父類的構造方法以及普通方法];
[呼叫父類構造方法的時候,必須把super放在構造方法中的第一行];

在這裡插入圖片描述

但是父類的無參構造和有參構造不能同時呼叫,每個類有且僅有一個建構函式會被例項化;
呼叫普通方法:

在這裡插入圖片描述

1.41關於super 與 this 能不能同時使用的問題
答案是不能,因為 superthis 在子類呼叫構造方法時都必須要放在第一行;我們先來看為什麼這種情況下 thissuper 要放在第一行;

[super]:
因為繼承的原因,在子類進行初始化的時候,必須要先初始化父類,這就需要呼叫父類的構造方法,super就起到了呼叫父類的構造方法的作用,也就是初始化父類的作用;因為在java中不允許呼叫未初始化的成員;

再說為什麼要放在第一行,因為編譯器會檢測建構函式第一行有沒有呼叫父類建構函式(包括有參和無參),如果沒有會預設新增 super(),有則不會;如果再第二行呼叫 super,會對父類進行兩次初始化,會造成資源的浪費;而且每個類有且僅有一個建構函式會被例項化;

[this]:
this 的作用就是呼叫本類的其它建構函式,上面說過每個建構函式會有預設的 super(),或者自定義了帶參的 super,這樣就已經初始化父類了,所以寫了 this 就不能寫 super,上面也說了不能出現兩個 super;至於要放第一行的原因和 super 差不多;

2. 總結

• 類的繼承由關鍵字 extends 確定,Java語言為單親繼承,及一個子類只能有一個父類,而一個父類可以有多個子類;
• 子類可以重寫父類中某一個方法,稱為方法覆蓋,也稱方法重寫,是繼承中非常重要的知識點。如果子類需要修改從父類繼承到的方法的方法體,就可以使用方法覆蓋;
• 當構建子類物件時會優先隱式自動呼叫父類的無參構造方法,而且這個構建呼叫過程是從父類“向外”遞迴擴散的,也就是從父類開始向子類一級一級地完成構建,即如果C繼承自B,而B繼承自A,那麼構建C的物件時,會先呼叫A的構造方法,然後呼叫B的構造方法,最後呼叫C的構造方法,以此類推;
• 如果沒有無參的父類構造方法,子類必須要使用 super 顯示的呼叫父類的構造方法,而且必須是在子類構造器中做的第一件事;this 引用物件自身、呼叫自己的構造方法,而 super 呼叫父類定義的成員變數、方法或構造方法, super 不能當作引用傳遞給其他的呼叫者而 this 可以;

相關文章