1. 程式人生 > >12_Java面向對象_第12天(構造方法、this、super)_講義

12_Java面向對象_第12天(構造方法、this、super)_講義

ride 學習 代碼執行 客戶端軟件 抽象 getname 程序 修飾 所有

今日內容介紹
1、構造方法
2、this關鍵字
3、super關鍵字
4、綜合案例

01構造方法引入

  • A:構造方法的引入
  •   在開發中經常需要在創建對象的同時明確對象的屬性值,
      比如員工入職公司就要明確他的姓名、年齡等屬性信息。
      那麽,創建對象就要明確屬性值,那怎麽解決呢?也就是在創建對象的時候就要做的事情,
      當使用new關鍵字創建對象時,怎麽給對象的屬性初始化值呢?
      這就要學習Java另外一門小技術,構造方法。
  • B: 那什麽是構造方法呢?
  •       從字面上理解即為構建創造時用的方法,即就是對象創建時要執行的方法。既然是對
          象創建時要執行的方法,那麽只要在new對象時,
          知道其執行的構造方法是什麽,就可以在執行這個方法的時候給對象進行屬性賦值。

02構造方法作用

  • A: 構造方法的作用:
  •   在new的同時給成員變量賦值,給對象屬性進行初始化。
  • B: 舉例:
  •   Perons p = new Person("張三",23); 在new 的時候給p對象的name屬性和age屬性進行賦值,使這個對象的屬性有值。

03構造方法的定義和運行特點

  • A: 構造方法定義
  •   構造方法的格式:
      修飾符 構造方法名(參數列表)
      {
      }
  • B: 構造方法的體現:
  •   構造方法沒有返回值類型。也不需要寫返回值。因為它是為構建對象的,對象創建完,方法就執行結束。
      構造方法名稱必須和類型保持一致。
      構造方法沒有具體的返回值。
      構造方法的代碼體現:
  • C: 構造方法舉例
  •   class Person {
          // Person的成員屬性age和name
          private int age;
          private String name;
    
          // Person的構造方法,擁有參數列表
          Person(int a, String nm) {
              // 接受到創建對象時傳遞進來的值,將值賦給成員屬性
              age = a;
              name = nm;
          }
      }
  • D: 構造方法運行特點:
  •   在new 對象的時候自動調用執行。

04默認添加的構造方法

  • A: 每一class類都必須有一個構造方法,構造方法不寫也有。
  • 編譯的時候,javac,系統會自動檢查類中是否有構造方法,如果沒有編譯器就會自動添加一個構造方法
    比如Person類, 編譯器添加一個無參構造 public Person(){}

05構造方法的調用賦值

  • A: 理解構造方法的格式和基本功能之後,現在就要研究構造方法是怎麽執行的呢?在創建對象的時候是如何初始化的呢?
  • 構造方法是專門用來創建對象的,也就是在new對象時要調用構造方法。現在來看看如何調用構造方法。

  • B: 案例
  •   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();
          }
      }

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

06構造方法的內存

技術分享圖片

A:內存加載的過程

有一個Person類, 創建Person 對象new Person()

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。

07構造方法的重載

  • A:當在描述事物時,要不要在類中寫構造方法呢?這時要根據描述事物的特點來確定,當描述的事物在創建其對象時就要明確屬性的值,這時就需要在定義類的時候書寫帶參數的構造方法。
  • 若創建對象時不需要明確具體的數據,這時可以不用書寫構造方法(不書寫也有默認的構造方法)。
  • 構造方法的細節:
    1、一個類中可以有多個構造方法,多個構造方法是以重載的形式存在的
    2、構造方法是可以被private修飾的,作用:其他程序無法創建該類的對象。
  • B: 舉例

      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;
          }
      }

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

