day08_封裝(private丶this丶構造方法)

爲什麼需要封裝,封裝的作用和含義?

面向對象共有三個特徵:封裝,繼承,多態。接下來我們具體學習封裝。我們程序設計追求“高內聚,低耦合”。

  • 高內聚 :類的內部數據操作細節自己完成,不允許外部干涉;
  • 低耦合 :僅對外暴露少量的方法用於使用。

隱藏對象內部的複雜性,只對外公開簡單的接口。便於外界調用,從而提高系統的可擴展性、可維護性。通俗的說,把該隱藏的隱藏起來,該暴露 的暴露出來。這就是封裝性的設計思想。

原則

  • 屬性隱藏起來,若需要訪問某個屬性,提供公共方法對其訪問。

封裝表現:

  • 方法就是一個最基本封裝體。
  • 類其實也是一個封裝體。

封裝的基本步驟

  1. 使用 private 關鍵字來修飾成員變量。
  2. 對需要訪問的成員變量,提供對應的一對 getXxx 方法 、 setXxx 方法。

Java中通過將數據聲明爲私有的(private),再提供公共的(public) 方法:getXxx()setXxx()實現對該屬性的操作,以實現下述目的:

  • 隱藏一個類中不需要對外提供的實現細節;
  • 使用者只能通過事先定製好的方法來訪問數據,可以方便地加入控制邏輯, 限制對屬性的不合理操作;
  • 便於修改,增強代碼的可維護性;

代碼示例

package demo04;

/*
 *  描述現實生活中的人的事物
 *    屬性:  姓名 年齡
 *    功能:  說話
 *
 *  出現安全問題: age問題,可能出現賦值爲負數的情況
 *  負數不會導致程序問題,違反生活中的真實情況
 *
 *  提高安全問題: 讓外面的類,不允許直接調用我的成員變量
 *  新的關鍵字  private 私有   屬於成員修飾符,不能修飾局部變量
 *  被private修飾的成員,只能在自己的本類中被使用
 *
 *  對私有變量,提供公共的訪問方式: 方法
 */
public class Person {
    //人的姓名,成員變量
    String name;
    //人的年齡,成員變量
    private int age ;

    //變量age被私有,提供方法,讓外面的類使用
    //定義方法,對age變量進行賦值,方法名字,必須set開頭
    public void setAge(int a){
        //對變量參數a進行範圍的限制
        if(a<0 || a > 200){
            //如果a超過範圍,手動將age賦值爲20
            age = 20;
        }else{
            //如果a沒有超過範圍,直接對age賦值
            age = a;
        }
    }

    //定義方法,對變量age獲取值使用,方法名字get
    public int getAge(){
        return age;
    }


    //定義人的說話功能,方法中,要求說出自己的姓名和年齡
    public void speak(){
        System.out.println(name+"..."+age);
    }
}

定義測試類

package demo04;


/*
 *   定義好的Person類進行測試
 *   創建對象,對象調用屬性和方法
 */
public class PersonTest {

    public static void main(String[] args) {
        //創建Person類的對象  new
        Person p = new Person();
        //對成員變量賦值
        //p.age = -200;
        //對成員變量age賦值,只能調用Set方法賦值
        p.setAge(50);

        p.name = "張三";
        //調用類中方法
        p.speak();

        //輸出成員變量age值,必須調用get方法
        System.out.println(p.getAge());
    }

}

四種訪問權限修飾符

           

我們發現 setXxx 方法中的形參名字並不符合見名知意的規定,那麼如果修改與成員變量名一致,是否就見名知意了呢?經過修改和測試,我們發現新的問題,成員變量賦值失敗了。也就是說,在修改了 setXxx() 的形參變量名後,方法並沒有給成員變量賦值!這是由於形參變量名與成員變量名重名,導致成員變量名被隱藏,方法中的變量名,無法訪問到成員變量,從而賦值失敗。所以,我們只能使用this關鍵字,來解決這個重名問題。

關鍵字this是什麼?

Java中,它的作用和其詞義很接近。

  • 它在方法內部使用,即這個方法所屬對象的引用;
  • 它在構造器內部使用,表示該構造器正在初始化的對象。
  • this 可以調用類的屬性、方法和構造器

什麼時候使用this關鍵字呢?

  • 當在方法內需要用到調用該方法的對象時,就用this。 具體的:我們可以用this來區分屬性局部變量

我們來改造一下什麼的Person類

package demo05;


/*
 *   類描述人:
 *     屬性: 姓名和年齡
 *     方法: 說話
 *
 *   私有化所有的屬性 (成員變量) ,必須寫對應的get/set方法
 *   凡是自定義的類,自定義成員變量,應該私有化,提供get/set
 *
 *   this關鍵字:
 *     區分成員變量和局部變量同名情況
 *     方法中,方位成員變量,寫this.
 */
public class Person {
    private String name;
    private int age;

    // set方法,變量name,age賦值
    public void setAge(int age) {
        this.age = age;
    }

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

    // get方法,變量name,age獲取值
    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public void speak() {
        String  name = "哈哈";
        int age = 16;

        System.out.println("人在說話  " + this.name + "..." + this.age);
    }
}

定義測試類

package demo05;


