02.Java面向對象問題

目錄介紹

  • 2.0.0.1 面向對象編程的四大特性及其含義?封裝、繼承、多態分別是什麼?爲什麼要封裝?爲何是單繼承而不能多繼承呢?
  • 2.0.0.2 重載和重寫的區別?重載和重寫綁定機制有何區別?父類的靜態方法可否被子類重寫?重寫是動態綁定,如何理解機制?
  • 2.0.0.3 什麼是綁定?靜態和動態綁定如何區別?動態綁定編譯原理是什麼?動態綁定運行原理是什麼?
  • 2.0.0.4 接口和抽象類的區別是什麼?接口的意義是什麼?抽象類的意義是什麼?如何選擇抽象類和接口?
  • 2.0.0.5 爲何內部類調用的外部變量必須是final修飾的?局部變量對垃圾回收機制有什麼樣的影響?
  • 2.0.0.7 什麼是多態?多態的實現方式有哪些?多態有哪些弊端?Java實現多態有哪些必要條件?多態的實現原理?
  • 2.0.0.9 靜態變量和成員變量的區別?代碼塊有哪些?構造代碼塊和構造方法哪個先執行?
  • 2.0.0.8 將不一樣對象分類的服務方法進行抽象,把業務邏輯的緊耦合關係拆開,實現代碼的隔離保證了方便的擴展?
  • 2.0.1.0 抽象類具備什麼特色?抽象類和普通類有何區別?抽象類能夠new嗎?會出現什麼問題?
  • 2.0.1.1 什麼是內部類,有哪些?靜態內部類和非靜態內部類的區別?內部類做用的做用主要是什麼?內部類和外部類聯繫?

好消息

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

2.0.0.1 面向對象編程的四大特性及其含義?封裝、繼承、多態分別是什麼?爲什麼要封裝?爲何是單繼承而不能多繼承呢?

  • 封裝
    • 將某事物的屬性和行爲包裝到對象中,構成一個不可分割的獨立實體。
    • 封裝把一個對象的屬性私有化,同時提供一些能夠被外界訪問的屬性的方法,若是屬性不想被外界訪問,咱們大可沒必要提供方法給外界訪問。可是若是一個類沒有提供給外界訪問的方法,那麼這個類也沒有什麼意義了。
  • 繼承
    • 繼承是使用已存在的類的定義做爲基礎創建新類的技術,新類的定義能夠增長新的數據或新的功能,也能夠用父類的功能,但不能選擇性地繼承父類。經過使用繼承咱們可以很是方便地複用之前的代碼。
    • 注意技術博客大總結
      • 子類擁有父類非 private 的屬性和方法。
      • 子類能夠擁有本身屬性和方法,即子類能夠對父類進行擴展。
      • 子類能夠用本身的方式實現父類的方法。
  • 多態
    • 所謂多態就是指程序中定義的引用變量所指向的具體類型和經過該引用變量發出的方法調用在編程時並不肯定,而是在程序運行期間才肯定,即一個引用變量倒底會指向哪一個類的實例對象,該引用變量發出的方法調用究竟是哪一個類中實現的方法,必須在由程序運行期間才能決定。
    • 在Java中有兩種形式能夠實現多態:繼承(多個子類對同一方法的重寫)和接口(實現接口並覆蓋接口中同一方法)。
  • 抽象
    • 對現實世界的事物進行歸納,抽象爲在計算機虛擬世界中有意義的實體
  • 爲何是單繼承而不能多繼承呢?
    • 若爲多繼承,那麼當多個父類中有重複的屬性或者方法時,子類的調用結果會含糊不清,所以用了單繼承。
    • 多繼承雖然能使子類同時擁有多個父類的特徵,可是其缺點也是很顯著的,主要有兩方面:
      • 若是在一個子類繼承的多個父類中擁有相同名字的實例變量,子類在引用該變量時將產生歧義,沒法判斷應該使用哪一個父類的變量。
      • 若是在一個子類繼承的多個父類中擁有相同方法,子類中有沒有覆蓋該方法,那麼調用該方法時將產生歧義,沒法判斷應該調用哪一個父類的方法。
    • Java是從C++語言上優化而來,而C++也是面向對象的,爲何它卻能夠多繼承的呢?首先,C++語言是1983年在C語言的基礎上推出的,Java語言是1995年推出的。其次,在C++被設計出來後,就會常常掉入多繼承這個陷阱,雖然它也提出了相應的解決辦法,但Java語言本着簡單的原則捨棄了C++中的多繼承,這樣也會使程序更具安全性。
  • 爲何是多實現呢?技術博客大總結
    • 經過實現接口拓展了類的功能,若實現的多個接口中有重複的方法也不要緊,由於實現類中必須重寫接口中的方法,因此調用時仍是調用的實現類中重寫的方法。

2.0.0.2 重載和重寫的區別?重載和重寫綁定機制有何區別?父類的靜態方法可否被子類重寫?重寫是動態綁定,如何理解機制?

  • 重載
    • 發生在同一個類中,方法名必須相同,參數類型不一樣、個數不一樣、順序不一樣,方法返回值和訪問修飾符能夠不一樣,發生在編譯時。
  • 重寫
    • 重寫表示子類重寫父類的方法
    • 發生在父子類中,方法名、參數列表必須相同,返回值範圍小於等於父類,拋出的異常範圍小於等於父類,訪問修飾符範圍大於等於父類;若是父類方法訪問修飾符爲 private 則子類就不能重寫該方法。
  • 重載和重寫綁定機制有何區別?技術博客大總結
    • 重載:類內多態,靜態綁定機制(編譯時已經知道具體執行哪一個方法),方法同名,參數不一樣
    • 重寫:類間多態,動態綁定機制(運行時肯定),實例方法,兩小兩同一大(方法簽名相同,子類的方法所拋出的異常、返回值的範圍不大於父類的對應方法,子類的方法可見性不小於父類的對應方法)方法簽名相同,子類的方法所拋出的異常、返回值的範圍不大於父類的對應方法,子類的方法可見性不小於父類的對應方法
  • 父類的靜態方法可否被子類重寫?
    • 父類的靜態方法是不能被子類重寫的,其實重寫只能適用於實例方法,不能用於靜態方法,對於上面這種靜態方法而言,咱們應該稱之爲隱藏。
    • 技術博客大總結
    • Java靜態方法形式上能夠重寫,但從本質上來講不是Java的重寫。由於靜態方法只與類相關,不與具體實現相關。聲明的是什麼類,則引用相應類的靜態方法(原本靜態無需聲明,能夠直接引用)。而且static方法不是後期綁定的,它在編譯期就綁定了。換句話說,這個方法不會進行多態的判斷,只與聲明的類有關。
  • 重寫是動態綁定,如何理解機制?
    • 在程序運行過程當中,根據具體的實例對象才能具體肯定是哪一個方法。
    • 動態綁定是多態性得以實現的重要因素,它經過方法表來實現:每一個類被加載到虛擬機時,在方法區保存元數據,其中,包括一個叫作 方法表(method table)的東西,表中記錄了這個類定義的方法的指針,每一個表項指向一個具體的方法代碼。若是這個類重寫了父類中的某個方法,則對應表項指向新的代碼實現處。從父類繼承來的方法位於子類定義的方法的前面。

