Java 面向對象

面向對象java

面向對象方法是一種運用對象, 類, 封裝, 繼承, 多態和消息等概念來構造, 測試, 重構軟件的方法 面向對象方法的主要優勢是符合人們一般的思惟方式從分析到設計再到編碼採用一致的模型表示 具備高度連續性軟件重用性好設計模式

過程和對象在程序中的體現: 過程其實就是函數 對象是將函數等一些內容進行了封裝數組

1. 面向對象的特色安全

1> 封裝jvm

2> 繼承函數

3> 多態 測試

2. 匿名對象使用場景this

1> 當對方法只進行一次調用的時候 可使用匿名對象編碼

2> 當對象對成員進行屢次調用時 不能使用匿名對象 必須給對象起名字spa

3. 在類中定義都稱之爲成員 成員有兩種

1> 成員變量 其實對應的就是事物的屬性

2> 成員函數 其實對應的就是事物的行爲

因此 其實定義類 就是在定義成員變量和成員函數 可是在定義前 必須先要對事物進行屬性和行爲的分析 才能夠用代碼來體現

4. private 修飾符

私有的 訪問權限最低 只有在本類中的訪問有效

注意: 私有僅僅是封裝的一種體現形式而已

5. 私有的成員

其餘類不能直接建立對象訪問 因此只有經過本類對外提供具體的訪問方式來完成對私有的訪問 能夠經過對外提供函數的形式對其進行訪問

好處: 能夠在函數中加入邏輯判斷等操做 對數據進行判斷等操做

6. 總結

屬性是用於存儲數據的 直接被訪問 容易出現安全隱患 因此 類中的屬性一般被私有化 並對外提供公共的訪問方法

這個方法通常有兩個 規範寫法: 對於屬性 age, 可使用setAge() getAge()對其進行操做

7. 類中怎麼沒有定義主函數?

注意: 主函數的存在 僅爲該類是否須要獨立運行 若是不須要 主函數是不用定義的

主函數的解釋: 保證所在類的獨立運行 是程序的入口 jvm調用

8. 成員變量和局部變量的區別

1> 成員變量直接定義在類中, 局部變量定義在方法中 參數上 語句中 

2> 成員變量在這個類中有效, 局部變量只在本身所屬的大括號內有效 大括號結束 局部變量失去做用域

3> 成員變量存在於堆內存中 隨着對象的產生而存在 消失而消失, 局部變量存在於棧內存中 隨着所屬區域的運行而存在 結束而釋放 

9. 構造函數

1> 用於給對象進行初始化 是給與之對應的對象進行初始化 它具備針對性 函數中的一種

分析事物時 發現具體事物一出現 就具有了一些特徵 那就將這些特徵定義到構造函數內

2> 特色

a. 該函數的名稱和所在類的名稱相同

b. 不須要定義返回值類型

c. 該函數沒有具體的返回值 

3> 注意

a. 全部對象建立時 都須要初始化纔可使用

b. 一個類在定義時 若是沒有定義過構造函數 那麼該類中會自動生成一個空參數的構造函數 若是在類中自定義了構造函數 那麼默認的構造函數就沒有了

c. 一個類中 能夠有多個構造函數 由於它們的函數名稱都相同 因此只能經過參數列表來區分 因此 一個類中若是出現多個構造函數 它們的存在是以重載體現的

10. 構造函數和通常函數的區別

1> 兩個函數定義格式不一樣

2> 構造函數是在對象建立時 就被調用 用於初始化 並且初始化動做只執行一次, 通常函數 是對象建立後 須要調用才執行 能夠被調用屢次

11. 構造代碼塊和構造函數的區別

構造代碼塊: 是給全部的對象進行初始化 也就是說 全部的對象都會調用一個代碼塊 只要對象一創建 就會調用這個代碼塊

構造函數: 是給與之對應的對象進行初始化 它具備針對性

12. 建立一個對象時的內存變化 (Person p = new Person();)

1> 先將硬盤上指定位置的Person.class文件加載進內存 

2> 執行main方法時 在棧內存中開闢了main方法的空間(壓棧-進棧) 而後在main方法的棧區分配了一個變量p

3> 在堆內存中開闢一個實體空間 分配了一個內存首地址值 ---> new

4> 在該實體空間中進行屬性的空間分配 並進行了默認初始化

5> 對空間中的屬性進行顯示初始化

6> 進行實體的構造代碼塊初始化

7> 調用該實體對應的構造函數 進行構造函數初始化 ---> ()

