java基礎(12):構造方法、this、super

来源:https://www.cnblogs.com/liuhui0308/archive/2019/10/07/11632781.html
-Advertisement-
Play Games

1. 構造方法 我們對封裝已經有了基本的瞭解,接下來我們來看一個新的問題,依然以Person為例,由於Person中的屬性都被private了,外界無法直接訪問屬性,必須對外提供相應的set和get方法。當創建人對象的時候,人對象一創建就要明確其姓名和年齡,那該怎麼做呢? 1.1 構造方法介紹 在開 ...


1. 構造方法

我們對封裝已經有了基本的瞭解,接下來我們來看一個新的問題,依然以Person為例,由於Person中的屬性都被private了,外界無法直接訪問屬性,必須對外提供相應的set和get方法。當創建人對象的時候,人對象一創建就要明確其姓名和年齡,那該怎麼做呢?

1.1 構造方法介紹

在開發中經常需要在創建對象的同時明確對象的屬性值,比如員工入職公司就要明確他的姓名、年齡等屬性信息。

那麼,創建對象就要明確屬性值,那怎麼解決呢?也就是在創建對象的時候就要做的事情,當使用new關鍵字創建對象時,怎麼給對象的屬性初始化值呢?這就要學習Java另外一門小技術,構造方法。

那什麼是構造方法呢?從字面上理解即為構建創造時用的方法,即就是對象創建時要執行的方法。既然是對象創建時要執行的方法,那麼只要在new對象時,知道其執行的構造方法是什麼,就可以在執行這個方法的時候給對象進行屬性賦值。

構造方法的格式:

修飾符 構造方法名(參數列表)
{
}

構造方法的體現:

構造方法沒有返回值類型。也不需要寫返回值。因為它是為構建對象的,對象創建完,方法就執行結束。

構造方法名稱必須和類型保持一致。

構造方法沒有具體的返回值。

構造方法的代碼體現:

class Person {
    // Person的成員屬性age和name
    private int age;
    private String name;

    // Person的構造方法,擁有參數列表
    Person(int a, String nm) {
        // 接受到創建對象時傳遞進來的值,將值賦給成員屬性
        age = a;
        name = nm;
    }
}

1.2 構造方法調用和記憶體圖解

理解構造方法的格式和基本功能之後,現在就要研究構造方法是怎麼執行的呢?在創建對象的時候是如何初始化的呢?

構造方法是專門用來創建對象的,也就是在new對象時要調用構造方法。現在來看看如何調用構造方法。

class Person {
    // Person的成員屬性age和name
    private int age;
    private String name;

    // Person的構造方法,擁有參數列表
    Person(int a, String nm) {
        // 接受到創建對象時傳遞進來的值,將值賦給成員屬性
        age = a;
        name = nm;
    }

    public void speak() {
        System.out.println("name=" + name + ",age=" + age);
    }
}

class PersonDemo {
    public static void main(String[] args) {
        // 創建Person對象,並明確對象的年齡和姓名
        Person p2 = new Person(23, "張三");
        p2.speak();
    }
}

上述代碼演示了創建對象時構造方法的調用。即在創建對象時,會調用與參數列表對應的構造方法。

上述代碼的圖解:

 

 

 

圖解說明:

1、首先會將main方法壓入棧中,執行main方法中的 new Person(23,"張三");

2、在堆記憶體中分配一片區域,用來存放創建的Person對象,這片記憶體區域會有屬於自己的記憶體地址(0x88)。然後給成員變數進行預設初始化(name=null,age=0)。

3、執行構造方法中的代碼(age = a ; name = nm;),將變數a對應的23賦值給age,將變數nm對應的”張三賦值給name,這段代碼執行結束後,成員變數age和name的值已經改變。執行結束之後構造方法彈棧,Person對象創建完成。將Person對象的記憶體地址0x88賦值給p2。

1.3 預設構造方法和細節

在沒有學習構造方法之前,我們也可以通過new關鍵字創建對象,並調用相應的方法,同時在描述事物時也沒有寫構造方法。這是為什麼呢?

在之前學習的過程中,描述事物時,並沒有顯示指定構造方法,當在編譯Java文件時,編譯器會自動給class文件中添加預設的構造方法。如果在描述類時,我們顯示指定了構造方法,那麼,當在編譯Java源文件時,編譯器就不會再給class文件中添加預設構造方法。