* A: 目前為止,學習兩種方法,分別為構造方法和一般方法,那麽他們之間有什麽異同呢?
* 
    1.格式不同
     構造方法 : 修飾符  類名(參數類型 參數 ...){
        初始化成員變量
    }
    一般方法: 需要有返回值類型
    2.作用不同
    構造方法一般用來給成員變量初始化;
    一般方法根據需求而定;
    3.調用方式不同
    構造方法創建對象時調用, 或者this() super() 語句調用
    普通方法需要對象調用或者靜態方法直接調用靜態方法.
    4.執行不同
    構造方法在對象創建時就執行了,而且只執行一次。
    一般方法是在對象創建後,需要使用時才被對象調用,並可以被多次調用。

09this在構造方法之間的調用

  • A: 在之前學習方法之間調用時,可以通過方法名進行調用。可是針對構造方法,無法通過構造方法名來相互調用。
    構造方法之間的調用,可以通過this關鍵字來完成。
    構造方法調用格式:
    this(參數列表);

  • B:調用構造方法的案例
  •   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;
          }
      }

10this在構造方法調用的內存圖

技術分享圖片

  • A: 被加載的代碼
    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);
          }
      }
  • B: 構造方法調用的原理圖
    • 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就代表哪個對象。
      調用其他構造方法的語句必須定義在構造方法的第一行,原因是初始化動作要最先執行。

11this簡易應用

* A: 當在方法中出現了局部變量和成員變量同名的時候,那麽在方法中怎麽區別局部變
    * 量成員變量呢?可以在成員變量名前面加上this.來區別成員變量和局部變量
* 
* B: 舉例1
* 
    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();
        }
    }

* C: 舉例2
    學習完了構造方法、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;
        }
    }

12super關鍵字_1

  • A: 子父類中構造方法的調用

      在創建子類對象時,父類的構造方法會先執行,因為子類中所有構造方法的第一行有默認的隱式super();語句。
  • B: 格式:
  •   調用本類中的構造方法
      this(實參列表);
      調用父類中的空參數構造方法
      super();
      調用父類中的有參數構造方法
      super(實參列表);

13super關鍵字_2

  • A:子類構造方法,有一個默認添加的構造方法
  •   public class Student extends Person {
           public Student(){
              super();
           }
      }
  • B :為什麽子類對象創建都要訪問父類中的構造方法?因為子類繼承了父類的內容,所以創建對象時,必須要先看父類是如何對其內容進行初始化的,看如下程序
  •       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語句,指定要訪問的父類有參數構造方法。

14子類父類的內存圖

技術分享圖片

15super關鍵字_3

  • A: 創建子類對象的時候會必須調用父類的構造方法。
  •  子類默認會調用父類的無參構造, 但如果父類沒有無參構造,子類的構造方法繼續調用父類的無參構造就會報錯。
     因此子類構造方法的第一行需要調用父類的構造方法,既可以調用父類的無參構造,也可以調用父類的有參構造,這樣語法上就不會報錯。

16super關鍵字_4

* A: 構造方法第一行,寫this()還是super()
*  this() 是調用本類的構造方法,super()是調用父類的構造方法, 且兩條語句不能同時存在
*  保證子類的所有構造方法調用到父類的構造方法即可

* B: 小結:
* 無論如何,子類的所有構造方法,直接或間接必須調用到父類構造方法;
* 子類的構造方法什麽都不寫,默認的構造方法第一行super()

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

* A 創建子類對象過程的細節   
* 如果子類的構造方法第一行寫了this調用了本類其他構造方法,那麽super調用父類的語句還有嗎?    
* 這時是沒有的,因為this()或者super(),只能定義在構造方法的第一行,因為初始化動作要先執行。   
* 父類構造方法中是否有隱式的super呢?     
* 也是有的。記住:只要是構造方法默認第一行都是super();     
* 父類的父類是誰呢?super調用的到底是誰的構造方法呢?    
* Java體系在設計,定義了一個所有對象的父類Object   

