02.Java物件導向問題

瀟湘劍雨發表於2018-12-24

目錄介紹

  • 2.0.0.1 過載和重寫的區別?過載和重寫繫結機制有何區別?父類的靜態方法能否被子類重寫?
  • 2.0.0.2 封裝、繼承、多型分別是什麼?
  • 2.0.0.3 介面和抽象類的區別是什麼?介面的意義是什麼?抽象類的意義是什麼?如何選擇抽象類和介面?
  • 2.0.0.4 什麼是內部類,有哪些?有什麼作用?靜態內部類和非靜態內部類的區別?
  • 2.0.0.5 為什麼內部類呼叫的外部變數必須是final修飾的?
  • 2.0.0.6 Java實現多型有哪些必要條件?具體怎麼實現?多型的實現原理?多型的作用?
  • 2.0.0.7 什麼是多型?多型的實現方式有哪些?多型有哪些弊端?
  • 2.0.0.9 靜態變數和成員變數的區別?程式碼塊有哪些?構造程式碼塊和構造方法哪一個先執行?
  • 2.0.1.0 抽象類具有什麼特點?抽象類和普通類有何區別?抽象類可以new嗎?會出現什麼問題?

好訊息

  • 部落格筆記大彙總【15年10月到至今】,包括Java基礎及深入知識點,Android技術部落格,Python學習筆記等等,還包括平時開發中遇到的bug彙總,當然也在工作之餘收集了大量的面試題,長期更新維護並且修正,持續完善……開源的檔案是markdown格式的!同時也開源了生活部落格,從12年起,積累共計500篇[近100萬字],將會陸續發表到網上,轉載請註明出處,謝謝!
  • 連結地址:https://github.com/yangchong211/YCBlogs
  • 如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起於忽微,量變引起質變!所有部落格將陸續開源到GitHub!

2.0.0.1 過載和重寫的區別?過載和重寫繫結機制有何區別?父類的靜態方法能否被子類重寫?

  • 過載

    • 發生在同一個類中,方法名必須相同,引數型別不同、個數不同、順序不同,方法返回值和訪問修飾符可以不同,發生在編譯時。   
  • 重寫

    • 重寫表示子類重寫父類的方法
    • 發生在父子類中,方法名、引數列表必須相同,返回值範圍小於等於父類,丟擲的異常範圍小於等於父類,訪問修飾符範圍大於等於父類;如果父類方法訪問修飾符為 private 則子類就不能重寫該方法。
  • 過載和重寫繫結機制有何區別?

    • 過載:類內多型,靜態繫結機制(編譯時已經知道具體執行哪個方法),方法同名,引數不同
    • 重寫:類間多型,動態繫結機制(執行時確定),例項方法,兩小兩同一大(方法簽名相同,子類的方法所丟擲的異常、返回值的範圍不大於父類的對應方法,子類的方法可見性不小於父類的對應方法)方法簽名相同,子類的方法所丟擲的異常、返回值的範圍不大於父類的對應方法,子類的方法可見性不小於父類的對應方法
  • 父類的靜態方法能否被子類重寫

    • 父類的靜態方法是不能被子類重寫的,其實重寫只能適用於例項方法,不能用於靜態方法,對於上面這種靜態方法而言,我們應該稱之為隱藏。
    • 技術部落格大總結
    • Java靜態方法形式上可以重寫,但從本質上來說不是Java的重寫。因為靜態方法只與類相關,不與具體實現相關。宣告的是什麼類,則引用相應類的靜態方法(本來靜態無需宣告,可以直接引用)。並且static方法不是後期繫結的,它在編譯期就繫結了。換句話說,這個方法不會進行多型的判斷,只與宣告的類有關。

2.0.0.2 物件導向程式設計的四大特性及其含義?封裝、繼承、多型分別是什麼?

  • 封裝

    • 將某事物的屬性和行為包裝到物件中,構成一個不可分割的獨立實體。
    • 封裝把一個物件的屬性私有化,同時提供一些可以被外界訪問的屬性的方法,如果屬性不想被外界訪問,我們大可不必提供方法給外界訪問。但是如果一個類沒有提供給外界訪問的方法,那麼這個類也沒有什麼意義了。
  • 繼承

    • 繼承是使用已存在的類的定義作為基礎建立新類的技術,新類的定義可以增加新的資料或新的功能,也可以用父類的功能,但不能選擇性地繼承父類。通過使用繼承我們能夠非常方便地複用以前的程式碼。
    • 注意

      • 子類擁有父類非 private 的屬性和方法。
      • 子類可以擁有自己屬性和方法,即子類可以對父類進行擴充套件。
      • 子類可以用自己的方式實現父類的方法。
  • 多型

    • 所謂多型就是指程式中定義的引用變數所指向的具體型別和通過該引用變數發出的方法呼叫在程式設計時並不確定,而是在程式執行期間才確定,即一個引用變數倒底會指向哪個類的例項物件,該引用變數發出的方法呼叫到底是哪個類中實現的方法,必須在由程式執行期間才能決定。
    • 在Java中有兩種形式可以實現多型:繼承(多個子類對同一方法的重寫)和介面(實現介面並覆蓋介面中同一方法)。
  • 抽象

    • 對現實世界的事物進行概括,抽象為在計算機虛擬世界中有意義的實體