2.0.0.3 什麼是綁定?靜態和動態綁定如何區別?動態綁定編譯原理是什麼?動態綁定運行原理是什麼?

  • 什麼是綁定?
    • 把一個方法與其所在的類/對象 關聯起來叫作方法的綁定。綁定分爲靜態綁定(前期綁定)和動態綁定(後期綁定)。
  • 靜態和動態綁定如何區別?
    • 靜態綁定(前期綁定)是指:
      • 在程序運行前就已經知道方法是屬於那個類的,在編譯的時候就能夠鏈接到類的中,定位到這個方法。
      • 在Java中,final、private、static修飾的方法以及構造函數都是靜態綁定的,不需程序運行,不需具體的實例對象就能夠知道這個方法的具體內容。
    • 動態綁定(後期綁定)是指:
      • 在程序運行過程當中,根據具體的實例對象才能具體肯定是哪一個方法。
      • 動態綁定是多態性得以實現的重要因素,它經過方法表來實現:每一個類被加載到虛擬機時,在方法區保存元數據,其中,包括一個叫作 方法表(method table)的東西,表中記錄了這個類定義的方法的指針,每一個表項指向一個具體的方法代碼。若是這個類重寫了父類中的某個方法,則對應表項指向新的代碼實現處。從父類繼承來的方法位於子類定義的方法的前面。
  • 動態綁定編譯原理技術博客大總結
    • 咱們假設 Father ft=new Son(); ft.say(); Son繼承自Father,重寫了say()。
    • 編譯:咱們知道,向上轉型時,用父類引用執行子類對象,並能夠用父類引用調用子類中重寫了的同名方法。可是不能調用子類中新增的方法,爲何呢?
    • 由於在代碼的編譯階段,編譯器經過 聲明對象的類型(即引用自己的類型) 在方法區中該類型的方法表中查找匹配的方法(最佳匹配法:參數類型最接近的被調用),若是有則編譯經過。(這裏是根據聲明的對象類型來查找的,因此此處是查找 Father類的方法表,而Father類方法表中是沒有子類新增的方法的,因此不能調用。)
    • 編譯階段是確保方法的存在性,保證程序能順利、安全運行。
  • 動態綁定運行原理是什麼?
    • 運行:咱們又知道,ft.say()調用的是Son中的say(),這不就與上面說的,查找Father類的方法表的匹配方法矛盾了嗎?不,這裏就是動態綁定機制的真正體現。
    • 上面編譯階段在 聲明對象類型 的方法表中查找方法,只是爲了安全地經過編譯(也爲了檢驗方法是不是存在的)。而在實際運行這條語句時,在執行 Father ft=new Son(); 這一句時建立了一個Son實例對象,而後在 ft.say() 調用方法時,JVM會把剛纔的son對象壓入操做數棧,用它來進行調用。而用實例對象進行方法調用的過程就是動態綁定:根據實例對象所屬的類型去查找它的方法表,找到匹配的方法進行調用。咱們知道,子類中若是重寫了父類的方法,則方法表中同名表項會指向子類的方法代碼;若無重寫,則按照父類中的方法表順序保存在子類方法表中。故此:動態綁定根據對象的類型的方法表查找方法是必定會匹配(由於編譯時在父類方法表中以及查找並匹配成功了,說明方法是存在的。這也解釋了爲什麼向上轉型時父類引用不能調用子類新增的方法:在父類方法表中必須先對這個方法的存在性進行檢驗,若是在運行時才檢驗就容易出危險——可能子類中也沒有這個方法)。技術博客大總結
  • 二者之間區分
    • 程序在JVM運行過程當中,會把類的類型信息、static屬性和方法、final常量等元數據加載到方法區,這些在類被加載時就已經知道,不需對象的建立就能訪問的,就是靜態綁定的內容;須要等對象建立出來,使用時根據堆中的實例對象的類型才進行取用的就是動態綁定的內容。

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

  • 接口和抽象類的區別是什麼
    • 接口的方法默認是 public,全部方法在接口中不能有實現(Java 8 開始接口方法能夠有默認實現),抽象類能夠有非抽象的方法
    • 接口中的實例變量默認是 final 類型的,而抽象類中則不必定
    • 一個類能夠實現多個接口,但最多隻能實現一個抽象類
    • 一個類實現接口的話要實現接口的全部方法,而抽象類不必定
    • 接口不能用 new 實例化,但能夠聲明,可是必須引用一個實現該接口的對象 從設計層面來講,抽象是對類的抽象,是一種模板設計,接口是行爲的抽象,是一種行爲的規範。
  • 接口的做用是什麼
    • 技術博客大總結
    • 一、重要性:在Java語言中, abstract class 和interface 是支持抽象類定義的兩種機制。正是因爲這兩種機制的存在,才賦予了Java強大的 面向對象能力。
    • 二、簡單、規範性:若是一個項目比較龐大,那麼就須要一個能理清全部業務的架構師來定義一些主要的接口,這些接口不只告訴開發人員你須要實現那些業務,並且也將命名規範限制住了(防止一些開發人員隨便命名致使別的程序員沒法看明白)。
    • 三、維護、拓展性:好比你要作一個畫板程序,其中裏面有一個面板類,主要負責繪畫功能,而後你就這樣定義了這個類。但是在不久未來,你忽然發現這個類知足不了你了,而後你又要從新設計這個類,更糟糕是你可能要放棄這個類,那麼其餘地方可能有引用他,這樣修改起來很麻煩。
    • 若是你一開始定義一個接口,把繪製功能放在接口裏,而後定義類時實現這個接口,而後你只要用這個接口去引用實現它的類就好了,之後要換的話只不過是引用另外一個類而已,這樣就達到維護、拓展的方便性。
    • 四、安全、嚴密性:接口是實現軟件鬆耦合的重要手段,它描敘了系統對外的全部服務,而不涉及任何具體的實現細節。這樣就比較安全、嚴密一些(通常軟件服務商考慮的比較多)。
  • 抽象類的意義是什麼
    • 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所修飾的值始終沒法改變,因此這個變量所指向的內存區域就不會變。
    • 爲了解決:局部變量的生命週期與局部內部類的對象的生命週期的不一致性問題
    • 注意:在java 1.8中,能夠不用final修飾,可是千萬不要被誤導,由於你不用final修飾,在匿名內部類中修改它的值仍是會致使編譯報錯。由於java 1.8其實會自動給它加上final
  • 局部變量對垃圾回收機制有什麼樣的影響?技術博客大總結
    • 先說出結論:局部變量表中的變量是很重要的垃圾回收根節點,被局部變量表中變量直接或者間接引用的對象都不會被回收。

2.0.0.7 什麼是多態?多態的實現方式有哪些?多態有哪些弊端?Java實現多態有哪些必要條件?多態的實現原理?

  • 什麼是多態?
    • 多態是指程序中定義的引用變量所指向的具體類型和經過該引用變量發出的方法調用在編程時並不肯定,而是在程序運行期間才肯定,即一個引用變量倒底會指向哪一個類的實例對象,該引用變量發出的方法調用究竟是哪一個類中實現的方法,必須在由程序運行期間才能決定。由於在程序運行時才肯定具體的類,這樣,不用修改源程序代碼,就可讓引用變量綁定到各類不一樣的類實現上,從而致使該引用調用的具體方法隨之改變,即不修改程序代碼就能夠改變程序運行時所綁定的具體代碼,讓程序能夠選擇多個運行狀態,這就是多態性。
  • 多態實現條件?技術博客大總結
    • 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();
              }
          }
      }
      複製代碼
    • 第二種實現多態的方式:基於接口實現的多態
      • 繼承是經過重寫父類的同一方法的幾個不一樣子類來體現的,那麼就可就是經過實現接口並覆蓋接口中同一方法的幾不一樣的類體現的。
      • 在接口的多態中,指向接口的引用必須是指定這實現了該接口的一個類的實例程序,在運行時,根據對象引用的實際類型來執行對應的方法。
      • 繼承都是單繼承,只能爲一組相關的類提供一致的服務接口。可是接口能夠是多繼承多實現,它可以利用一組相關或者不相關的接口進行組合與擴充,可以對外提供一致的服務接口。因此它相對於繼承來講有更好的靈活性。
  • 多態有哪些弊端?技術博客大總結
    • 不轉型的話,不能使用子類特有的屬性和行爲
    class Demo_SuperMan {
        public static void main(String[]args){
            Person p=new SuperMan();//父類引用指向子類對象。超人提高爲了人
                                    //父類引用指向子類對象,就是向上轉型
            System.out.println(p.name);
            p.Tsy();
            //p.Fly();//找不到該方法
            SuperMan sm=(SuperMan)p;//向下轉型,看到整個對象的內容
            sm.Fly();
        }
    }
     
    class Person{
        String name="John";
        public void Tsy(){
            System.out.println("Tsy");
        }
    }
     
    class SuperMan extends Person{
        String name="SuperName";
        @Override
        public void Tsy(){
            System.out.println("子類Tsy");
        }
     
        public void Fly(){
            System.out.println("飛出去救人");
        }
    }
    複製代碼

