1. 程式人生 > >JavaSE之面向物件程式設計—類與物件(下)—— 6

JavaSE之面向物件程式設計—類與物件(下)—— 6

                                                                                        6——多型


面向物件程式設計一共由三大特性,分別是:繼承、封裝、多型,前兩種特性我們已經學習並且總結過了,多於多型我們今天來看看它是怎麼讓我們的面向物件程式設計變得多姿多彩的。
一、多型的實現
首先我們來看一下多型是通過什麼來實現的:
1、方法的多型性
(1)方法過載:在同一個類中,方法名字相同,引數個數不同、引數型別不同、引數順序不同就叫做方法過載;方法過載將同一個引數名可以同時實現不同引數型別、引數個數的功能。比如我們在main方法中使用的System.out.println();這個方法在源程式中是將所有的引數型別、引數個數都考慮進去了的,這樣我們在使用的時候不管輸入什麼才可以正確的輸出結果。
(2)方法重寫:子類通過繼承將父類的所有結構都繼承過來了,但是對於父類的一些方法有些不滿意,所以對它進行了改進 ,對於方法名字相同、引數個數相同、引數型別相同但是方法實現的功能不同就叫做方法覆寫;方法覆寫同樣也實現了多型。
2.物件的多型:物件的多型性前提是有方法覆寫,分為兩種
(1)物件向上轉型:父類 父類物件=new 子類;
情況一:通過向上轉型以後這個方法子類是經過子類覆寫的,這個時候是可以呼叫成功的。

//(1)向上轉型
class Person{
	private String name;
	public void print(){
		System.out.println("這是父類的方法");
	}
}
class Student extends Person{
    public void print(){
		System.out.print("這是子類經過覆寫以後的方法");
	}
}
public class Fuxie{
	public static void main(String[] args){
	Person per=new Student();//向上轉型
	per.print();//觀察向上轉型以後父類呼叫的方法到底是經過覆寫以後的方法還是原來的方法

	}
}

在這裡插入圖片描述

情況二 :父類的物件呼叫的方法是沒有經過子類覆寫的,這個時候呼叫會出現錯誤,具體錯誤下面程式碼的執行結果可見
//(1)向上轉型
class Person{
	private String name;
	public void print(){
		System.out.println("這是父類的方法");
	}
	public void Print2(){
		System.out.println("這是被父類的第二個方法,子類不對它進行覆寫");
	}
}
class Student extends Person{
    public void print(){
		System.out.print("這是子類經過覆寫以後的方法");
	}
}
public class Fuxie{
	public static void main(String[] args){
	Person per=new Student();//向上轉型
	per.print();//觀察向上轉型以後父類呼叫的方法到底是經過覆寫以後的方法還是原來的方法
//在這個程式裡面,型別是Person類的,但是它對應開闢的空間是Student的,所以最後在父類物件呼叫方法的時候,呼叫的是被覆寫過以後的方法
	//對一個子類沒有覆寫的方法用父類的物件呼叫,看它是否會有結果輸出。
	per.print2();
	}
}

在這裡插入圖片描述
總結:對於物件的向上轉型,我們的java是支援的,兩種型別是相容的,編譯、執行均可以通過,但是前提是轉型後這個物件呼叫的方法是被覆寫過的,否則還是會出錯。
(2)物件向下轉型:子類 子類物件=new 父類;
通過下面的程式碼我們來看向下轉型我們需要注意什麼,它的一些知識:

//(2)向下轉型
class Person{
	public void print(){
		System.out.println("這是父類的方法");
	}
	public void print2(){
		System.out.println("這是父類的第二個方法");
	}
}
class Student extends Person{
	public void print(){
		System.out.println("這是子類覆寫以後的方法");
	}
}
public class Fuxie{
	public static void main(String[] args){
	Student stu=new Person();//向下轉型:將小型別轉化為大型別
	stu.print();
	}
}

在這裡插入圖片描述
通過上面的栗子我們可以看出向下轉型會報錯:型別不相容,因為子類相當於是小型別,父類相當於是大型別,大型別轉小型別是不可以的,所以會提示型別不相容。下面我們來看一下強轉可以不。
(3)強轉

//(3)強轉
class Person{
	public void print(){
		System.out.println("這是父類的方法");
	}
	public void print2(){
		System.out.println("這是父類的第二個方法");
	}
}
class Student extends Person{
	public void print(){
		System.out.println("這是子類覆寫以後的方法");
	}
}
public class Fuxie{
	public static void main(String[] args){
	Student stu=(Student)new Person();//向下轉型:將小型別轉化為大型別——》強轉
	stu.print();
	}
}