2.0.0.3 介面和抽象類的區別是什麼?介面的意義是什麼?抽象類的意義是什麼?如何選擇抽象類和介面?

  • 介面和抽象類的區別是什麼

    • 介面的方法預設是 public,所有方法在介面中不能有實現(Java 8 開始介面方法可以有預設實現),抽象類可以有非抽象的方法
    • 介面中的例項變數預設是 final 型別的,而抽象類中則不一定
    • 一個類可以實現多個介面,但最多隻能實現一個抽象類
    • 一個類實現介面的話要實現介面的所有方法,而抽象類不一定
    • 介面不能用 new 例項化,但可以宣告,但是必須引用一個實現該介面的物件 從設計層面來說,抽象是對類的抽象,是一種模板設計,介面是行為的抽象,是一種行為的規範。
  • 介面的作用是什麼

    • 技術部落格大總結
    • 1、重要性:在Java語言中, abstract class 和interface 是支援抽象類定義的兩種機制。正是由於這兩種機制的存在,才賦予了Java強大的 物件導向能力。
    • 2、簡單、規範性:如果一個專案比較龐大,那麼就需要一個能理清所有業務的架構師來定義一些主要的介面,這些介面不僅告訴開發人員你需要實現那些業務,而且也將命名規範限制住了(防止一些開發人員隨便命名導致別的程式設計師無法看明白)。
    • 3、維護、擴充性:比如你要做一個畫板程式,其中裡面有一個皮膚類,主要負責繪畫功能,然後你就這樣定義了這個類。可是在不久將來,你突然發現這個類滿足不了你了,然後你又要重新設計這個類,更糟糕是你可能要放棄這個類,那麼其他地方可能有引用他,這樣修改起來很麻煩。
    • 如果你一開始定義一個介面,把繪製功能放在介面裡,然後定義類時實現這個介面,然後你只要用這個介面去引用實現它的類就行了,以後要換的話只不過是引用另一個類而已,這樣就達到維護、擴充的方便性。
    • 4、安全、嚴密性:介面是實現軟體鬆耦合的重要手段,它描敘了系統對外的所有服務,而不涉及任何具體的實現細節。這樣就比較安全、嚴密一些(一般軟體服務商考慮的比較多)。
  • 抽象類的意義是什麼

    • 1.因為抽象類不能例項化物件,所以必須要有子類來實現它之後才能使用。這樣就可以把一些具有相同屬性和方法的元件進行抽象,這樣更有利於程式碼和程式的維護。
    • 2.當又有一個具有相似的元件產生時,只需要實現該抽象類就可以獲得該抽象類的那些屬性和方法。
  • 如何選擇抽象類和介面?

    • 使用介面:

      • 需要讓不相關的類都實現一個方法,例如不相關的類都可以實現 Compareable 介面中的 compareTo() 方法;
      • 需要使用多重繼承。
    • 使用抽象類:

      • 需要在幾個相關的類中共享程式碼。
      • 需要能控制繼承來的成員的訪問許可權,而不是都為 public。
      • 需要繼承非靜態和非常量欄位。

