多態、構造方法(構造函數、構造器)


1、多態

(1)多態概述定義及使用格式:

多態是繼封裝、繼承之后,面向對象的特性。

父類引用變量可以指向子類對象。

注意:

多態的前提是必須有子父類關系或者類實現接口關系,否則無法完成多態。

在使用多態后的父類引用變量調用方法時,會調用子類重寫后的方法。

多態的定義格式:就是父類的引用變量指向子類對象

使用格式:

父類類型  變量名 = 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){…}

例如:

 2、構造方法(構造函數、構造器)

(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 {
//構造方法在創建對象時被調用,並且一個對象只能調用一次構造方法
    //構造方法只能對屬性賦值一次
    //2、構造方法,如果該類沒有構造方法,默認有一個空參構造方法
    //如果這個類有構造方法,就不會默認添加一個空參構造
    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());
    }

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM