banner
Onei

Onei

github
nintendo switch
discord server
steam
pixiv
bento
follow

Java 之 面向物件

面向過程:側重分步驟,考慮完成該功能的過程(自己一步一步做)
側重分模塊(找人分發任務解決任務)

總結
面向對象優勢:可擴展,可維護,靈活性高,程序耦合度低
面向對象缺點:性能比面向過程相對較差

💪 方法特點#

  • 靜態方法用類名調用,構造方法創建實例化時對象調用,成員方法對象調用
  • 構造方法
    • 聲明:權限修飾符 方法名(參數列表){方法體}; 方法名和類名必須一致
    • 類中沒有構造方法,默認有一個無參構造,如果自己編寫了則默認的就沒有了,一般自己寫完構造方法會再寫一個無參
  • 只有成員方法才可以直接訪問成員屬性,靜態方法不能訪問成員變量(方法只要需要成員變量就定義為成員方法)
  • 成員方法可以訪問靜態變量

🎗 類和對象之間的關係#

  • 類:對事物客觀描述的標準
  • 對象:一切皆對象,符合類標準的具體個體

對象使用#

實例化對象:Student s1 = new Student();
通過 get 和 set 方法獲取和設置成員屬性

🔌 JavaBean#

JavaBean 是一種Java語言寫成的可重用組件,它是一個類(類必須是具體的公共的,並且具有無參構造器)

  • 私有化成員變量
  • 對外提供getset方法
  • 顯式聲明無參和全參構造
  • getset方法的作用
    • 保護成員變量
    • 進行攔截

🎉 實例化的內存過程#

  • 加載客戶端類
  • main()方法壓棧
  • 加載服務端類
  • 調用構造方法
  • 在堆內存中開辟空間,對實例化對象初始化
  • 構造方法出棧,實例化對象賦值給變量

💥 異常#

  • 編譯時異常
  • 運行時異常
    • 空指針異常(用null訪問成員變量時)
    • 陣列下標越界
    • 類型轉換異常

⚠️ 易錯點#

  • 區分成員方法和構造方法:看有無返回值(構造方法無返回值)
  • 對象可以調用靜態變量,javac編譯時會改成類名調用靜態變量(所以空指針也不影響)
  • 靜態方法不能調用成員變量

👈 this#

對象中第一個成員變量,保存了當前對象的內存地址(不能出現在靜態方法中)

作用#

  • 用在成員方法 / 構造方法中 區分同名的成員變量和局部變量
  • 重載調用當前類的有參構造方法
    必須在當前構造方法方法體第一行
  • 鏈式調用

⚙️ static#

修飾符 用來標註靜態屬性 如果沒有使用static為成員屬性

功能#

  • 靜態變量
  • 靜態方法
  • 靜態代碼塊
    不能調用 在程序加載時調用 (在main()方法之前運行) 只執行一次

代碼塊:無名稱方法 、自動調用

訪問一個類的靜態屬性時才會加載該類到內存中
實例語句塊可看作無名字成員方法

📦 封裝#

把所有組成部分組合到一起,還可以通過權限控制修飾符將數據隱藏起來,可以控制用戶對類數據的修改程度
適當的封裝可以讓代碼更容易理解,易於維護,更提高了代碼的安全性

導包#

放在 package 之下 class 之上
靜態導入
導入某個類的某個靜態變量

權限控制#

範圍publicprotecteddefaultprivate
同類✔️✔️✔️✔️
同包✔️✔️✔️
子類✔️✔️
全局✔️

🧬 繼承#

從一個已有的類中衍生出一個新的類。該類往往包含著父類的特徵,還可以新增特有的屬性

📝 重寫#

必須有繼承關係

  • 方法名、參數列表、返回值相同
  • 不能比原方法有更低的訪問權限
  • 不能比原方法有更寬泛的異常

重寫重載區別#

注解#

源碼注解
編譯注解
運行時注解

🛑 final#

可放置在

  • 變量
  • 方法

🌱 多態#