2.0.0.4 什麼是內部類,有哪些?有什麼作用?靜態內部類和非靜態內部類的區別?

  • 什麼是內部類

    • 內部類就是定義在另外一個類裡面的類。它隱藏在外部類中,封裝性更強,不允許除外部類外的其他類訪問它;但它可直接訪問外部類的成員。
  • 內部類有哪些

    • 成員內部類:成員內部類是外圍類的一個成員,是依附於外圍類的,所以,只有先建立了外圍類物件才能夠建立內部類物件。也正是由於這個原因,成員內部類也不能含有 static 的變數和方法;
    • 靜態內部類:靜態內部類,就是修飾為static的內部類,該內部類物件不依賴於外部類物件,就是說我們可以直接建立內部類物件,但其只可以直接訪問外部類的所有靜態成員和靜態方法;
    • 區域性內部類:區域性內部類和成員內部類一樣被編譯,只是它的作用域發生了改變,它只能在該方法和屬性中被使用,出了該方法和屬性就會失效;
    • 匿名內部類:定義匿名內部類的前提是,內部類必須要繼承一個類或者實現介面,格式為 new 父類或者介面(){定義子類的內容(如函式等)}。也就是說,匿名內部類最終提供給我們的是一個 匿名子類的物件。
  • 靜態內部類和非靜態內部類的區別有:

    • 靜態內部類是指被宣告為static的內部類,可不依賴外部類例項化;而非靜態內部類需要通過生成外部類來間接生成。
    • 靜態內部類只能訪問外部類的靜態成員變數和靜態方法,而非靜態內部類由於持有對外部類的引用,可以訪問外部類的所用成員

2.0.0.5 為什麼內部類呼叫的外部變數必須是final修飾的?

  • 為什麼內部類呼叫的外部變數必須是final修飾的?

    • 簡單解答:一方面,由於方法中的區域性變數的生命週期很短,一旦方法結束變數就要被銷燬,為了保證在內部類中能找到外部區域性變數,通過final關鍵字可得到一個外部變數的引用;另一方面,通過final關鍵字也不會在內部類去做修改該變數的值,保護了資料的一致性。
    • 詳細一點可以這樣說:因為生命週期的原因。方法中的區域性變數,方法結束後這個變數就要釋放掉,final保證這個變數始終指向一個物件。首先,內部類和外部類其實是處於同一個級別,內部類不會因為定義在方法中就會隨著方法的執行完畢而跟隨者被銷燬。問題就來了,如果外部類的方法中的變數不定義final,那麼當外部類方法執行完畢的時候,這個區域性變數肯定也就被GC了,然而內部類的某個方法還沒有執行完,這個時候他所引用的外部變數已經找不到了。如果定義為final,java會將這個變數複製一份作為成員變數內建於內部類中,這樣的話,由於final所修飾的值始終無法改變,所以這個變數所指向的記憶體區域就不會變。為了解決:區域性變數的生命週期與區域性內部類的物件的生命週期的不一致性問題

2.0.0.7 什麼是多型?多型實現條件?多型的實現方式有哪些?

  • 什麼是多型?

    • 多型是指程式中定義的引用變數所指向的具體型別和通過該引用變數發出的方法呼叫在程式設計時並不確定,而是在程式執行期間才確定,即一個引用變數倒底會指向哪個類的例項物件,該引用變數發出的方法呼叫到底是哪個類中實現的方法,必須在由程式執行期間才能決定。因為在程式執行時才確定具體的類,這樣,不用修改源程式程式碼,就可以讓引用變數繫結到各種不同的類實現上,從而導致該引用呼叫的具體方法隨之改變,即不修改程式程式碼就可以改變程式執行時所繫結的具體程式碼,讓程式可以選擇多個執行狀態,這就是多型性。
  • 多型實現條件?

    • Java實現多型有三個必要條件:繼承、重寫、向上轉型。
    • 繼承:在多型中必須存在有繼承關係的子類和父類。
    • 重寫:子類對父類中某些方法進行重新定義,在呼叫這些方法時就會呼叫子類的方法。
    • 向上轉型:在多型中需要將子類的引用賦給父類物件,只有這樣該引用才能夠具備技能呼叫父類的方法和子類的方法。
  • 多型的實現方式有哪些?

    • 多型作用:多型性就是相同的訊息使得不同的類做出不同的響應。
    • 第一種實現方式:基於繼承實現的多型

      • 基於繼承的實現機制主要表現在父類和繼承該父類的一個或多個子類對某些方法的重寫,多個子類對同一方法的重寫可以表現出不同的行為。多型的表現就是不同的物件可以執行相同的行為,但是他們都需要通過自己的實現方式來執行,這就要得益於向上轉型了。
      public class MainJava {
          public static void main(String[] args) {
              //定義父類陣列
              Wine[] wines = new Wine[2];
              //定義兩個子類
              Test1 test1 = new Test1();
              Test2 test2 = new Test2();
              Wine win e = new Wine();
              //父類引用子類物件
              wines[0] = test1;
              wines[1] = test2;
              for(int i = 0 ; i < 2 ; i++){
                  System.out.println(wines[i].toString() + "--" + wines[i].drink());
              }
              System.out.println("-------------------------------");
              System.out.println(test1.toString() + "--" + test1.drink());
              System.out.println(test2.toString() + "--" + test2.drink());
          }
          public static class Wine {
              private String name;
              public String getName() {
                  return name;
              }
              public void setName(String name) {
                  this.name = name;
              }
              public String drink(){
                  return "喝的是 " + getName();
              }
              public String toString(){
                  return null;
              }
          }
      
          public static class Test1 extends Wine{
              public Test1(){
                  setName("Test1");
              }
              public String drink(){
                  return "喝的是 " + getName();
              }
              public String toString(){
                  return "Wine : " + getName();
              }
          }
      
          public static class Test2 extends Wine{
              public Test2(){
                  setName("Test2");
              }
              public String drink(){
                  return "喝的是 " + getName();
              }
              public String toString(){
                  return "Wine : " + getName();
              }
          }
      }
    • 第二種實現多型的方式:基於介面實現的多型

      • 繼承是通過重寫父類的同一方法的幾個不同子類來體現的,那麼就可就是通過實現介面並覆蓋介面中同一方法的幾不同的類體現的。
      • 在介面的多型中,指向介面的引用必須是指定這實現了該介面的一個類的例項程式,在執行時,根據物件引用的實際型別來執行對應的方法。
      • 繼承都是單繼承,只能為一組相關的類提供一致的服務介面。但是介面可以是多繼承多實現,它能夠利用一組相關或者不相關的介面進行組合與擴充,能夠對外提供一致的服務介面。所以它相對於繼承來說有更好的靈活性。
  • 多型有哪些弊端?

