1. 程式人生 > 其它 >面向物件-2

面向物件-2

11.許可權修飾符

許可權修飾符是用來控制一個成員能夠被訪問的範圍的
可以修飾成員變數,方法,構造器,內部類,不同許可權修飾符修飾的成員能夠被訪問的範圍將受到限制
四種許可權修飾符作用範圍從小到大(private > 預設 > protected > public)

修飾符 同一個類中 同一個包中其他類 不同包下的子類 不同包下的無關類
private
預設
protected
public

12.final關鍵字

final的作用

  • final關鍵字是最終的意思可修飾(方法,變數,類)
  • 修飾方法:表明該方法是最終方法,不能被重寫。
  • 修飾變數:表示該變數第一次賦值後,不能再次被賦值(有且僅能被賦值一次)
  • 修飾類:表明該類是最終類,不能被繼承

final修飾變數的注意點

  • final修飾的變數是基本型別,那麼變數儲存的資料值不能發生改變
  • final修飾的變數是引用型別,那麼變數儲存的地址值不能發生改變,但是地址指向的物件的內容是可以發生變化的

13.列舉

列舉的概述

  • 列舉是java中的一種特殊型別
  • 列舉的作用:是為了做資訊的標誌和資訊的分類

定義列舉的格式

修飾符 enum 列舉名稱{
  第一行都是羅列列舉類例項的名稱,建議全部大寫
}

列舉的特徵

  • 列舉類都是繼承了列舉型別:java.lang.Enum
  • 列舉都是最終類,不可以被繼承
  • 列舉類的構造器都是私有的,列舉類對外不能建立物件

選擇常量做資訊標誌和分類雖然可以實現可讀性,但是入參值不受約束,程式碼相對不夠嚴謹;列舉做資訊標誌和分類,程式碼可讀性好,入參約束嚴謹,程式碼優雅,是最好的資訊分類技術,建議使用

public enum Season {
    SPRING,SUMMER,AUTUMN,WINTER;
}

14.抽象類

抽象類概述

  • 某個父類知道其所有子類要完成某功能,但是每個子類完成的情況都不一樣,父類就只定義該功能的基本要求,具體實現由子類完成,這個類就可以是一個抽象類,抽象類其實就是一種不完全的設計圖

抽象類必須使用abstract修飾

  • 格式:修飾符 abstract class 類名{}

抽象方法

  • 抽象類中定義的子類必須完成的功能的基本要求
  • 沒有方法體,只有方法簽名,必須abstract修飾
  • 格式:修飾符 abstract 返回值型別 方法名稱(形參列表);

抽象類的使用總結與注意事項

  • 抽象類是用來被繼承的,抽象方法是交給子類重寫實現的
  • 一個類如果繼承了抽象類,那麼這個類必須重寫完抽象類的全部抽象方法,否則這個類也必須定義成抽象類

抽象類特徵

  • 有得有失:得到了抽象方法,失去了建立物件的能力
  • 類有的成員(成員變數、方法、構造器)抽象類都具備
  • 抽象類中不一定有抽象方法,有抽象方法的類一定是抽象類
  • 一個類繼承了抽象類必須重寫完抽象類的全部抽象方法,否則這個類也必須定義成抽象類
  • 不能用abstract修飾變數、程式碼塊、構造器
  • final和abstract是互斥關係

14.1模板方法模式

使用場景:當系統中出現同一個功能多處在開發,而該功能中大部分程式碼是一樣的,只有其中部分可能不同的時候

模板方法模式實現步驟

  • 把功能定義成一個所謂的模板方法,放在抽象類中,模板方法中只定義通用且能確定的程式碼
  • 模板方法中不能決定的功能定義成抽象方法讓具體子類去實現
  • 模板方法建議使用final關鍵字修飾,因為模板方法是讓子類直接使用,不是讓子類重寫的,一旦重寫,模板方法就無效了

模板方法的好處

  • 模板方法極大提高了程式碼的複用性
  • 模板方法已經定義了通用結構,模板不能確定的定義成抽象方法
  • 使用者只需關心自己需要實現的功能

15.介面

介面概述

  • 介面就是體現規範的,其中用抽象方法定義的一組行為規範,介面時更加徹底的抽象
  • 體現了現實世界中"如果你是這類事物…則必須完成某些行為…"的思想
    格式
介面用關鍵字interface來定義
public interface 介面名{
	//常量
	//抽象方法
}

jdk8之前介面中只能是抽象方法和常量,沒有其他成分,jdk8之後介面中可以定義方法,可以定義預設方法和靜態方法,預設方法必須要用default關鍵字修飾,且只有在介面被實現之後才能呼叫,靜態方法要用static關鍵字修飾,只能用介面名.方法名的形式來呼叫。
介面不能例項化(建立物件)
介面中的成員變數都是public修飾的,寫不寫都是,因為規範的目的是為了公開化

/**
 * 定義了預設方法和靜態方法的介面
 */
public interface InterNew {
    default void defaultMethod(){
        System.out.println("介面預設方法被執行~~");
    }
    static void staticMethod(){
        System.out.println("介面靜態方法被執行~~");
    }
}
/**
 * 介面的實現類
 */
public class InterNewImpl implements InterNew {
}
public class Demo {
    public static void main(String[] args) {
        InterNewImpl interNew = new InterNewImpl();
        //呼叫介面的預設方法
        interNew.defaultMethod();
        //呼叫介面的靜態方法
        InterNew.staticMethod();
    }
}

執行結果

介面的用法

  • 介面是用來被類實現(implements)的,實現介面的類被稱為實現類,實現類可以理解成所謂的子類

格式

修飾符 class 實現類 implements 介面1,介面2,介面3……{
}