* 註意:
    類中的構造方法默認第一行都有隱式的super()語句,在訪問父類中的空參數構造方法。
    所以父類的構造方法既可以給自己的對象初始化,也可以給自己的子類對象初始化。
    如果默認的隱式super()語句在父類中沒有對應的構造方法,那麽必須在構造方法中通過    this或者super的形式明確要調用的構造方法。

18super的應用

 * A: 練習:描述學生和工人這兩個類,將他們的共性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();
        }
    }

19完整員工案例分析

  • A: 項目介紹
  •   某IT公司有多名員工,按照員工負責的工作不同,進行了部門的劃分(研發部員工、維護部員工)。
      研發部根據所需研發的內容不同,又分為JavaEE工程師、Android工程師;維護部根據所需維護
      的內容不同,又分為網絡維護工程師、硬件維護工程師。
      公司的每名員工都有他們自己的員工編號、姓名,並要做它們所負責的工作。
      工作內容
      JavaEE工程師:員工號為xxx的 xxx員工,正在研發淘寶網站
      Android工程師:員工號為xxx的 xxx員工,正在研發淘寶手機客戶端軟件
      網絡維護工程師:員工號為xxx的 xxx員工,正在檢查網絡是否暢通
      硬件維護工程師:員工號為xxx的 xxx員工,正在修復打印機
      請根據描述,完成員工體系中所有類的定義,並指定類之間的繼承關系。進行XX工程師類的對象創建,完成工作方法的調用。
  • B: 案例分析
  •   根據上述部門的描述,得出如下的員工體系圖
    
      根據員工信息的描述,確定每個員工都有員工編號、姓名、要進行工作。則,
      把這些共同的屬性與功能抽取到父類中(員工類),關於工作的內容由具體的工程師來進行指定。
      工作內容
      JavaEE工程師:員工號為xxx的 xxx員工,正在研發淘寶網站
      Android工程師:員工號為xxx的 xxx員工,正在研發淘寶手機客戶端軟件
      網絡維護工程師:員工號為xxx的 xxx員工,正在檢查網絡是否暢通
      硬件維護工程師:員工號為xxx的 xxx員工,正在修復打印機
      創建JavaEE工程師對象,完成工作方法的調用

20案例代碼實現

  • A:定義員工類(抽象類)
  •   public abstract class Employee {
          private String id;// 員工編號
          private String name; // 員工姓名
    
          //空參數構造方法
          public Employee() {
              super();
          }
          //有參數構造方法
          public Employee(String id, String name) {
              super();
              this.id = id;
              this.name = name;
          }
          public String getId() {
              return id;
          }
          public void setId(String id) {
              this.id = id;
          }
          public String getName() {
              return name;
          }
          public void setName(String name) {
              this.name = name;
          }
          //工作方法(抽象方法)
          public abstract void work(); 
      }
  • B : 定義研發部員工類Developer 繼承 員工類Employee
  •   public abstract class Developer extends Employee {
          //空參數構造方法
          public Developer() {
              super();
          }
          //有參數構造方法
          public Developer(String id, String name) {
              super(id, name);
          }
      }
  • C: 定義維護部員工類Maintainer 繼承 員工類Employee
  •   public abstract class Maintainer extends Employee {
          //空參數構造方法
          public Maintainer() {
              super();
          }
          //有參數構造方法
          public Maintainer(String id, String name) {
              super(id, name);
          }
      }
  • D: 定義JavaEE工程師 繼承 研發部員工類,重寫工作方法
  •   public class JavaEE extends Developer {
          //空參數構造方法
          public JavaEE() {
              super();
          }
          //有參數構造方法
          public JavaEE(String id, String name) {
              super(id, name);
          }
    
          @Override
          public void work() {
              System.out.println("員工號為 " + getId() + " 的 " + getName() + " 員工,正在研發淘寶網站");
          }
      }
  • E: 定義Android工程師 繼承 研發部員工類,重寫工作方法
  •   public class Android extends Developer {
          //空參數構造方法
          public Android() {
              super();
          }
          //有參數構造方法
          public Android(String id, String name) {
              super(id, name);
          }
    
          @Override
          public void work() {
              System.out.println("員工號為 " + getId() + " 的 " + getName() + " 員工,正在研發淘寶手機客戶端軟件");
          }
      }
  • F: 定義Network網絡維護工程師 繼承 維護部員工類,重寫工作方法
  •   public class Network extends Maintainer {
          //空參數構造方法
          public Network() {
              super();
          }
          //有參數構造方法
          public Network(String id, String name) {
              super(id, name);
          }
    
          @Override
          public void work() {
              System.out.println("員工號為 " + getId() + " 的 " + getName() + " 員工,正在檢查網絡是否暢通");
          }
      }
  • G: 定義Hardware硬件維護工程師 繼承 維護部員工類,重寫工作方法
  •   public class Hardware extends Maintainer {
          //空參數構造方法
          public Hardware() {
              super();
          }
          //有參數構造方法
          public Hardware(String id, String name) {
              super(id, name);
          }
    
          @Override
          public void work() {
              System.out.println("員工號為 " + getId() + " 的 " + getName() + " 員工,正在修復打印機");
          }
      }
  • H: 在測試類中,創建JavaEE工程師對象,完成工作方法的調用
  •   public class Test {
          public static void main(String[] args) {
              //創建JavaEE工程師員工對象,該員工的編號000015,員工的姓名 小明
              JavaEE ee = new JavaEE("000015", "小明");
              //調用該員工的工作方法
              ee.work();
          }
      }