class  Person {
    //如果沒有顯示指定構造方法,編譯會在編譯時自動添加預設的構造方法
    //Person(){}  //空參數的預設構造方法
}

當在描述事物時,要不要在類中寫構造方法呢?這時要根據描述事物的特點來確定,當描述的事物在創建其對象時就要明確屬性的值,這時就需要在定義類的時候書寫帶參數的構造方法。若創建對象時不需要明確具體的數據,這時可以不用書寫構造方法(不書寫也有預設的構造方法)。

構造方法的細節:

1、一個類中可以有多個構造方法,多個構造方法是以重載的形式存在的

2、構造方法是可以被private修飾的,作用:其他程式無法創建該類的對象。

class Person {
    private int age;
    private String name;

    // 私有無參數的構造方法,即外界不能通過new Person();語句創建本類對象
    private Person() {
    }

    // 多個構造方法是以重載的形式存在
    Person(int a) {
        age = a;
    }

    Person(String nm, int a) {
        name = nm;
        age = a;
    }
}

1.4 構造方法和一般方法區別

到目前為止,學習兩種方法,分別為構造方法和一般方法,那麼他們之間有什麼異同呢?

構造方法在對象創建時就執行了,而且只執行一次。

一般方法是在對象創建後,需要使用時才被對象調用,並可以被多次調用。

問題:

有了構造方法之後可以對對象的屬性進行初始化,那麼還需要對應的set和get方法嗎?

需要相應的set和get方法,因為對象在創建之後需要修改和訪問相應的屬性值時,在這時只能通過set或者get方法來操作。

思考,如下代碼有問題嗎?

class Person {
    void Person() {
    }
}

class PersonDemo {
    public static void main(String[] args) {
        Person p = new Person();
    }
}

2. this關鍵字

在之前學習方法時,我們知道方法之間是可以相互調用的,那麼構造方法之間能不能相互調用呢?若可以,怎麼調用呢?

2.1 this調用構造方法

在之前學習方法之間調用時,可以通過方法名進行調用。可是針對構造方法,無法通過構造方法名來相互調用。

構造方法之間的調用,可以通過this關鍵字來完成。

構造方法調用格式:

this(參數列表);

構造方法的調用

class Person {
    // Person的成員屬性
    private int age;
    private String name;

    // 無參數的構造方法
    Person() {
    }

    // 給姓名初始化的構造方法
    Person(String nm) {
        name = nm;
    }

    // 給姓名和年齡初始化的構造方法
    Person(String nm, int a) {
        // 由於已經存在給姓名進行初始化的構造方法 name = nm;因此只需要調用即可
        // 調用其他構造方法,需要通過this關鍵字來調用
        this(nm);
        // 給年齡初始化
        age = a;
    }
}

2.2 this的原理圖解

瞭解了構造方法之間是可以相互調用,那為什麼他們之間通過this就可以調用呢?

通過上面的學習,簡單知道使用this可以實現構造方法之間的調用,但是為什麼就會知道this調用哪一個構造方法呢?接下來需要圖解完成。

class Person {
    private int age;
    private String name;

    Person() {
    }
    Person(String nm) {
        name = nm;
    }
    Person(String nm, int a) {
        this(nm);
        age = a;
    }
}

class PersonDemo {
    public static void main(String[] args) {
        Person p = new Person("張三", 23);
    }
}

 

 

 

圖列說明:

1、先執行main方法,main方法壓棧,執行其中的new Person(“張三”,23);

2、堆記憶體中開闢空間,併為其分配記憶體地址0x33,,緊接著成員變數預設初始化(name=null  age = 0);

3、擁有兩個參數的構造方法(Person(String nm , int a))壓棧,在這個構造方法中有一個隱式的this,因為構造方法是給對象初始化的,那個對象調用到這個構造方法,this就指向堆中的那個對象。

4、由於Person(String nm , int a)構造方法中使用了this(nm);構造方法Person(String nm)就會壓棧,並將“張三”傳遞給nm。在Person(String nm , int a)構造方法中同樣也有隱式的this,this的值同樣也為0x33,這時會執行其中name = nm,即把“張三”賦值給成員的name。當賦值結束後Person(String nm , int a)構造方法彈棧。

