anonymous的Java學習筆記(5)——面向對象之類與對象

面向對象

Java是面向對象的程序設計語言, Java 語言提供了定義類、成員變量、方法等最基本的功能 。

類與對象

所有使用類定義的變量都是引用變量,它們將會引用到類的對象。也就是說,所有類是引用類型。

定義類

面向對象的程序設計過程中有兩個重要概念:類(class)和對象(object,也被稱爲實例,instance),其中類是某一批對象的抽象,可以把類理解成某種概念。對象纔是一個具體存在的實體,從這個意義上來看,日常所說的人,其實都是人的實例,而不是人類。

定義類語法格式

[修飾符] class 類名
{
    零個到多個構造器定義...
    零個到多個成員變量...
    零個到多個方法...
}

在上邊的語法格式中

  • 修飾符可以是publicfinalabstract,或者完全省略這三個修飾符
  • 類名命名規則遵循大駝峯命名法規則:每個單詞首字母大寫,其他字母全部小寫,單詞與單詞之間不要使用任何分隔符。
    • 例如
    MyTest、HandleExcel、HandleRequests
    

類的組成

一個類通常包含三中最常見的成員。

  • 構造器
    • 構造器是一個類創建對象的根本途徑,如果一個類沒有構造器,這個類通常無法創建實例。
    • 因此,Java語言提供了一個功能:如果程序員沒有爲一個類編寫構造器,則系統會爲該類提供一個默認的構造器。一旦程序員爲一個類提供了構造器,系統將不再爲該類提供構造器。
  • 成員變量:成員變量用於定義該類或該類的實例所包含的狀態數據。
  • 方法:方法則用於定義該類或該類的實例的行爲特徵或者功能實現。

需要注意的點

  1. 類中的成員數量無限制。
  2. 類中各成員之間的定義順序沒有要求,各成員之間可以互相調用。但是static修飾的成員不能訪問沒有static修飾的成員。

成員變量

定義成員變量語法格式

[修飾符] 類型 成員變量名 [=默認值];

成員變量詳細說明

  • 修飾符
    • 可以省略
    • 可以是publicprotectedprivatestaticfinal,其中publicprotectedprivate三個最多隻能出現一個,可以與staticfinal組合使用來修飾成員變量
  • 類型
    • 不可省略,可以是基本數據類型和引用數據類型。
  • 成員變量名
    • 遵循小駝峯命名法規則:第一個單詞首字母小寫,後面每個單詞首字母大寫,其他字母全部小寫,單詞與單詞之間不要使用任何分隔符。
  • 默認值
    • 定義成員變量還可以指定 個可邊的默認值

方法

定義方法語法格式

[修飾符] 方法返回值類型 方法名(形參列表)
{
    //由零條或多條可執行語句組成的方法體
}

方法詳細說明

  • 修飾符
    • 可以省略
    • 可以是publicprotectedprivatestaticfinal,其中publicprotectedprivate三個最多隻能出現一個,可以與staticfinal組合使用來修飾方法
  • 方法返回值類型
    • 返回值類型可以是基本數據類型和引用類型
    • 如果聲明瞭方法返回值類型,方法體內必須提供一個return語句,返回一個變量或表達式。變量或者表達式的類型必須與此處聲明的類型匹配。
    • 如果未聲明方法返回值類型,必須使用void聲明該方法沒有返回值。
  • 方法名
    • 方法名命名規則與成員變量命名規則一致。
  • 形參列表
    • 形參列表用於定義該方法可以接受的參數
    • 格式:由零組或多組形參組成
      • 零組就是值該方法沒有形參
      • 一組形參:(數據類型 形參名)
      • 多組形參:(數據類型 形參名1, 數據類型 形參名2)
    • 一旦定義方法時指定了形參列表,調用方法時必須傳入對應的參數值(誰調用方法,誰負責爲形參賦值)
  • 方法體
    • 方法體裏多條可執行性語句之間有嚴格的執行順序,排在方法體前面的語句總是先執行,排在方法體後面的語句總是後執行。

static關鍵字

static的真正作用就是用於區分成員變量、方法、內部類、初始化塊這四種成員到底屬於類本身還是屬於實例。

在類中定義的成員,static相當於一個標誌,有static修飾的成員屬於類本身,沒有static修飾的成員屬於該類的實例。

  • 通常把static修飾的成員變量和方法也稱爲類變量、類方法。
  • 不使用static修飾的普通方法、成員變量則屬於該類的單個實例,而不屬於該類。因此通常把不使用static修飾的成員變量和方法也稱爲實例變量、實例方法。

構造器

構造器是一個特殊的方法,定義構造器的語法格式與定義方法的語法格式很像,定義構造器的語法格式如下:

[修飾符] 構造器名 (形參列表)
{
    //由零條到多條可執行性語句組成的構造器執行體
}