作業測試

1、構造方法的格式是什麽?有哪些註意事項?
權限修飾符 類名(參數列表){方法體}

2、構造方法可以重載嗎? 裏邊可以有return語句嗎?
可以重載 可以有return但不能有返回值

3、給成員變量賦值有幾種方式?有什麽區別?
get/set
直接賦值
帶參構造器賦值
初始化
static 代碼塊賦值
默認構造器賦值

4.編寫一個完整的Person類,使用this關鍵字給成員變量進行賦值.
在測試類中測試
代碼:

public class HomeWork {
    public static void main(String[] args) {
        Person p = new Person();
        p.run();
        System.out.println(p.getAge());
        System.out.println(p.getName());
    }
}

class Person {
    private int age;
    private String name;

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public void run() {
        this.age = 10;
        this.name = "邊天旭";
    }
}

5、根據需求,完成如下代碼(按照標準格式寫),並在測試類中進行測試。

標準格式包含: 私有屬性   無參構造  有參構造  setter 和getter 需求中的方法
需求一:
    員工類Employee
        屬性:姓名name,工號id,工資salary 
        行為:顯示所有成員信息的方法show()

代碼:

class Employee {
    private String name;
    private String id;
    private double salary;

    public Employee() {
        super();
        // TODO Auto-generated constructor stub
    }

    public Employee(String name, String id, double salary) {
        super();
        this.name = name;
        this.id = id;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

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

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public void show() {
        System.out.println("姓名:" + this.name);
        System.out.println("工號:" + this.id);
        System.out.println("工資:" + this.salary);
    }
}

需求二:
    動物類Animal
        屬性:姓名name,年齡age
        行為:吃飯eat,睡覺sleep

代碼:

class Animal {
    private String name;
    private int 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;
    }

    public Animal(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public Animal() {
        super();
    }

    public void eat() {
        System.out.println("動物吃飯");
    }

    public void sleep() {
        System.out.println("動物睡覺");
    }
}

    需求三:
        人類Person
            屬性:姓名name,年齡age,性別gender
            行為:學習study,睡覺sleep

代碼:

class person {
    private String name;
    private int age;
    private char gender;

    public person() {
        super();
        // TODO Auto-generated constructor stub
    }

    public person(String name, int age, char gender) {
        super();
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    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;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }

    public void study() {
        System.out.println("學生學習");
    }

    public void sleep() {
        System.out.println("學生睡覺");
    }
}

12_Java面向對象_第12天(構造方法、this、super)_講義