一、多態函數
(1)多態概述定義及使用格式:學習
多態是繼封裝、繼承以後,面向對象的特性。測試
父類引用變量能夠指向子類對象。this
注意:spa
多態的前提是必須有子父類關係或者類實現接口關係,不然沒法完成多態。code
在使用多態後的父類引用變量調用方法時,會調用子類重寫後的方法。對象
多態的定義格式:就是父類的引用變量指向子類對象blog
使用格式:繼承
父類類型 變量名 = new 子類類型();接口
變量名.方法名();
普通類多態定義的格式
父類 變量名 = new 子類();
如: class Fu {}
class Zi extends Fu {}
類的多態使用
Fu f = new Zi();
l 抽象類多態定義的格式:
抽象類 變量名 = new 抽象類子類(); 如: public abstract class Fu {----------------定義一個抽象父類 public abstract void method();----------抽象方法method } public class Zi extends Fu { public void method(){----------------重寫方法 System.out.println(「重寫父類抽象方法」); } } //類的多態使用 Fu fu= new Zi();--------------類的多態使用
l 接口多態定義的格式
接口 變量名 = new 接口實現類(); 如:public interface Fu { public abstract void method(); } public class Zi implements Fu { public void method(){ System.out.println(「重寫接口抽象方法」); } } //接口的多態使用 Fu fu = new Zi();
l 注意事項
同一個父類的方法會被不一樣的子類重寫。在調用方法時,調用的爲各個子類重寫後的方法。
如 Person p1 = new Student();
Person p2 = new Teacher();
p1.work(); //p1會調用Student類中重寫的work方法
p2.work(); //p2會調用Teacher類中重寫的work方法
當變量名指向不一樣的子類對象時,因爲每一個子類重寫父類方法的內容不一樣,因此會調用不一樣的方法。
(2)多態成員的方法
l 多態成員變量
當子父類中出現同名的成員變量時,多態調用該變量時:
編譯時期:參考的是引用型變量所屬的類中是否有被調用的成員變量。沒有,編譯失敗。
運行時期:也是調用引用型變量所屬的類中的成員變量。
簡單記:編譯和運行都參考等號的左邊。編譯運行看左邊。
Public class Fu {-----------------------父類 int num = 4;------------------------定義常量 }
Public class Zi extends Fu {---------------繼承 int num = 5;------------------定義常量,長量名與父類相同 }
Public class Demo { public static void main(String[] args) { Fu f = new Zi(); System.out.println(f.num); Zi z = new Zi(); System.out.println(z.num); } }
l 多態成員方法
編譯時期:參考引用變量所屬的類,若是類中沒有調用的方法,編譯失敗。
運行時期:參考引用變量所指的對象所屬的類,並運行對象所屬類中的成員方法。
簡而言之:編譯看左邊,運行看右邊。
Public class Fu { int num = 4; void show() { System.out.println("Fu show num"); } }
Public class Zi extends Fu { int num = 5; public void show() { System.out.println("Zi show num"); } }
Public class Demo { public static void main(String[] args) { Fu f = new Zi(); f.show(); } }
(3)instanceof關鍵字
經過instanceof關鍵字來判斷某個對象是否屬於某種數據類型。如學生的對象屬於學生類,學生的對象也屬於人類。
使用格式:
boolean b = 對象 instanceof 數據類型;
如
Person p1 = new Student(); // 前提條件,學生類已經繼承了人類
boolean flag = p1 instanceof Student; //flag結果爲true
boolean flag2 = p1 instanceof Teacher; //flag結果爲false
(4)多態轉型:分爲向上轉型與向下轉型兩種
向上轉型:當有子類對象賦值給一個父類引用時,即是向上轉型,多態自己就是向上轉型的過程。
使用格式:
父類類型 變量名 = new 子類類型();
如:Person p = new Student();
l 向下轉型:一個已經向上轉型的子類對象可使用強制類型轉換的格式,將父類引用轉爲子類引用,這個過程是向下轉型。若是是直接建立父類對象,是沒法向下轉型的!
使用格式:
子類類型 變量名 = (子類類型) 父類類型的變量;
如:Student stu = (Student) p; //變量p 實際上指向Student對象
(5)多態的好處與弊端
當父類的引用指向子類對象時,就發生了向上轉型,即把子類類型對象轉成了父類類型。向上轉型的好處是隱藏了子類類型,提升了代碼的擴展性。
但向上轉型也有弊端,只能使用父類共性的內容,而沒法使用子類特有功能,功能有限制。看以下代碼
舉例說明:
//描述動物類,並抽取共性eat方法 public abstract class Animal { abstract void eat(); }
// 描述狗類,繼承動物類,重寫eat方法,增長lookHome方法 public class Dog extends Animal { public void eat() { System.out.println("啃骨頭"); } public void lookHome() { System.out.println("看家"); } }
// 描述貓類,繼承動物類,重寫eat方法,增長catchMouse方法 public class Cat extends Animal { public void eat() { System.out.println("吃魚"); } public void catchMouse() { System.out.println("抓老鼠"); } }
測試:
public class Test { public static void main(String[] args) { Animal a = new Dog(); //多態形式,建立一個狗對象 a.eat(); // 調用對象中的方法,會執行狗類中的eat方法 // a.lookHome();//使用Dog類特有的方法,須要向下轉型,不能直接使用 // 爲了使用狗類的lookHome方法,須要向下轉型 // 向下轉型過程當中,可能會發生類型轉換的錯誤,即ClassCastException異常 // 那麼,在轉以前須要作健壯性判斷 if( !a instanceof Dog){ // 判斷當前對象是不是Dog類型 System.out.println("類型不匹配,不能轉換"); return; } Dog d = (Dog) a; //向下轉型 d.lookHome();//調用狗類的lookHome方法 } }
l何時使用向上轉型:
當不須要面對子類類型時,經過提升擴展性,或者使用父類的功能就能完成相應的操做,這時就可使用向上轉型。
如:Animal a = new Dog();
a.eat();
何時使用向下轉型
當要使用子類特有功能時,就須要使用向下轉型。
如:Dog d = (Dog) a; //向下轉型
d.lookHome();//調用狗類的lookHome方法
向下轉型的好處:可使用子類特有功能。
弊端是:須要面對具體的子類對象;在向下轉型時容易發生ClassCastException類型轉換異常。在轉換以前必須作類型判斷。
如:if( !a instanceof Dog){…}
例如:
二、構造方法(構造函數、構造器)
(1)構造方法介紹
從字面上理解即爲構建創造時用的方法,即就是對象建立時要執行的方法。既然是對象建立時要執行的方法,那麼只要在new對象時,知道其執行的構造方法是什麼,
就能夠在執行這個方法的時候給對象進行屬性賦值。
格式:
修飾符 構造方法名(參數列表)
{
}
構造方法的體現:
構造方法沒有返回值類型。也不須要寫返回值。由於它是爲構建對象的,對象建立完,方法就執行結束。
構造方法名稱必須和類名保持一致。
構造方法沒有具體的返回值。
public class Person {-------------------定義person類 // Person的成員屬性age和name private int age; private String name; } // Person的構造方法,擁有參數列表
public Person(int a, String nm) {------------------構造方法,傳參 // 接受到建立對象時傳遞進來的值,將值賦給成員屬性 age = a; name = nm; } }
構造方法是專門用來建立對象的,也就是在new對象時要調用構造方法。
構造方法舉例:
public class Person { // Person的成員屬性age和name private int age; private String name; // Person的構造方法,擁有參數列表 public Person(int a, String nm) { // 接受到建立對象時傳遞進來的值,將值賦給成員屬性 age = a; name = nm; } public void speak() {//---------------------定義方法 System.out.println("name=" + name + ",age=" + age); } }
public class PersonDemo { public static void main(String[] args) { // 建立Person對象,並明確對象的年齡和姓名 Person p2 = new Person(23, "張三");//---------------new對象時直接賦值 p2.speak(); } }
構造方法的注意事項:
---------------描述事物時,並無顯示指定構造方法,當在編譯Java文件時,編譯器會自動給class文件中添加默認
的構造方法。若是在描述類時,咱們顯示指定了構造方法,那麼,當在編譯Java源文件時,編譯器就不會再給class文件
中添加默認構造方法。
-----------------------一個類中能夠有多個構造方法,多個構造方法是以重載的形式存在的
-----------------------構造方法是能夠被private修飾的,做用:其餘程序沒法建立該類的對象。
(2)構造方法和通常方法的區別
目前學習了兩種方法:通常方法與構造方法
區別:
-------------------構造方法在對象建立時就執行了,並且只執行一次。
-------------------通常方法是在對象建立後,須要使用時才被對象調用,並能夠被屢次調用
構造方法舉例:
//構造方法 //權限、類名(參數列表) public class Person { private String name; private int age; public Person(String name,int age){//有參構造方法 this.name=name; this.age=age; } public Person(){ System.out.println("這是空參的構造方法"); } 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; } }
package demo04; public class Test { //構造方法在建立對象時被調用,而且一個對象只能調用一次構造方法 //構造方法只能對屬性賦值一次 //二、構造方法,若是該類沒有構造方法,默認有一個空參構造方法 //若是這個類有構造方法,就不會默認添加一個空參構造 public static void main(String[] args) { Person p = new Person(); Person b= new Person("lisi",19); System.out.println(p.getName()+".."+p.getAge()); System.out.println(b.getName()+".."+b.getAge()); } }