5、程式繼續執行構造方法(Person(String nm , int a)中的age = a;這時會將23賦值給成員屬性age。賦值結束構造方法(Person(String nm , int a)彈棧。

6、當構造方法(Person(String nm , int a)彈棧結束後,Person對象在記憶體中創建完成,並將0x33賦值給main方法中的p引用變數。

註意:

this到底代表什麼呢?this代表的是對象,具體代表哪個對象呢?哪個對象調用了this所在的方法,this就代表哪個對象。

調用其他構造方法的語句必須定義在構造方法的第一行,原因是初始化動作要最先執行。

2.3 成員變數和局部變數同名問題

通過上面學習,基本明確了對象初始化過程中的細節,也知道了構造方法之間的調用是通過this關鍵字完成的。但this也有另外一個用途,接下來我們就學習下。

當在方法中出現了局部變數和成員變數同名的時候,那麼在方法中怎麼區別局部變數成員變數呢?可以在成員變數名前面加上this.來區別成員變數和局部變數

class Person {
    private int age;
    private String name;

    // 給姓名和年齡初始化的構造方法
    Person(String name, int age) {
        // 當需要訪問成員變數是,只需要在成員變數前面加上this.即可
        this.name = name;
        this.age = age;
    }

    public void speak() {
        System.out.println("name=" + this.name + ",age=" + this.age);
    }
}

class PersonDemo {
    public static void main(String[] args) {
        Person p = new Person("張三", 23);
        p.speak();
    }
}

2.4 this的應用

學習完了構造方法、this的用法之後,現在做個小小的練習。

需求:在Person類中定義功能,判斷兩個人是否是同齡人

class Person {
    private int age;
    private String name;

    // 給姓名和年齡初始化的構造方法
    Person(String name, int age) {
        // 當需要訪問成員變數是,只需要在成員變數前面加上this.即可
        this.name = name;
        this.age = age;
    }

    public void speak() {
        System.out.println("name=" + this.name + ",age=" + this.age);
    }

    // 判斷是否為同齡人
    public boolean equalsAge(Person p) {
        // 使用當前調用該equalsAge方法對象的age和傳遞進來p的age進行比較
        // 由於無法確定具體是哪一個對象調用equalsAge方法,這裡就可以使用this來代替
        /*
         * if(this.age == p.age) { return true; } return false;
         */
        return this.age = p.age;
    }
}

3. super關鍵字

3.1 子父類中構造方法的調用

在創建子類對象時,父類的構造方法會先執行,因為子類中所有構造方法的第一行有預設的隱式super();語句。

格式:

調用本類中的構造方法
this(實參列表);
調用父類中的空參數構造方法
super();
調用父類中的有參數構造方法
    super(實參列表);

為什麼子類對象創建都要訪問父類中的構造方法?因為子類繼承了父類的內容,所以創建對象時,必須要先看父類是如何對其內容進行初始化的,看如下程式:

public class Test {
    public static void main(String[] args) {
        new Zi();
    }
    
}
class Fu{
    int num ;
    Fu(){
        System.out.println("Fu構造方法"+num);
        num = 4;
    }
}
class Zi extends Fu{
    Zi(){
         //super(); 調用父類空參數構造方法
        System.out.println("Zi構造方法"+num);
    }
}

執行結果:

       Fu構造方法0

       Zi構造方法4 

通過結果發現,子類構造方法執行時中,調用了父類構造方法,這說明,子類構造方法中有一句super()。

那麼,子類中的構造方法為什麼會有一句隱式的super()呢?

原因:子類會繼承父類中的內容,所以子類在初始化時,必須先到父類中去執行父類的初始化動作。這樣,才可以使用父類中的內容。

當父類中沒有空參數構造方法時,子類的構造方法必須有顯示的super語句,指定要訪問的父類有參數構造方法。

3.2 子類對象創建過程的細節

如果子類的構造方法第一行寫了this調用了本類其他構造方法,那麼super調用父類的語句還有嗎?

這時是沒有的,因為this()或者super(),只能定義在構造方法的第一行,因為初始化動作要先執行。

父類構造方法中是否有隱式的super呢?

也是有的。記住:只要是構造方法預設第一行都是super();

父類的父類是誰呢?super調用的到底是誰的構造方法呢?

Java體系在設計,定義了一個所有對象的父類Object

 

註意:

類中的構造方法預設第一行都有隱式的super()語句,在訪問父類中的空參數構造方法。所以父類的構造方法既可以給自己的對象初始化,也可以給自己的子類對象初始化。

如果預設的隱式super()語句在父類中沒有對應的構造方法,那麼必須在構造方法中通過this或者super的形式明確要調用的構造方法。

3.3 super應用

練習:描述學生和工人這兩個類,將他們的共性name和age抽取出來存放在父類中,並提供相應的get和set方法,同時需要在創建學生和工人對象就必須明確姓名和年齡

//定義Person類,將Student和Worker共性抽取出來
class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        // super();
        this.name = name;
        this.age = age;
    }
    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;
    }
}
class Student extends Person {
    // Student類的構造方法
    Student(String name, int age) {
        // 使用super關鍵字調用父類構造方法,進行相應的初始化動作
        super(name, age);
    }
    public void study() {// Studnet中特有的方法
        System.out.println(this.getName() + "同學在學習");
    }
}
class Worker extends Person {
    Worker(String name, int age) {
        // 使用super關鍵字調用父類構造方法,進行相應的初始化動作
        super(name, age);
    }
    public void work() {// Worker 中特有的方法
        System.out.println(this.getName() + "工人在工作");
    }
}
public class Test {
    public static void main(String[] args) {
        Student stu = new Student("小明",23);
stu.study();
        
Worker w = new Worker("小李",45);
w.work();
    }
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 下表列出了用於操作HTML和CSS的所有方法。 ...
  • 0--前言 對於分散式系統環境,主鍵ID的設計很關鍵,什麼自增intID那些是絕對不用的,比較早的時候,大部分系統都用UUID/GUID來作為主鍵,優點是方便又能解決問題,缺點是插入時因為UUID/GUID的不規則導致每插入一條數據就需要重新排列一次,性能低下;也有人提出用UUID/GUID轉lon ...
  • 中介者模式: 1、定義:用一個中介對象來封裝一系列的對象交互,中介者使各對象不需要顯式地相互引用, 從而使其耦合鬆散,而且可以獨立地改變它們之間的交互 2、模型結構: (1)抽象中介者(Mediator):它是中介者的介面,提供了同事對象註冊與轉發同事對象信息的抽象方法 (2)具體中介者(Concr ...
  • 1.代碼生成器: [正反雙向](單表、主表、明細表、樹形表,快速開發利器)freemaker模版技術 ,0個代碼不用寫,生成完整的一個模塊,帶頁面、建表sql腳本、處理類、service等完整模塊2.多數據源:(支持同時連接無數個資料庫,可以不同的模塊連接不同數的據庫)支持N個數據源3.阿裡資料庫連 ...
  • 1. final關鍵字 1.1 final的概念 繼承的出現提高了代碼的復用性,並方便開發。但隨之也有問題,有些類在描述完之後,不想被繼承,或者有些類中的部分方法功能是固定的,不想讓子類重寫。可是當子類繼承了這些特殊類之後,就可以對其中的方法進行重寫,那怎麼解決呢? 要解決上述的這些問題,需要使用到 ...
  • GoLang 開山篇 1、Golang 的學習方向 Go語言,我們可以簡單的寫成Golang. 2、GoLang 的應用領域 2.1 區塊鏈的應用開發 2.2 後臺的服務應用 2.3 雲計算/雲服務後臺應用 3、學習方法的介紹 建立一個整體框架、然後細節 在實際工作中,要培養用到什麼,能夠快速學習什 ...
  • 一、遞歸 1、遞歸的定義 在一個函數內部調用函數自身。 2、遞歸的最大深度--996 修改最大深度 我們會發現,將遞歸的最大深度改成100000後,並沒有達到100000,這是由我們的電腦性能決定的。 3、遞歸的特點 (1)調用自身 (2)必須要有結束條件 4、實例 菲波那切數列:0 1 1 2 ...
  • python day4 元組/字典/集合類知識點補充 (學習資源來自老男孩教育) 2019/10/7 [TOC] 1. 元組tuple知識點補充 創建和轉換 ,比如 元組的特性 元組的特性:元組的元素不可修改,但是元素的元素可以被修改。即元組的兒子不能變,但是元組的孫子可以變。 2. 字典dict的 ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...