public class PersonTest {
    public static void main(String[] args) {
        Person p = new Person();
        //調用set方法,對成員變量賦值
        p.setAge(18);
        p.setName("旺財");
        p.speak();


        //調用get方法,獲取成員變量的值
        System.out.println(p.getName());
        System.out.println(p.getAge());
    }
}

經過測試變量重名問題就解決了。

構造方法

我們對封裝已經有了基本的瞭解,接下來我們來看一個新的問題,依然以Person爲例,由於Person中的屬性都被private了,外界無法直接訪問屬性,必須對外提供相應的set和get方法。當創建人對象的時候,人對象一創建就要明確其姓名和年齡,那該怎麼做呢?使用構造方法,那什麼是構造方法呢?從字面上理解即爲構建創造時用的方法,即就是對象創建時要執行的方法。既然是對象創建時要執行的方法,那麼只要在new對象時,知道其執行的構造方法是什麼,就可以在執行這個方法的時候給對象進行屬性賦值。

構造方法的作用:

當一個對象被創建時候,構造方法用來初始化該對象,給對象的成員變量賦初始值。

定義格式

構造器的特徵

  • 它具有與類相同的名稱
  • 它不聲明返回值類型。(與聲明爲void不同)
  • 不能被staticfinalsynchronizedabstractnative修飾,不能有 return語句返回值

注 意:

  • Java語言中,每個類都至少有一個構造器
  • 默認構造器的修飾符與所屬類的修飾符一致
  • 一旦顯式定義了構造器,則系統不再提供默認構造器
  • 一個類可以創建多個重載的構造器
  • 父類的構造器不可被子類繼承

代碼示例

/*
 *  自定義的Person類.成員變量,name age
 *  要求在 new Person的同時,就指定好name,age的值
 *  實現功能,利用方法去實現, 構造方法,構造器 Constructor
 *  作用: 在new 的同時對成員變量賦值, 給對象的屬性初始化賦值  new Person 對屬性 name,age賦值
 *
 *  構造方法的定義格式
 *    權限  方法名(參數列表){
 *    }
 *    方法的名字,必須和類的名字完全一致
 *    構造方法不允許寫返回值類型  , void 也不能寫
 *
 *    構造方法在什麼時候,運行呢, 在new 的時候,自動執行
 *    只運行一次,僅此而已
 *
 *    每個class必須擁有構造方法,構造方法不寫也有
 *    編譯的時候,javac, 會自動檢查類中是否有構造方法
 *    如果有,就這樣的
 *    如果沒有,編譯器就會自動添加一個構造方法
 *      編譯器自動添加的構造方法: public Person(){}
 *    自己手寫了構造方法,編譯的時候,不會自動添加構造方法!
 */
public class Person {
    private String name;
    private int age;

    //定義出Person類的構造方法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        //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 demo01;

/*
 *  new 對象的時候,就是在調用對象的構造方法
 *   new Person(); 調用的是類中的空參數構造方法
 *   new Person("張三",20); 調用類中的有參數構造方法
 */
public class Test {
    public static void main(String[] args) {
        Person p = new Person("張三", 20);
        //對象p 調用方法getName,getAge
        System.out.println(p.getName());
        System.out.println(p.getAge());

    }
}

構造方法和一般方法區別

  • 構造方法在對象創建時就執行了,而且只執行一次。
  • 一般方法是在對象創建後,需要使用時才被對象調用,並可以被多次調用。

​​​​​​​this調用構造方法

構造方法之間的調用,可以通過this關鍵字來完成。格式:this(參數列表);

總結一下this的用法

  •  this可以在普通方法之間相互調用
  •  this.的方式,區分局部變量和成員變量同名情況
  •  this在構造方法之間的調用

​​​​​​​代碼示例

package demo02;


public class Person {
    private String name;
    private int age;

    public Person(){
        //調用了有參數的構造方法
        //參數李四,20傳遞給了變量name,age
        //this可以在構造方法之間進行調用
        this("李四",20);
    }
    /*
     *  構造方法,傳遞String,int
     *  在創建對象的同時爲成員變量賦值
     */
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        //this.的方式,區分局部變量和成員變量同名情況
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
   public void method1(){
       System.out.println("我是方法1");
       //this在普通方法之間的調用
       this.method2();
   }
    public void method2(){
        System.out.println("我是方法2");
    }

}

注意:

  • 可以在類的構造器中使用"this(形參列表)"的方式,調用本類中重載的其 他的構造器!
  • 明確:構造器中不能通過"this(形參列表)"的方式調用自身構造器
  • 如果一個類中聲明瞭n個構造器,則最多有 n - 1個構造器中使用了 "this(形參列表)"
  • "this(形參列表)"必須聲明在類的構造器的首行!
  • 在類的一個構造器中,最多隻能聲明一個"this(形參列表)"

總結:屬性賦值過程

截止到目前,我們講到了很多位置都可以對類的屬性賦值。現總結這幾個位 置,並指明賦值的先後順序。

賦值的位置:
  • ① 默認初始化
  • ② 顯式初始化
  • ③ 構造器中初始化
  • ④ 通過“對象.屬性“或“對象.方法”的方式賦值
賦值的先後順序: ① - ② - ③ - ④
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章