8> 將首地址賦值給p p變量就引用了該實體 ---> (指向了該對象)

 

封裝(面向對象特徵之一)

是指隱藏對象的屬性和實現細節 僅對外提供公共訪問方式

好處: 將變化隔離 便於使用 提升重用性 安全性

封裝原則: 將不須要對外提供的內容都隱藏起來 把屬性都隱藏 提供公共方法對其訪問

1. this

1> 表明對象 就是所在函數所屬對象的引用

2> 哪一個對象調用了this所在的函數 this就表明哪一個對象 就是哪一個對象的引用

3> 在定義功能時 若是該功能內部使用到了調用該功能的對象 這時就用this來表示這個對象

4> this 還能夠用於構造函數間的調用

調用格式: this(實際參數);

this對象後面跟上 . 調用的是成員屬性和成員方法(通常方法)

this對象後面跟上 () 調用的是本類中的對應參數的構造函數

注意: this調用構造函數 必須定義在構造函數的第一行 由於構造函數是用於初始化的 因此初始化動做必定要執行 不然編譯失敗

2. static

關鍵字 是一個修飾符 用於修飾成員(成員變量和成員函數)

1> 特色

a. 想要實現對象中的共性數據的對象共享 能夠將這個數據進行靜態修飾

b. 被靜態修飾的成員 能夠直接被類名所調用 也就是說 靜態的成員多了一種調用方式 類名.靜態方式

c. 靜態隨着類的加載而加載 並且優先於對象存在 

2> 弊端

a. 有些數據是對象特有的數據 是不能夠被靜態修飾的 由於 特有數據會變成對象的共享數據 這樣對事物的描述就出了問題 因此 在定義靜態時 必需要明確 這個數據是不是被對象所共享的

b. 靜態方法只能訪問靜態成員 不能夠訪問非靜態成員 由於靜態方法加載時 優先於對象存在 因此沒有辦法訪問對象中的成員

c. 靜態方法中不能使用this super關鍵字 由於this表明對象 而靜態在時 有可能沒有對象 因此this沒法使用

d. 主函數是靜態的 

3. 何時定義靜態成員?

1> 成員變量 (數據共享時靜態化)

該成員變量的數據是不是全部對象都同樣

若是是 那麼該變量須要被靜態修飾 由於是共享的數據

若是不是 那麼就說這是對象的特有數據 要存儲到對象中

2> 成員函數 (方法中沒有調用特有數據時就定義成靜態)

若是判斷成員函數是否須要被靜態修飾呢?

只要參考 該函數內是否訪問了對象中的特有數據

若是有訪問特有數據 那方法不能被靜態修飾

若是沒有訪問過特有數據 那麼這個方法須要被靜態修飾

4. 成員變量和靜態變量的區別

1> 成員變量所屬於對象 因此也稱爲實例變量

靜態變量所屬於類 因此也稱爲類變量

2> 成員變量存在於堆內存中

靜態變量存在於方法區中

3> 成員變量隨着對象建立而存在 隨着對象被回收而消失

靜態變量隨着類的加載而存在 隨着類的消失而消失

4> 成員變量只能被對象所調用

靜態變量能夠被對象調用 也能夠被類名調用

因此 成員變量能夠稱爲對象的特有數據 靜態變量稱爲對象的共享數據 

5. 靜態的注意

靜態的生命週期很長

6. 靜態代碼塊

就是一個有靜態關鍵字標示的一個代碼塊區域 定義在類中

做用: 能夠完成類的初始化 靜態代碼塊隨着類的加載而執行 並且只執行一次(new 多個對象就只執行一次) 若是和主函數在同一類中 優先於主函數執行

7. 主函數分析

public: 訪問權限最大

static: 不須要對象 直接類名便可

void: 主函數沒有返回值

main: 主函數特定的名稱

(String[] args): 主函數的參數 是一個字符串數組類型的參數 jvm調用main方法時 傳遞的實際參數是 new String[0]

jvm默認傳遞的是長度爲0的字符串數組 咱們在運行該類時 也能夠指定具體的參數進行傳遞 能夠在控制檯 運行該類時 在後面加入參數 參數之間經過空格隔開 jvm會自動將這些字符串參數做爲args數組中的元素 進行存儲

8. 靜態代碼塊 構造代碼塊 構造函數同時存在時的執行順序

靜態代碼塊 ---> 構造代碼塊 ---> 構造函數

9. 生成Java幫助文檔

命令格式: javadoc –d 文件夾名 –auther –version *.java