在這裡插入圖片描述
通過上面的栗子我們可以看出來經過強轉了以後我們的編譯是可以通過的,我們的邏輯是沒有問題的,但是執行的時候仍然會出錯,是因為要向下轉型必須先經過向上轉型以後才是可行的。
(4)看起來像是對的,其實是錯的

class Person{
	public void print(){
		System.out.println("這是父類的方法");
	}
	public void print2(){
		System.out.println("這是父類的第二個方法");
	}
}
class Student extends Person{
	public void print(){
		System.out.println("這是子類覆寫以後的方法");
	}
}
public class Fuxie{
	public static void main(String[] args){
	person per = new Student();//向上轉型
    Student stu=per;
	}
}

在這裡插入圖片描述
上面的程式看起來像是自己建立自己的程式,但其實剛開始是經過了一次向上轉型,轉型完以後,我們的程式還沒有執行,那麼這是執行下面的 Student stu=per;這條語句的時候,per的型別還不是Student這個型別,還是原來修飾它的那個型別Person,所以下面的這個執行會出錯。型別不相容。
對於上面的情況我們也可以舉一個基本資料型別的栗子來看看:

//舉一個基本資料型別看看
public class Fuxie{
	public static void main(String[] args){
		//第一種方法:將一個整數直接賦給byte變數
		byte b=20;
		System.out.println(b);
		//第二種方法:將一個整數先賦給int型變數,再利用這個變數給byte型變數賦值
		int a=10;
		byte b=a;
		System.out.println(a);
	}
}

在這裡插入圖片描述
對於我們的基本資料型別也是一樣的,如果上面的程式碼中我們先將一個整數賦值給int變數,然後再通過這個整形變數給byte型變數賦值的時候編譯時會提示我們說型別不相容,其實這個和我們的物件向下轉型的強轉型別是一個道理,看起來我們是將一個整數付給了byte,但是由於編寫後還沒有分配空間,在編譯的時候只是按照前面提示的型別進行判斷,並不會分配空間(注意:只要程式還沒有執行就還沒有分配空間),所以在編譯的時候認為這個a就是int型的,所以我們的編譯都不可以通過;但是基本資料型別經過強轉以後是可以正常執行的,但是對於類是不行的。

//經過強轉
public class Fuxie{
	public static void main(String[] args){
		//第一種方法:將一個整數直接賦給byte變數
		byte b=20;
		System.out.println(b);
		//第二種方法:將一個整數先賦給int型變數,再利用這個變數給byte型變數賦值
		int a=10;
		byte c=(byte)a;
		System.out.println(c);
	}
}

在這裡插入圖片描述
二、解決向下轉型存在的安全隱患
我們在生活中做一個事情的時候會先判斷它的好壞,在向下轉型的時候我們先對它進行判斷,然後再進行轉型,這個實現的過程通過instanceof來實現,語法如下:
子類物件 instanceof 類,返回boolean型別
觀察instanceof操作:

class Person{
	public void print(){
		System.out.println("這是父類的方法");
	}
}
class Student extends Person{
	public void print(){
		System.out.println("這是子類經過覆寫以後的方法");
	}
}
public class Fuxie{
	public static void main(String[] args){
		Person per=new Student();//實現了向上轉型
		System.out.println(per instanceof Person);//判斷是真還是假
		System.out.println(per instanceof Student);
		if(per instanceof Student){//避免ClassCastException
			Student stu=(Student)per;//實現向下轉型,因為在向下轉型之前已經有了向上轉型,所以
			                   //經過了向上轉型,所以才可以成功。
		stu.print();//最後經過呼叫的方法是經過子類覆寫以後的方法
		}
	}
}

在這裡插入圖片描述
通過instanceof這個關鍵字可以讓我們在進行向下轉型的時候保證這個一定是經過了向上轉型的。這樣轉型才可以成功。
對於向上轉型、向下轉型有什麼意義:

//向上轉型的應用
class Person{
	public void print(){
		System.out.println("我是人類");
	}
}
class Student extends Person{
	public void print(){
		System.out.println("我是學生");
	}
}
class Worker extends Person{
	public void print(){
		System.out.println("我是工人");
	}
}
public class Fuxie{
	public static void main(String[] args){
		whoyu(new Student());
		whoyu(new Worker());
	}
	public static void whoyu(Person per){//傳參:Person per=new Student();實現向上轉型
		per.print();
	}
}

在這裡插入圖片描述
通過上面的例項,可以看到向上轉型可以實現物件的傳參,可以實現傳參後引數的統一。
三、多型的總結:
1.多型的核心是在於方法覆寫這一塊。
2.向上轉型可以實現傳參引數的統一化。
3.兩個沒有關係的類是不可能實現轉型的,會報錯:ClassCastException。