2.0.0.9 靜態變數和成員變數的區別?程式碼塊有哪些?構造程式碼塊和構造方法哪一個先執行?

  • 靜態變數和成員變數的區別

    • A:所屬不同

      • 靜態變數屬於類,所以也稱為類變數
      • 成員變數屬於物件,所以也稱為例項變數(物件變數)
    • B:記憶體中位置不同

      • 靜態變數儲存於方法區的靜態區
      • 成員變數儲存於堆記憶體
    • C:記憶體出現時間不同

      • 靜態變數隨著類的載入而載入,隨著類的消失而消失
      • 成員變數隨著物件的建立而存在,隨著物件的消失而消失
    • D:呼叫不同

      • 靜態變數可以通過類名呼叫,也可以通過物件呼叫
      • 成員變數只能通過物件名呼叫
  • 程式碼塊有哪些

    • A:程式碼塊概述

      • 在Java中,使用{}括起來的程式碼被稱為程式碼塊。
    • B:程式碼塊分類

      • 根據其位置和宣告的不同,可以分為區域性程式碼塊,構造程式碼塊,靜態程式碼塊,同步程式碼塊。
    • C:常見程式碼塊的應用

      • a:區域性程式碼塊

        • 在方法中出現;限定變數生命週期,及早釋放,提高記憶體利用率
      • b:構造程式碼塊

        • 在類中方法外出現;多個構造方法方法中相同的程式碼存放到一起,每次呼叫構造都執行,並且在構造方法前執行
      • c:靜態程式碼塊

        • 在類中方法外出現,加了static修飾
        • 在類中方法外出現,並加上static修飾;用於給類進行初始化,在載入的時候就執行,並且只執行一次。
  • 構造程式碼塊和構造方法哪一個先執行?

2.0.1.0 抽象類具有什麼特點?抽象類和普通類有何區別?抽象類可以new嗎?會出現什麼問題?

  • 抽象類具有什麼特點

    • 抽象類和抽象方法都使用 abstract 關鍵字進行宣告。抽象類一般會包含抽象方法,抽象方法一定位於抽象類中。
  • 抽象類和普通類有何區別

    • 抽象類和普通類最大的區別是,抽象類不能被例項化,需要繼承抽象類才能例項化其子類。
    public abstract class AbstractClassExample {
        protected int x;
        private int y;
        public abstract void func1();
    
        public void func2() {
            System.out.println("func2");
        }
    }
    
    public class AbstractExtendClassExample extends AbstractClassExample {
        @Override
        public void func1() {
            System.out.println("func1");
        }
    }
  • 抽象類可以new嗎?會出現什麼問題?

    • 注意抽象類是不能被例項化的,也就是不能new出來的!
    • 如果執意需要new,則會提示
    • image

其他介紹

01.關於部落格彙總連結

02.關於我的部落格


相關文章