/**

 類描述

 @author 做者名

 @version 版本號

 */

/**

 方法描述

 @param 參數描述

 @return 返回值描述

 */

10. 設計模式

java中有23種設計模式

解決問題最行之有效的思想 是一套被反覆使用, 多數人知曉的, 通過分類編目的, 代碼設計經驗的總結 使用設計模式是爲了可重用代碼 讓代碼更容易被他人理解 保證代碼可靠性

11. 單例設計模式

解決的問題: 保證一個類在內存中的對象惟一性

Runtime()方法就是單例設計模式進行設計的 

1> 思想

a. 不讓其餘程序建立該類對象

b. 在本類中建立一個本類對象

c. 對外提供方法 讓其餘程序獲取這個對象

2> 步驟

a. 由於建立對象都須要構造函數初始化 只要將本類中的構造函數私有化 其餘程序就沒法再建立該類對象

b. 就在類中建立一個本類的對象

c. 定義一個方法 返回該對象 讓其餘程序能夠經過方法就獲得本類對象 (做用: 可控)

3> 代碼體現

a. 私有化構造函數

b. 建立私有並靜態的本類對象

c. 定義公有並靜態的方法 返回該對象

4> 餓漢式

class Single {
    private Single() {} //私有化構造函數
    private static Single s = new Single(); //建立私有並靜態的本類對象
    public static Single getInstance() { //定義公有並靜態的方法 返回該對象
        return s;
    }
} 

5> 懶漢式 延遲加載方法

class Single2 {
    private Single2() {}
    private static Single2 s;
    public static synchronized Single2 getInstance() {
        if(s==null)
            s = new Single2();
        return s;
    }
} 

6> 第三種格式

class Single {
    private Single() {}
    public static final Single s = new Single(); //final是最終的意思 被final修飾的變量不能夠被更改
}

 

繼承(面向對象特徵之一)

Java只支持單繼承 不支持多繼承 可是Java支持多重繼承

單繼承: 一個類只能有一個父類

多繼承: 一個類能夠有多個父類

多重繼承: A繼承B B繼承C C繼承D

1. 好處

1> 提升了代碼的複用性

2> 讓類與類之間產生了關係 提供了另外一個特徵多態的前提

2. 父類的由來

實際上是由多個類不斷向上抽取共性內容而來的

java中對於繼承 java只支持單繼承 java雖然不直接支持多繼承 可是保留了這種多繼承機制 進行改良

3. 子父類出現後 類中成員的特色

1> 成員變量

當子父類中出現同樣的屬性時 子類類型的對象 調用該屬性 值是子類的屬性值

若是想要調用父類中的屬性值 須要使用一個關鍵字 super

this: 表明是本類類型的對象引用

super: 表明是子類所屬的父類中的內存空間引用

注意: 子父類中一般是不會出現同名成員變量的 由於父類中只要定義了 子類就不用在定義了 直接繼承過來用就能夠了

2> 成員函數

當子父類中出現瞭如出一轍的方法時 創建子類對象會運行子類中的方法 好像父類中的方法被覆蓋掉同樣 這種狀況 是函數的另外一個特性: 覆蓋(複寫 重寫)

當一個類的功能內容須要修改時 能夠經過覆蓋來實現

3> 構造函數

發現子類構造函數運行時 先運行了父類的構造函數

緣由: 子類的全部構造函數中的第一行 其實都有一條隱身的語句super();

super(); 表示父類的構造函數 並會調用於參數相對應的父類中的構造函數 super();是在調用父類中空參數的構造函數

爲何子類對象初始化時 都須要調用父類中的函數? (爲何要在子類構造函數的第一行加入這個super();)

由於子類繼承父類 會繼承到父類中的數據 因此必需要看父類是如何對本身的數據進行初始化的 因此子類在進行對象初始化時 先調用父類的構造函數 這就是子類的實例化過程

4> 注意

a. 子類中全部的構造函數都會默認訪問父類中的空參數的構造函數 由於每個子類構造內第一行都有默認的語句super();

若是父類中沒有空參數的構造函數 那麼子類的構造函數內 必須經過super語句指定要訪問的父類中的構造函數

若是子類構造函數中用this來指定調用子類本身的構造函數 那麼被調用的構造函數也同樣會訪問父類中的構造函數

b. super(); this(); 兩個語句只能有一個定義在第一行 因此只能出現其中一個

c. super(); 或者 this(); 必定要定義在第一行 由於super();或者this();都是調用構造函數 構造函數用於初始化 因此初始化的動做要先完成 