父類引用指向子類對象

  • 父類
  • 引用 指向的引用數據類型
  • 指向 可以找到誰
  • 子類對象 創建一個子類的實例化對象

使用父類創建的引用類型變量 可以找到子類對象
父類 變量名 = new 子類();

向上轉型(由子類轉換為父類) 類似於自動轉換類型

非成員方法

優點#

  • 降低耦合度
  • 擴展性 替換性 靈活性增強

缺點#

會丟失子類特有的屬性
成員方法 如果子類重寫了父類的成員方法則調用子類的成員屬性
非成員方法 調用父類方法

public class Poly {
    public static void main(String[] args) {
        Sup sub = new Sub();
        // 2
        System.out.println(sub.age);
        sub.m1();
        // Son m2
        sub.m2();
        // sub.m3();
    }
}
class Sup{
    int age = 2;
    public void m1(){
        System.out.println("Father m1");
    }
    public void m2(){
        System.out.println("Father m2");
    }
}
class Sub extends Sup{
    int age = 1;
    public void m2(){
        System.out.println("Son m2");
    }
    public void m3(){
        System.out.println("Son m3");
    }
} 

instanceof#

判斷某個對象是否由某個類實例化而來

向下轉型(由父類轉換為子類)

  • 直接多態
    父類 變量名 = new 子類();
  • 實參形參多態
  • 返回值多態
    方法返回值使用父類聲明

隱蔽多態#

通過子類對象,調用繼承父類的成員方法時 此時上下文環境為多態環境

public class Poly_05 {
    public static void main(String[] args) {
    // Sup sup = new Sub();
    // // 2 父類
    // System.out.println(sup.age);
    // // 父類 因為子類沒有
    // sup.m1();
    // // 子類 因為覆寫
    // sup.m2();
    // // 報錯,因為父類沒有,多態會丟失子類特有屬性
    // // sup.m3();
    // // 向下轉型
    // Sub sub = (Sub) sup;
    // // 1 子類
    // System.out.println(sub.age);
    // // 父類 繼承
    // sub.m1();
    // // 子類 因為子類有
    // sub.m2();
    // // 子類,又沒有使用多態
    // sub.m3();

    Sub sub = new Sub();
    sub.m1();
    }
}

class Sup {
    int age = 2;
    public void m1() {
    /**
     * this : 是對象中第一個成員變量,保存當前對象的內存地址
     * 
     * this既然保存當前對象內存地址,那麼this的類型 可以是當前類類型,可以是父類類型
     * 
     * this寫在哪個類中,哪個類就是當前類 所以 當前類 是Sup 父類 是 Object
     * 
     * 因為this能調用當前類中所有的屬性,並沒有丟失,所以this是Sup 當前類類型
     * 
     * Sup this;
     * 
     * this : 哪個對象調用這個成員方法,this就指向誰
     * 
     * 最終是Sub調用的m1方法,所以this 指向 Sub
     * 
     * Sup this = Sub;
     */
    
    // System.out.println("父類m1");
    System.out.println(this);
    // 2 父類
    System.out.println(this.age);
    System.out.println(this.sakjdkashdhqwrjnfaksf);
    System.out.println(age);
    // 子類
    m2();
    // 報錯
    // m3();
    }

    public void m2() {
    System.out.println("父類m2");
    }
}

class Sub extends Sup {
    int age = 1;

    public void m2() {
    System.out.println("子類m2");
    }

    public void m3() {
    System.out.println("子類m3");
    }
}

🐘 抽象#

abstract修飾符 用來修飾抽象類和抽象方法

abstract 修飾的類是抽象類,並且抽象類不能創建對象而且抽象類一般主要用於被繼承
abstract 修飾的方法是抽象方法。該方法沒有方法體,不實現功能,用於讓不同的子類實現方法
抽象方法必須在抽象類中,而抽象類中可以存在普通方法
抽象類中可看作特殊的類,只不過不能創建對象而已
abstractfinal不能同時出現

  • 子類如果繼承了抽象類 那麼需要實現所有的抽象方法 否則該子類就需要使用 abstract 修飾
  • 抽象類繼承抽象類,需要實現 0~N 個抽象方法
  • 普通類繼承抽象類需要實現所有方法