2.0.0.8 將不一樣對象分類的服務方法進行抽象,把業務邏輯的緊耦合關係拆開,實現代碼的隔離保證了方便的擴展?

  • 看看下面這段代碼,改編某偉大公司產品代碼,你以爲能夠利用面向對象設計原則如何改進?
    public class VIPCenter {
        void serviceVIP(T extend User user>) {
         if (user instanceof SlumDogVIP) {
            // 窮 X VIP,活動搶的那種
            // do somthing
          } else if(user instanceof RealVIP) {
            // do somthing
          }
          // ...
    }
    複製代碼
    • 這段代碼的一個問題是,業務邏輯集中在一塊兒,當出現新的用戶類型時,好比,大數據發現了咱們是肥羊,須要去收穫一下, 這就須要直接去修改服務方法代碼實現,這可能會意外影響不相關的某個用戶類型邏輯。
    • 利用開關原則,能夠嘗試改造爲下面的代碼。將不一樣對象分類的服務方法進行抽象,把業務邏輯的緊耦合關係拆開,實現代碼的隔離保證了方便的擴展。技術博客大總結
    public class VIPCenter {
        private Map<User.TYPE, ServiceProvider> providers;
        void serviceVIP(T extend User user) {
            providers.get(user.getType()).service(user);
        }
    }
    
    interface ServiceProvider{
        void service(T extend User user) ;
    }
    
    class SlumDogVIPServiceProvider implements ServiceProvider{
        void service(T extend User user){
            // do somthing
        }
    }
    
    class RealVIPServiceProvider implements ServiceProvider{
        void service(T extend User user) {
            // do something
        }
    }
    複製代碼

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

2.0.1.1 Java數據類型有哪些?什麼是值傳遞?什麼是引用傳遞?如何理解值傳遞和引用傳遞,以及它們有何區別?

  • Java數據類型有哪些?技術博客大總結
    • Java中的數據類型分爲兩種爲基本類型和引用類型。
      • 一、基本類型的變量保存原始值,因此變量就是數據自己。
        • 常見的基本類型:byte,short,int,long,char,float,double,Boolean,returnAddress。
      • 二、引用類型的變量保存引用值,所謂的引用值就是對象所在內存空間的「首地址值」,經過對這個引用值來操做對象。
        • 常見的引用類型:類類型,接口類型和數組。
    • 基本類型(primitive types)
      • primitive types 包括boolean類型以及數值類型(numeric types)。numeric types又分爲整型(integer types)和浮點型(floating-point type)。整型有5種:byte short int long char(char本質上是一種特殊的int)。浮點類型有float和double。
    • 引用類型(reference types)
      • ①接口 ②類 ③數組
  • 什麼是值傳遞?
    • 在方法的調用過程當中,實參把它的實際值傳遞給形參,此傳遞過程就是將實參的值複製一份傳遞到函數中,這樣若是在函數中對該值(形參的值)進行了操做將不會影響實參的值。由於是直接複製,因此這種方式在傳遞大量數據時,運行效率會特別低下。
    • 好比String類,設計成不可變的,因此每次賦值都是從新建立一個新的對象,所以是值傳遞!
  • 什麼是引用傳遞?技術博客大總結
    • 引用傳遞彌補了值傳遞的不足,若是傳遞的數據量很大,直接復過去的話,會佔用大量的內存空間。
    • 引用傳遞就是將對象的地址值傳遞過去,函數接收的是原始值的首地址值。
    • 在方法的執行過程當中,形參和實參的內容相同,指向同一塊內存地址,也就是說操做的其實都是源數據,因此方法的執行將會影響到實際對象。
  • 如何理解值傳遞和引用傳遞,以及它們有何區別?
    • 看下面代碼案例
      private void test1(){
          Demo demo = new Demo();
          demo.change(demo.str, demo.ch);
          Log.d("yc---",demo.str);
          Log.d("yc---", Arrays.toString(demo.ch));
          //打印值
          //yc---: hello
          //yc---: [c, b]
      }
      
      public class Demo {
          String str = new String("hello");
          char[] ch = {'a', 'b'};
          public void change(String str, char[] ch) {
              str = "ok";
              ch[0] = 'c';
          }
      }
      複製代碼
    • 案例過程分析
      • 爲對象分配空間
        • image
      • 執行change()方法
        • 執行前實參(黑色)和形參(紅色)的指向以下:
        • image
      • 最後打印
        • 由於String是不可變類且爲值傳遞,而ch[]是引用傳遞,因此方法中的str = "ok",至關於從新建立一個對象並無改變實參str的值,數組是引用傳遞,直接改變,因此執行完方法後,指向關係以下:
        • image
  • 經過上面的分析咱們能夠得出如下結論:技術博客大總結
    • 基本數據類型傳值,對形參的修改不會影響實參;
    • 引用類型傳引用,形參和實參指向同一個內存地址(同一個對象),因此對參數的修改會影響到實際的對象。
    • String, Integer, Double等immutable的類型特殊處理,能夠理解爲傳值,最後的操做不會修改實參對象。
  • 如何理解引用類型的按值傳遞?
    • 引用類型的按值傳遞,傳遞的是對象的地址。只是獲得元素的地址值,並無複製元素。好比數組,就是引用傳遞,假如說是值傳遞,那麼在方法調用賦值中,將實參的值複製一份傳遞到函數中將會很是影響效率。

其餘介紹

01.關於博客彙總連接

02.關於個人博客

相關文章
相關標籤/搜索