4. 繼承的細節

1> 何時使用繼承呢?

當類與類之間存在着所屬關係時 才具有了繼承的前提 ab中的一種 a繼承b 狼是犬科中的一種

英文書中 所屬關係: " is a "

注意: 不要僅僅爲了獲取其餘類中的已有成員進行繼承

因此判斷所屬關係 能夠簡單看 若是繼承後 被繼承的類中的功能 均可以被該子類所具有 那麼繼承成立 若是不是 不能夠繼承

2> 在方法覆蓋時 注意兩點

a. 子類覆蓋父類時 必需要保證 子類方法的權限必須大於等於父類方法權限能夠實現繼承 不然 編譯失敗

b. 覆蓋時 要麼都靜態 要麼都不靜態 (靜態只能覆蓋靜態 或者被靜態覆蓋)

繼承的一個弊端: 打破了封裝性 對於一些類 或者類中功能 是須要被繼承 或者複寫的

可使用關鍵字 final(最終) 解決這個問題

5. final

1> 這個關鍵字是一個修飾符 能夠修飾類, 方法, 變量

2> final修飾的類是一個最終類 不能夠被繼承

3> final修飾的方法是一個最終方法 不能夠被覆蓋

4> final修飾的變量是一個常量 只能賦值一次

不加final修飾也可使用 那麼這個值是一個變量 是能夠更改的, 加了final 程序更爲嚴謹 常量名稱定義時 有規範 全部字母都大寫 若是由多個單詞組成 中間用 _ 鏈接 

6. 抽象類 abstract

抽象: 不具體 看不明白 抽象類表象體現

在不斷抽取過程當中 將共性內容中的方法聲明抽取 可是方法不同 沒有抽取 這時抽取到的方法 並不具體 須要被指定關鍵字abstract所標示 聲明爲抽象方法

抽象方法所在類必定要標示爲抽象類 也就是說該類須要被abstract關鍵字所修飾

1> 抽象類的特色

a. 抽象方法只能定義在抽象類中 抽象類和抽象方法必須由abstract關鍵字修飾(能夠描述類和方法 不能夠描述變量)

b. 抽象方法只定義方法聲明 並不定義方法實現

c. 抽象類不能夠被建立對象(實例化)

d. 只有經過子類繼承抽象類並覆蓋了抽象類中的全部抽象方法後 該子類才能夠實例化 不然 該子類仍是一個抽象類

2> 抽象類的細節

a. 抽象類中有構造函數 用於給子類對象進行初始化

b. 抽象類中能夠定義非抽象方法 抽象類和通常類沒有太大的區別 都是在描述事物

c. 抽象關鍵字abstract final, private, static 不能夠共存

d. 抽象類中能夠不定義抽象方法 抽象方法目的僅僅爲了避免讓該類建立對象

3> 模板方法設計模式

解決的問題: 當功能內部一部分實現時肯定 一部分實現是不肯定的 這時能夠把不肯定的部分暴露出去 讓子類去實現

abstract class GetTime {
    public final void getTime() { //此功能若是不須要複寫 可加final限定
        long start = System.currentTimeMillis();
        code(); //不肯定的功能部分 提取出來 經過抽象方法實現
        long end = System.currentTimeMillis();
        System.out.println("毫秒是:"+(end-start));
    }
    public abstract void code(); //抽象不肯定的功能 讓子類複寫實現
}

class SubDemo extends GetTime {
    public void code() { //子類複寫功能方法
        for(int y=0; y<1000; y++) {
            System.out.println("y");
        }
    }
}

7. 接口 interface

1> 是用關鍵字interface定義的

2> 接口中包含的成員 最多見的有全局常量, 抽象方法

注意: 接口中的成員都有固定的修飾符

成員變量: public static final

成員方法: public abstract

interface Inter{

    public static final int x = 3;

    public abstract void show();

}

3> 接口中有抽象方法 說明接口不能夠實例化 接口的子類必須實現了接口中全部的抽象方法後 該子類才能夠實例化 不然 該子類仍是一個抽象類

4> 類與類之間存在着繼承關係 類與接口中間存在的是實現關係 繼承用extends 實現用implements

5> 接口和類不同的地方 就是 接口能夠被多實現 這就是多繼承改良後的結果 java將多繼承機制經過多現實來體現

6> 一個類在繼承另外一個類的同時 還能夠實現多個接口 因此接口的出現避免了單繼承的侷限性 還能夠將類進行功能的擴展