👄 接口#

interface 關鍵字

1.8 之前接口是完全抽象的,只允許出現抽象方法和常量 (psf)
在接口中只有常量沒有變量,並且psf可以省略 且權限控制默認是public
抽象方法的 abstract 可以省略

interface A{
  int age = 1;

  // 默認方法
  default void dmethod(){
    System.out.println("默認方法");
  }
}
class B{
  void m(){
    System.out.println(A.age);
  }
}

🌌 Object#

Object是 Java 提供的根類 所有類都直接或間接繼承Object
java.lang.Objectjava.lang包下 核心包下的所有類不需要導入

toString#

equals#

== 基本類型比較值大小,引用類型比較地址
==equal() 的默認底層實現
默認的 equals() 比較地址

finalize#

JVM 跨平台 多線程 面向對象 自動垃圾回收
垃圾 沒有任何引用指向該對象的時候,該對象成為垃圾對象
垃圾被回收時 自動調用該對象的 finalize() 方法 是在對象生命結束時候被調用
System.gc() 程序員可以建議 JVM 進行垃圾回收

🔗 類之間關係#

類與類之間的關係詳見 這裡

🧩 內部類#

成員內部類#

class A{
  class B{

  }
}

等同於成員變量 不能有靜態聲明
內部類可以使用權限控制修飾符
可以訪問外部類的私有化 (被 private 修飾) 屬性
成員內部類可以直接訪問外部類的所有數據
此時 B 類的全類名為 A$B

靜態內部類#

class A{
  private int a = 1;
  private static int b = 1;
  static class B{
    int c = 1;
    static int d = 1;
    public void method(){
      // System.out.print(a);
      A aaa = new A();
      System.out.print(aaa.a);
      System.out.print(b);
    }
  }
}
  • 靜態內部類可以等同看作靜態變量
  • 靜態內部類無法直接訪問外部類的的成員屬性
  • 靜態內部類可以聲明任何數據 (靜態 / 成員)
  • 創建外部類的對象後可訪問外部類的的成員屬性

局部內部類#

  • 方法中的類是局部內部類
  • 局部內部類可看作局部變量
  • 如果通過局部內部類訪問外部方法中的局部變量的時候,該變量需要加final修飾 1.8 後final可以省略
  • 局部內部類不能使用權限修飾符
  • 局部內部類不能有靜態聲明
class A{
  void method(){
    class B{

    }
  }
}

此時B類的全類名為 A$1B
如果內部類名重複 則為外部類類名 $2 內部類類名

匿名內部類#

當一個方法的參數需要傳入一個類對象時,可以使用匿名內部類

語法#

new 實現接口(){
  //匿名內部類類體部分
}

實現接口 接口沒有構造函數所以為空參數

new 父類構造器(實參列表){
  //匿名內部類類體部分
}

調用父類構造器可以為空參數,也可以傳入參數

示例#

//接口部分
interface Product{
  public double getPrice();
  public String  getName();
}

public class Anonymous{
  public void test (Product p){
      System.out.println(p.getName()+"--------"+p.getPrice());
  }
  public static void main(String[] args ){
    Anonymous as = new Anonymous();
    //此處實現接口並實現抽象方法
    as.test(new Product(){
      //實現方法
      public double getPrice( ){
        return 8888;
      }
      //實現方法
      public String getName(){
        return "I can do it ";
      }
    });
  }
}

上面代碼很簡單,就是定義了一個類Anonymous,在類裡定義了一個test方法。然後就是創建 Anonymous 對象,調用他的實例方法 test ()
不過調用test()方法時,要傳入一個Product對象。但是由於Product是一個接口,無法創建對象,所以要實現該接口。因此此處採用匿名內部類的方式進行,並實現接口中全部的抽象方法

作用#

無需通過實現接口或者繼承抽象類的方式來實現。但是使用匿名內部類的優點是顯而易見的,可以少些代碼,而且代碼更加簡潔

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。