構造器詳細說明

  • 修飾符
    • 可以省略
    • 可以是publicprotectedprivate其中之一
  • 構造器名字:構造器名字必須與類名相同。
  • 形參列表:和定義方法形參列表的格式完全相同。
    使用構造器時需要注意的點
  • 構造器既不能定義返回值類型,也不能使用void聲明構造器沒有返回值。
  • 如果爲構造器定義了返回值類型,或使用void聲明構造器沒有返回值,編譯時不會出錯,但Java會把這個所謂的構造器當成方法來處理——>它就不再是構造器。

構造器不是沒有返回值嗎,爲什麼不能用void來聲明呢?

  1. 這是Java語法的規定
  2. 實際上,類的構造器是有返回值的。當使用new關鍵字來調用構造器時,構造器返回該類的實例,可以把這個類的實例當成構造器的返回值,因此構造器的返回值類型總是當前類,無需定義返回值類型。
  3. 必須注意:不要在構造器裏顯式使用return來返回當前類的對象,因爲構造器的返回值是隱式的。

定義一個Person類

public class Person{
    //定義兩個成員變量
    public String name;
    public int age;
    //定義一個say方法
    public void say(String content){
        System.out.println(content);
    }
}

上邊的Person類裏沒有手動定義構造器,系統自動爲該類提供一個構造器,系統提供的構造器總是沒有參數的。

Java中類的作用

  • 定義變量
  • 創建對象
  • 調用類的類方法或訪問類的類變量。

使用類

對象的產生和使用

創建對象的根本途徑是構造器,通過new關鍵字來調用某個類的構造器即可創建這個類的實例。

創建對象
//使用Person類定義一個Person類型的變量
Person p;
//通過new關鍵字調用Person類的構造器,返回一個Person實例
//講該Person實例賦值給p
p = new Person();
//上邊代碼可以簡寫成一行代碼
Person p = new Person();
使用對象

Java的對象大致有如下作用

  • 訪問對象的實例變量(也叫實例屬性)
  • 調用對象的方法

注意點

  • 類或實例訪問方法或成員變量的語法是:類.類變量|方法,或者實例.實例變量|方法
  • static修飾的方法和成員變量,既可通過類來調用,也可通過實例來調用
  • 沒有使用static修飾的普通方法和成員變量,只可通過實例來調用
  • 如果堆內存裏的對象沒有任何變量指向該對象,那麼程序將無法再訪問該對象,這個對象也就變了垃圾,Java的垃圾回收機制將回收該對象,釋放該對象所佔的內存區。
  • 如果希望通知垃圾回收機制回收某個對象,只需要切斷該對象的所有引用變量和它之間的關係即可,也就是把這些引用變量賦值爲**null**。

代碼示例

Person.java

package com.abc.part_four;

public class Person {
    //定義兩個成員變量
    public String name;
    public int age;

    //定義一個say方法
    public void say(String content) {
        System.out.println(content);
    }

}

PersonTest.java

package com.abc.part_four;

public class PersonTest {
    public static void main(String[] args) {
        Person p = new Person();
        System.out.println("***************未對Person類的實例屬性name,age進行賦值前***************");
        System.out.println(p.name);
        System.out.println(p.age);
        p.name = "小明";
        p.age = 21;
        System.out.println("***************對Person類的實例屬性name,age進行賦值後***************");
        System.out.println(p.name);
        System.out.println(p.age);
        System.out.println("***************調用Person類的實例方法say***************");
        p.say("人生苦短,Let's Go!");
    }


}

運行PersonTest.java輸出以下結果

***************未對Person類的實例屬性name,age進行賦值前***************
null
0
***************對Person類的實例屬性name,age進行賦值後***************
小明
21
***************調用Person類的實例方法say***************
人生苦短,Let's Go!

大部分時候,定義一個類就是爲了重複創建該類的實例,同一個的多個實例具有相同的特徵,而類則是定義了多個實例的共同特徵。從某個角度來看,類定義的是多個實例的特徵,因此類不是一種具體存在,實例纔是具體存在 。完全可以這樣說:你不是人這個類,我也不是人這個類,我們都只是人的實例。

對象this的使用

Java中this關鍵字總是指向調用該方法的對象。this作爲對象的默認引用有兩種情形:

  1. 構造器中引用該構造器正在初始化的對象。
  2. 在方法中引用調用該方法的對象。
在方法中引用調用該方法的對象

this關鍵宇最大地作用就是讓類中一個方法,訪問該類裏的另一個方法或實例變量。

代碼示例

Dog1.java

package com.abc.part_four;

public class Dog1 {
    public String dogName;

    public void jump() {
        System.out.println("Dog jump~");
    }

    public void run() {
        dogName = "小花花";
        Dog1 dog = new Dog1();
        dog.jump();//假設Dog run的前提是Dog jump
        System.out.println("Dog run~");
    }
}

Dog2.java

package com.abc.part_four;