7> 其實java中是有多繼承的 接口與接口之間存在着繼承關係 接口能夠多繼承接口

8> 接口都用於設計上 設計上的特色 (能夠理解主板上提供的接口)

a. 接口是對外提供的規則

b. 接口是功能的擴展

c. 接口的出現下降了耦合性

8. 抽象類和接口

抽象類: 通常用於描述一個體系單元 將一組共性內容進行抽取 特色: 能夠在類中定義抽象內容讓子類實現 能夠定義非抽象內容讓子類直接使用 它裏面定義的都是一些體系中的基本內容

接口: 通常用於定義對象的擴展功能 是在繼承以外還需這個對象具有的一些功能

抽象類和接口的共性: 都是不斷向上抽取的結果

抽象類和接口的區別:

1> 抽象類只能被繼承 並且只能單繼承

接口須要被實現 並且能夠多實現

2> 抽象類中能夠定義非抽象方法 子類能夠直接繼承使用

接口中都有抽象方法 須要子類去實現

3> 抽象類使用的是 is a 關係

接口使用的 like a 關係

4> 抽象類的成員修飾符能夠自定義

接口中的成員修飾符是固定的 全都是public

 

多態(面向對象特徵之一)

函數自己就具有多態性 某一種事物有不一樣的具體的體現 

1. 體現

父類引用或者接口的引用指向了本身的子類對象 

2. 多態的好處

提升了程序的擴展性

3. 多態的弊端

當父類引用指向子類對象時 雖然提升了擴展性 可是隻能訪問父類中具有的方法 不能夠訪問子類中特有的方法 (前期不能使用後期產生的功能 即訪問的侷限性)

4. 多態的前提

1> 必需要有關係 好比繼承 或者實現

2> 一般會有覆蓋操做 

5. 多態的出現 思想上的變化

之前是建立對象並指揮對象作事情 有了多態之後 咱們能夠找到對象的共性類型 直接操做共性類型作事情便可 這樣能夠指揮一批對象作事情 即經過操做父類或接口實現

class 黃大仙 {
    void 講課() {
        System.out.println("企業管理");
    }
    void 釣魚() {
        System.out.println("釣魚");
    }
}
 
class 黃禕a extends 黃大仙 {
    void 講課() {
        System.out.println("島國文化");
    }
    void 看電影() {
        System.out.println("看電影");
    }
}

class {
    public static void main(String[] args) {
        黃大仙 x = new 黃禕a(); //黃禕a對象被提高爲了黃大仙類型
        //x.講課(); //島國文化
        //x.看電影(); //錯誤
        黃禕a y = (黃禕a)x; //將黃大仙類型強制轉換成黃禕a類型
        y.看電影(); //在多態中 自始自終都是子類對象在作着類型的變化
    }
}

若是想用子類對象的特有方法 如何判斷對象是哪一個具體的子類類型呢?

能夠能夠經過一個關鍵字 instanceof //判斷對象是否實現了指定的接口或繼承了指定的類

格式: <對象 instanceof 類型> 判斷一個對象是否所屬於指定的類型

Student instanceof Person = true; //student繼承了person 

6. 多態在子父類中的成員上的體現的特色

1> 成員變量: 在多態中 子父類成員變量同名

在編譯時期: 參考的是引用型變量所屬的類中是否有調用的成員 (編譯時不產生對象 只檢查語法錯誤)

運行時期: 也是參考引用型變量所屬的類中是否有調用的成員

簡單一句話: 不管編譯和運行 成員變量參考的都是引用變量所屬的類中的成員變量

更簡單: 成員變量 --- 編譯運行都看 = 左邊

2> 成員函數

編譯時期: 參考引用型變量所屬的類中是否有調用的方法

運行事情: 參考的是對象所屬的類中是否有調用的方法

由於在子父類中 對於如出一轍的成員函數 有一個特性: 覆蓋

簡單一句: 成員函數 編譯看引用型變量所屬的類 運行看對象所屬的類

更簡單: 成員函數 --- 編譯看 = 左邊, 運行看 = 右邊

3> 靜態函數

編譯時期: 參考的是引用型變量所屬的類中是否有調用的成員

運行時期: 也是參考引用型變量所屬的類中是否有調用的成員

由於靜態方法 其實不所屬於對象 而是所屬於該方法所在的類

簡單一句: 調用靜態的方法引用是哪一個類的引用調用的就是哪一個類中的靜態方法

更簡單: 靜態函數 --- 編譯運行都看 = 左邊

相關文章
相關標籤/搜索