介面可以被類單實現,也可以被類多實現
一個類實現介面,必須重寫完全部介面的全部抽象方法,否則這個類需要定義成抽象類。

介面和介面之間的關係

  • 類和類之間的關係是單繼承(一個類只能繼承一個父類),類和介面之間的關係是多實現(一個類可以實現多個介面)。
  • 介面和介面之間的關係是多繼承(一個介面可以同時繼承多個介面)。
    介面多繼承的作用:整合多個介面為同一個介面,便於子類實現。

介面的注意事項

  • 介面不能建立物件
  • 一個類實現多個介面,多個介面中有同樣的靜態方法不衝突
  • 一個類繼承了父類,同時又實現了介面,父類和介面中有同名方法,預設呼叫父類的
  • 一個類實現了多個介面,多個介面中存在同名的預設方法,不衝突,這個類重寫該方法即可

16.多型

同類型的物件,執行同一個行為,會表現出不同的行為特徵

多型的常見形式

  • 父類型別 物件名稱 = new 子類構造器;
  • 介面 物件名稱 = new 實現類構造器;

多型成員訪問特點

  • 方法呼叫:編譯看左邊,執行看右邊
  • 變數呼叫:編譯看左邊,執行也看左邊(多型側重行為多型)

多型的實現前提

  • 有繼承/實現關係;有父類引用指向子類物件;有方法重寫

優勢

  • 在多型形式下,右邊物件可以實現解耦合,便於擴充套件和維護
  • 定義方法的時候,使用父類作為引數,該方法就可以接收這父類的一切子類物件,體現出多型的擴充套件性與便利
public abstract class Shape {
    public String name = "形狀";
    public abstract void area();
}
public class Circle extends Shape{
    public String name = "圓形";
    @Override
    public void area() {
        System.out.println("面積為Πr^2");
    }
}
public class Rectangle extends Shape{
    public String name = "矩形";
    @Override
    public void area() {
        System.out.println("面積為長乘寬");
    }
}
public class Test {
    public static void main(String[] args) {
        //多型的形式  父類型別 物件名稱 = new 子類構造器
        Shape s1 = new Circle();
        System.out.println(s1);//變數:編譯看左邊,執行看右邊
        s1.area();//方法:編譯看左邊,執行也看左邊

        Shape s2 = new Rectangle();
        System.out.println(s2);
        s2.area();
    }
}

執行結果

public class Test2 {
    public static void main(String[] args) {
        Circle c = new Circle();
        calc(c);

        Rectangle r = new Rectangle();
        calc(r);
    }
    public static void calc(Shape s){
        s.area();
    }
}

執行結果

弊端

  • 但是多型情況下不能使用子類的獨有功能(可以使用型別轉換)

自動型別轉換(從子到父):子類物件賦值給父類型別的變數指向
強制型別轉換(從父到子):

  • 子類 物件變數 = (子類)父類型別的變數
  • 作用:可以解決多型下的劣勢,可以實現呼叫子類獨有的功能
  • 如果轉型後的型別和物件真實型別不是同一種類型,那麼執行的時候會報異常
  • 轉換前使用instanceof判斷當前物件的真實型別,再進行強制轉換
  • 變數名 instanceof 類名;
  • 判斷關鍵字左邊的變數指向的物件的真實型別,是否為右邊的型別或其子型別,是則返回true

17.內部類

內部類就是定義在一個類裡面的類,裡面的類可以理解成寄生,外部類可以理解成宿主

public class People {
    //內部類
    public class heart {}
}

內部類的使用場景、作用

  • 當一個事物的內部,還有一個部分需要完整的結構進行描述,而這個內部的完整結構又只為外部事物提供服務,那麼整個內部的完整結構可以選擇內部類來設計
  • 內部類通常可以方便訪問外部成員,包括私有的成員
  • 內部類提供了更好的封裝性,內部類本身就可以用private protected等修飾,封裝性可以做到更多控制

內部類分類

  • 靜態內部類
  • 成員內部類
  • 區域性內部類
  • 匿名內部類

17.1靜態內部類

有static修飾,屬於外部類本身

它的特點和使用與普通類是完全一樣的,類有的成分都有,只是在別的類裡面

public class Outer {
    //靜態成員內部類
    public static class inner{
       
    }
}

靜態內部類建立物件的格式

public class Test {
    public static void main(String[] args) {
        Outer.Inner in = new Outer.Inner();
    }
}

靜態內部類可以直接訪問外部類的靜態成員,不能直接訪問外部類的例項成員,必須用外部類的物件訪問

17.2成員內部類

無static修飾,屬於外部類的物件

public class Outer{
    //成員內部類
    public class Inner{
        
    }
}

成員內部類建立物件格式

格式:外部類名.內部類名 = new 外部類構造器.() new 內部類構造器();
範例:Outer.Inner in = new Outer().new Inner();

成員內部類中可以直接訪問外部類的靜態成員,例項方法中可以直接訪問外部類的例項成員

在成員內部類中訪問所在外部類物件 外部類名.this

17.3區域性內部類

區域性內部類放在方法、程式碼塊、構造器等執行體中

17.4匿名內部類

本質上是一個沒有名字的區域性內部類,定義在方法中、程式碼塊中

方便建立子類物件,最終目的是為了簡化程式碼編寫

new 類|抽象類名|介面名(){
    重寫方法
}
public class Test {
    public static void main(String[] args) {
        Animal a = new Animal() {
            @Override
            public void run() {
                System.out.println("動物在跑");
            }
        };
        a. run();
    }
}

abstract class Animal{
    public abstract void run();
}

執行結果

  • 匿名內部類是一個沒有名字的內部類
  • 匿名內部類寫出來就會產生一個匿名內部類的物件
  • 匿名內部類的物件型別相當於是當前new的那個型別的子型別