public class Dog2 {
    public String dogName;

    public void jump() {
        System.out.println("Dog jump~");
    }

    public void run() {
        dogName = "小花花";
        this.jump();//假設Dog run的前提是Dog jump
        System.out.println("Dog run~");
    }
}

Dog3.java

package com.abc.part_four;

public class Dog3 {
    public String dogName;

    public void jump() {
        System.out.println("Dog jump~");
    }

    public void run() {
        dogName = "小花花";
        jump();//假設Dog run的前提是Dog jump
        System.out.println("Dog run~");
    }
}

DogTest.java

package com.abc.part_four;

public class DogTest {
    public static void main(String[] args) {
        System.out.println("*********Dog1*********");
        Dog1 d1 = new Dog1();
        // 調用Dog1裏的run方法,創建兩個Dog對象
        d1.run();
        /**
         * 這裏產生了兩個問題
         * 第一個問題:Dog1類中run()方法中調用jum()方法時是否一定需要一個Dog對象?
         * 第二個問題:是否一定需要重新創建一個Dog對象?
         * 第一個問題的答案是肯定的,因爲沒有使用static修飾的成員變量和方法都必須使用對象來調用 。
         * 第二個問題的答案是否定的,因爲當程序調用run()法時,一定會提供一個Dog對象,這樣就可以直接使用這個己經存在的Dog對象,而無須重新創建新Dog對象了.
         * 因此需要在run()方法中獲得調用該方法的對象,通過this關鍵字就可以滿足這個要求。
         *
         * this可以代表任何對象,當this出現在某個方法體中時,它所代表的對象是不確定的,但它的類型是確定的:它所代表的只能是當前類的實例,只有當這個方法被調用時,它所代表的對象才被確定下來:誰在調用這個方法,this就代表誰。
         * 因此將Dog1中run()方法中使用this關鍵字來調用jump()方法會更合適些。
         * 代碼如Dog2所示
         */
        System.out.println("*********Dog2*********");
        Dog2 d2 = new Dog2();
        //調用Dog1裏的run方法,只創建了一個Dog對象
        d2.run();
        /**
         * this關鍵字可以省略
         * 代碼如Dog3所示
         */
        System.out.println("*********Dog3*********");
        Dog3 d3 = new Dog3();
        d3.run();


    }
}

對於static修飾的方法而言,可以使用類來直接調用該方法,static修飾的方法中不能使用this引用。

  • 由於static修飾的方法不能使用this引用,所以static修飾的方法不能訪問不使用static修飾的普通成員,因此Java語法規定:靜態成員(包括方法、成員變量)不能直接訪問非靜態成員(包括方法、成員變量)。

靜態方法直接訪問非靜態方法時引發錯誤代碼示例

package com.abc.part_four;

public class StaticAccessNonStatic {
    public void say1(){
        System.out.println("一個簡單的非靜態方法");
    }
    public static void say2(){
        System.out.println("一個簡單的靜態方法");
    }
    public static void main(String[] args){
        //執行程序編譯時會報錯:Error:(11, 9) java: 無法從靜態上下文中引用非靜態 方法 say1()。
        // 因爲say1()是屬於示例的方法不是屬於類的方法。因此必須需要使用對象來調用該方法。
        //say1();
        /**
         * 在上面的main()方法中直接調用say1()方法時,系統相當於使用this作爲該方法的調用者,
         * 而main()方法是static修飾的方法,static修飾的方法屬於類,而不屬於對象,因此調用static修飾的方法的主調總是類本身.
         */
        //如果確實需要在靜態方法裏調用非靜態方法。可以創建類對象,使用類對象來調用非靜態方法。
        new StaticAccessNonStatic().say1();//輸出:一個簡單的非靜態方法
        //執行不會報錯
        say2();//輸出:一個簡單的靜態方法
    }
}

大部分時候,普通方法訪問其他方法、成員變量時無須使用**this前綴 ,但如果方法裏有個局部變量和成員變量同名,但程序又需要在該方法裏訪問這個被覆蓋的成員變量,則必須使用`this1**前綴。

構造器中引用該構造器正在初始化的對象(簡單來說就是在構造器中使用this關鍵字)

this引用也可以用於構造器中作爲默認引用,由於構造器是直接使用new關鍵宇來調用,而不是使用對象來調用的,所以this在構造器中代表該構造器正在初始化的對象。

代碼示例

package com.abc.part_four;

public class ThisInConstructor {
    public String name;

    //定義一個構造器
    public ThisInConstructor() {
        //在構造器裏定義一個name變量
        String name;
        //使用this代表該構造器正在初始化的對象
        //下面的代碼將會把該構造器正在初始化的對象的name成員變量設置成`小花花`
        this.name = "小花花";
    }

    public static void main(String[] args) {
        System.out.println(new ThisInConstructor().name);//小花花
    }
}

程序輸出

小花花
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章