【推薦】【Java編程思想】【筆記】

工欲善其事必先利其器! java

再快不能快基礎,再爛不能爛語言! 程序員

第一章 對象導論

"咱們之因此將天然界分解,組織成各類概念,並按其含義分類,主要是由於咱們是整個口語交流社會共同遵照的協定的參與者,這個協定以語言的形式固定下來......除非同意這個協定中規定的有關語言信息的組織和分類,不然咱們根本沒法交談。———Benjamin Lee Whorf( 1897~1941 )"

1.1 抽象過程

  • 面向對象的特性:
    1. 萬物皆對象。 將對象視爲奇特的變量,它能夠存儲數據,除此以外,你還能夠要求它 在自身上執行操做。理論上講,你能夠抽取待求解問題的任何概念化構建(狗,建築 物,服務等),將其表示爲程序中的對象。
    2. 程序是對象的集合,他們經過發送消息來告知彼此所要作的。 要想請求一個對象,就 必須對該對象發送一條消息。更具體地說,能夠把消息想象爲對某個特定對象的方法的 調用請求。
    3. 每一個對象都有本身的由其餘對象所構成的存儲。 換句話說,能夠經過建立包含現有對 象的包的方式來建立新類型的對象。所以,能夠在程序中構建複雜的體系,同時將其復 雜性影藏在對象的簡單性背後。
    4. 每一個對象都擁有其類型。 按照通用的說法,「每一個對象都是某個類(class)的一個實 例(instance)」,這裏「類」就是「類型」的同義詞。每一個類最重要的區別於其餘類的特性 就是「能夠發送什麼樣的消息給它」。
    5. 某一特定類型的全部對象均可以接收一樣的消息。 這是一句意味深長的表述,你在稍 後便會看到。由於「圓形」類型的對象一樣也是「幾何形」類型的對象,因此一個「圓形」對象 一定可以接受發送給「幾何形」對象的消息。這意味着能夠編寫與「幾何形」交互並自動處理 全部與幾何形性質相關的事務的代碼。這種可替代性(substitutability)是OOP中最強 有力的概念之一。
  • 每個對象在內存中都有一個惟一的地址(每個對象均可以惟一地與其餘對象區分開來)。

1.2 每一個對象都有一個接口

  • 建立抽象數據類型(類)是面向對象程序設計的基本概念之一。編程

    抽象數據的運行方式與內置(built-in)類型幾乎徹底一致:你能夠建立某一類型的變量(按 照面向對象的說法,稱其爲對象或者實例),而後操做這些變量(稱其爲發送消息或者請 求;發送消息,對象就知道要作什麼)。數組

  • 每個對象都屬於定義了特性和行爲的某個特定的類。安全

  • 由於類描述了具備相同特性(數據元素)和行爲(功能)的對象集合,因此一個類實際上就是一個數據類型。bash

  • 接口肯定了對某一特定對象所能發出的請求。併發

1.3 每一個對象都提供服務

  • 高內聚低耦合函數

    內聚: 是從功能角度來度量模塊內的聯繫,一個好的內聚模塊應當剛好作一件事。它描述 的是模塊內的功能聯繫;工具

    耦合: 是軟件結構中各模塊之間相互鏈接的一種度量,耦合強弱取決於模塊間接口的複雜 程度、進入或訪問一個模塊的點以及經過接口的數據。佈局

    高內聚低耦合,是軟件工程中的概念,是判斷設計好壞的標準,主要是面向對象的設 計,主要是看類的內聚性是否高,耦合度是否低。

    耦合性: 也稱塊間聯繫。指軟件系統結構中各模塊間相互聯繫緊密程度的一種度量。模 塊之間聯繫越緊密,其耦合性就越強,模塊的獨立性則越差。模塊間耦合高低取決於模 塊間接口的複雜性、調用的方式及傳遞的信息

    內聚性: 又稱塊內聯繫。指模塊的功能強度的度量,即一個模塊內部各個元素彼此結合 的緊密程度的度量。若一個模塊內各元素(語名之間、程序段之間)聯繫的越緊密,則 它的內聚性就越高。

    所謂高內聚是指一個軟件模塊是由相關性很強的代碼組成,只負責一項任務,也就是常 說的單一責任原則。

    耦合: 一個軟件結構內不一樣模塊之間互連程度的度量。

    對於低耦合,粗淺的理解是:一個完整的系統,模塊與模塊之間,儘量的使其獨立存 在。 也就是說,讓每一個模塊,儘量的獨立完成某個特定的子功能。模塊與模塊之間的 接口,儘可能的少而簡單。若是某兩個模塊間的關係比較複雜的話,最好首先考慮進一步 的模塊劃分。這樣有利於修改和組合。

  • 將對象看做是服務提供者還有一個附帶的好處:它有助於提升對象的內聚性。高內聚是 軟件設計的基本質量要求之一:這意味着一個軟件構造(例如一個對象,固然它也有可能 是指一個方法或一個對象庫)的各個方面「組合」得很好。人們在設計對象時所面臨的一個 問題是,將過多的功能都塞在一個對象中。

  • 在良好的面向對象設計中,每一個對象均可以很好地完成一項任務,可是它並不試圖作更多的事情。

  • 將對象做爲服務提供者看待是一件偉大的簡化工具,這不只在設計過程當中很是有用,而 且當其餘人試圖理解你的代碼或重用某個對象時,若是他們看出了這個對象所能提供的 服務的價值,它會使調整對象以適應其設計的過程變得簡單得多。

1.4 被影藏的具體實現

  • 將程序員開發人員按照角色分爲類建立者(那些建立行數據類型的程序員)和客戶端程序 員(那些在其應用中使用數據類型的類消費者)是大有裨益的。客戶端程序員的目標是收 集各類用來實現快速應用開發的類。類建立者的目標是構建類,這種類只向客戶端程序 員暴露必須的部分,而隱藏其餘部分。
  • 訪問控制存在的緣由
    • 第一個存在的緣由就是讓客戶端程序員沒法觸及他們不該該觸及的部分。
    • 第二個存在的緣由就是容許庫設計者能夠改變類內部的工做方式而不用擔憂會影響到客戶端程序員。
  • JAVA邊界值
    • public: 表示緊隨其後的元素對任何人都是可用的。
    • private: 關鍵字表示除類型建立者和類型的內部方法之外的任何人都不能訪問的元素。 private就像是你與客戶端程序員之間的一堵磚牆,若是有人試圖訪問private成 就會在編譯時獲得錯誤信息。
    • protected: protected關鍵字與private做用至關,差異僅在於繼承的類能夠訪問 protected成員,可是不能訪問private成員。
    • 默認訪問權限: 當沒有使用前面提到的任何訪問指定詞時,它將發揮做用。這種權限一般被稱爲包訪問權限,由於在這種權限下,類能夠訪問在同一個包(庫構件)中的其餘類的成員,可是在包以外,這些成員如同指定了private同樣。

1.5 複用具體實現

  • 代碼複用是面向對象程序設計語言鎖提供的最了不得的優勢之一。

  • 新的類型能夠由任意數量,任意類型的其餘對象以任意能夠實現新的類中想要的功能的方式組成。

  • 由於是在使用現有的類合成新的其餘對象的類,因此這種概念被稱爲組合(composition),若是組合是動態發生的,那麼它一般被稱爲聚合(aggregation)。

  • 在創建新類時,應該首先考慮組合,由於它更加簡單靈活。 若是採用這種方式,設計會變得更加清晰,一旦有了一些經驗以後,便可以看出必須使用繼承的場合了。

1.6 繼承

  • 當源類(被稱爲基類,超類或父類)發生變更時,被修改的「副本」(被稱爲導出類,繼承類或者子類)也會反應出變更。

  • 能夠建立一個基類來表示系統中某些對象的核心概念,從基類型中導出其餘類型,來表示此核心能夠被實現的各類不一樣方式。

  • 當繼承現有類型時,也就建立了新的類型。 這個新的類型不只包括如今類型的全部成員(儘管private成員被隱藏起來,而且不可訪問),並且更重要的是它複製了基類的接口。也就是說,全部能夠發送給基類對象的消息同時也能夠發送到導出類對象。

  • 經過繼承而產生的類型等價性是理解面向對象程序設計方法內涵的重要門檻!

  • 有兩種方法可使基類與導出類產生差別

      1. 直接在導出類中添加新方法。這些新方法並非基類接口的一部分。這意味着基類並不能知足你的全部需求,所以必需添加更多的 方法。
      1. 使導出類和基類之間產生差別的方法是改變現有基類的方法的行爲,這被稱之爲覆蓋(overriding)那個方法。
  • 繼承應該只覆蓋基類的方法(而不添加在基類中沒有的新方法),在某種意義上,這是一種處理繼承的理想方式。咱們常常將這種狀況下的基類與導出類之間的關係稱爲is-a(是一個)關係。

  • 有時必須在導出類型添加新的接口元素,這樣也就擴展了接口。這種狀況咱們能夠描述爲is-like-a(像是一個)關係。

1.7 伴隨多態的可互換對象

  • 經過導出新的子類型而輕鬆擴展設計的能力是對改動進行封裝的基本方式之一。

    這種能力能夠極大地改善咱們的設計,同時也下降軟件維護的代價。

  • 面向對象程序設計的最重要妙訣:編譯器不可能產生傳統意義上的函數調用。 一個非面向對象編程的編譯器產生的函數調用會引發所謂的前期綁定 ,這個術語你可能之前從未據說過,可能從未想過函數調用的其餘方式。這麼作意味着編譯器將產生對一個具體函數名字的調用,而運行時將這個調用解析到將要被執行的代碼的絕對地址。然而在OOP(面向對象編程)中,程序直到運行時纔可以肯定代碼的地址,因此當消息發送到一個泛化對象時,必須採用其餘的機制。

  • 當向對象發送消息時,被調用的代碼直到運行時才能肯定。 編譯器確保被調用方法的存在,並對調用參數和返回值執行類型檢查(沒法提供此類保證的語言被稱爲是弱類型的),可是並不知道將被執行的確切代碼。

  • 在java中,動態綁定是默認行爲,不須要添加額外的關鍵字來實現多態。

  • 把將被導出類看作是它的基類的過程稱爲向上轉型。

    轉型這個名稱的靈感來自於模型鑄造的塑模動做;而向上(up)這個詞來源於繼承圖的典型佈局方式;一般基類在頂部,而導出類在其下部散開。所以,轉型爲一個基類就是在繼承圖中向上移動,即「向上轉型」。

  • 正是由於多態才使得事情老是可以被正確處理。編譯器和運行系統會處理相關的細節,你須要立刻知道的只是事情會發生,更重要的是怎樣經過它來設計。當向一個對象發送消息時,即便涉及向上轉型,該對象也知道要執行什麼樣的正確行爲。

1.8 單根繼承結構

  • 在OOP中,是否全部的類最終都繼承自單一的基類?答案是yes,這個終極基類的名字就是Object。 事實證實,單根繼承結構帶來了不少好處。
  • 在單根繼承結構中的全部對象都具備一個共用的接口,因此它們歸根到底都是相同的基本類型。
  • 單根繼承結構保證全部對象都具有某些功能。
  • 單根繼承結構使垃圾回收器的實現變得容易不少,而垃圾回收器正是Java相對C++的重要改進之一。 因爲全部對象都保證具備其類型信息,所以不會因沒法肯定對象的類型而陷入僵局。這對於系統級操做(如異常處理)顯得尤爲重要,而且給編程帶來了更大的靈活性。

1.9 容器(集合)

  • 容器(也稱爲集合,不過java類庫以不一樣的含義使用「集合」這個術語,因此本書使用「容器」這個詞),在任何須要時均可擴充本身以容納你置於其中的全部東西。所以不須要知道未來會把多少個對象置於容器中,只須要建立一個容器對象,而後讓它處理全部細節。

  • Java容器

    • List(用於存儲序列)
    • Map(也被稱爲關聯數組,是用來創建對象之間的關聯)
    • Set(每種對象類型只持有一個)
    • 諸多隊列,樹,堆棧等更多的構件。
  • 使用時仍是要對容器有所選擇,緣由以下:

    • 不一樣容器提供了不一樣類型的接口和外部行爲。堆棧相比於隊列就具有不一樣的接口和行爲,也不一樣於集合列表的接口和行爲。它們之中的某些容器提供的解決方案可能要比其餘容器靈活得多。
    • 不一樣的容器對於某些操做具備不一樣的效率。最好的例子就是兩種List的比較:ArrayList和LinkedList。它們都是具備相同接口和外部行爲的簡單的序列,可是它們對於某些操做所花費的代價卻有天壤之別。在ArrayList中,隨機訪問元素是一個花費固定時間的操做;可是,對於LinkedList來講,隨機選取元素須要在列表中移動,這種代價是高昂的,訪問越靠近表尾的元素,花費的時間越長。而另外一方面,若是想在序列中間插入一個元素,LinkedList的開銷卻比ArrayList要小。
  • 咱們能夠在一開始使用LinkedList構建程序,而在優化系統性能時改用ArrayList。接口List所帶來的抽象,把在容器之間進行轉換時對代碼產生的影響下降到最小限度。

  • 參數化類型(範型) 在JavaSE5以前,容器存儲的對象都只具備Java中的通用類型:Object。

    單根繼承結構意味着全部東西都是Object類型,因此能夠存儲Object的容器能夠存儲任何東西。這使得容器很容易被複用。

  • 向上轉型是安全的,例如Circle是一種Shape類型;可是不知道某個Object是Circle仍是Shape,因此除非確切知道所要處理的對象的類型,不然向下轉型幾乎是不安全的。

  • 若是向下轉型錯誤的話,就會獲得被稱爲異常的運行時錯誤。

  • 參數化類型(範型)就是一個編譯器能夠自動定製用於特定類型上的類。 例如,經過使用參數化類型,編譯器能夠定製一個只接納和取出Shape對象的容器。

  • 爲了利用泛型的優勢,不少標準類庫構建都已經進行了修改。就像咱們將要看到的那樣,範型對本書中的許多代碼都產生了重要的影響。

1.10 對象的建立和生命期

  • 在使用對象時,最關鍵的問題之一即是它們的生成和銷燬方式。

    每一個對象爲了生存都須要資源,尤爲是內存。當咱們再也不須要一個對象時,它必須被清理掉。使其佔有的資源能夠被釋放和重用。

  • 爲了追求最大的執行速度,對象的存儲空間和生命週期能夠在編寫程序時肯定。

    • 這能夠經過將對象置於堆棧(它們有時被稱爲自動變量)或限域變量或靜態存儲區域內來實現。

      這種方式將存儲空間分配和釋放置於優先考慮的位置,某些狀況下這樣的控制很是有價值。可是,也犧牲了靈活性,由於必須在編寫程序時知道對象確切的數量,生命週期和類型。

    • 第二種方式是在被稱爲堆(heap)的內存池中動態地建立對象。

      在這種方式中,直到運行時才知道須要多少對象,它們的生命週期如何,以及它們的具體類型是什麼。

  • 若是須要一個新對象,能夠在須要的時刻直接在堆中建立。由於存儲空間是在運行時被動態管理的,因此須要大量的時間在堆中分配存儲空間,這可能要遠遠大於在堆棧中建立存儲空間的時間。

  • 建立堆棧存儲空間的時間依賴於存儲機制的設計

  • 動態方式有這樣一個通常性的邏輯假設:對象趨向於變得複雜。因此查找和釋放存儲空間的開銷不會對對象的建立形成重大沖擊。動態方式所帶來的更大的靈活性正是解決通常化編程問題的要點所在。

  • java徹底採用動態內存分配方式。每當想要建立新對象時,就要使用new關鍵字來構建此對象的動態實例。

  • 還有一個議題,就是生命週期。對於容許在堆棧上建立對象的語言,編譯器能夠肯定對象存活的時間,並能夠自動銷燬它。

  • java提供了被稱爲「垃圾回收器」的機制,它能夠自動發現對象什麼時候再也不被使用,並繼而銷燬它。

    垃圾回收器很是有用,由於它減小了所必須考慮的議題和必須編寫的代碼。更重要的是,垃圾回收器提供了更高層的保障,能夠避免暗藏的內存泄漏問題。

  • java的垃圾回收器被設計用來處理內存釋放問題(儘管它不包括清理對象的其餘方面)。垃圾回收器「知道」對象什麼時候再也不被使用,並自動釋放對象佔用的內存。

1.11 異常處理:處理錯誤

  • 異常是一種對象,它從出錯地點被「拋出」,並被專門設計用來處理特定類型錯誤的相應的異常處理器「捕獲」。異常處理就像是與程序正常執行路徑並行的、在錯誤發生時執行的另外一條路徑。由於它是另外一條徹底分離的執行路徑,因此它不會干擾正常的執行代碼。
  • 被拋出的異常不像方法返回的錯誤值和方法設置的用來表示錯誤條件的標誌位那樣能夠被忽略,異常不能被忽略,因此它保證必定會在某處獲得處理。
  • 異常提供了一種從錯誤情況進行可靠恢復的途徑。如今再也不是隻能退出程序,你能夠常常進行校訂,並恢復程序的執行,這些都有助於編寫出更健壯的程序。

1.12 併發編程

  • 在計算機編程中有一個基本的概念,就是在同一時刻處理多個任務的思想。
  • 在程序中,彼此獨立運行的部分稱之爲線程。
  • 對於大量的問題,把問題切分紅多個可獨立運行的部分(任務),從而提升程序的響應能力。稱之爲「併發」。
  • 線程只是一種爲單一處理器分配執行時間的手段。
  • 若是有多個並行任務都要訪問同一項資源,那麼就會出問題。例如,兩個進程不能同時向一臺打印機發送信息。爲了解決這個問題,能夠共享的資源,例如打印機,必須在使用期間被鎖定。所以,整個過程是:某個任務鎖定某項資源,完成其任務,而後釋放資源鎖,使其餘任務可使用這項資源。

第2章 一切都是對象

"若是咱們說另外一種不一樣的語言,那麼咱們就會發覺一個有些不一樣的世界。——Luduing Wittgerstein( 1889~1951 )"

2.1 用引用操縱對象

  • java中,一切都被視爲對象,所以可採用單一的語法。儘管一切都看做是對象,但操做的標識符其實是對象的一個「引用」。

    例:遙控器(引用)操做電視機(對象)。

    • java操做的標識符其實是對象的一個「引用」
    • java操做的標識符其實是對象的一個「引用」
    • java操做的標識符其實是對象的一個「引用」

2.2 必須由你建立全部對象

  • new 關鍵字的意思是「給我一個新對象」。
  • 存儲數據的地方:
    • 寄存器: 最快的存儲區,但因爲寄存器的數量極其有限,因此根據需求進行分配。你不能直接控制,在程序中也感受不到寄存器存在的任何跡象。

    • 堆棧: 位於通用RAM(隨機訪問存儲器)中。堆棧指針若往下移則分配新內存,若往上移動則釋放內存。

      堆棧:就是STACK。其實是隻有一個出入口的隊列,即後進先出(First In Last Out),先分配的內存一定後釋放。通常由系統自動分配,存放函數的參數值,局部變量等,自動清除。

      堆棧是每一個函數進入的時候分一小塊,函數返回的時候就釋放了

      局部變量放在堆棧中,因此函數返回,局部變量就全沒了。

    • 堆: 一種通用的內存池(位於RAM區),用來存放全部的Java對象。

      當須要一個對象時,只需用new寫一行簡單的代碼,當執行這行代碼時,會自動在堆裏進行存儲分配。

      用堆進行存儲分配和清理可能比用堆棧進行存儲分配須要更多的時間。

    • 常量存儲: 常量值一般是直接存放在程序代碼內部。

    • 非RAM存儲: 若是數據徹底存活於程序以外,那麼它能夠不受程序的任何控制,在程序沒有運行也能夠存在。例如:流對象和持久化對象。

  • 基本數據類型
    • 基本數據類型不用new來建立對象,而是建立一個並不是是引用的「自動」變量。這個變量直接存儲「值」,並置於堆棧中,所以更加高效。
    • 全部數據類型都有正負號,沒有無符號的數值類型。
    • 基本類型具備的包裝器類,使得能夠在堆中建立一個非基本對象,用來表示對應的及本類型。
    • java SE5的自動包裝功能將自動地將基本數據類型轉換成包裝器類型。
    • java提供了兩個用於高精度計算的類:BigInteger(支持任意精度的整數)和BigDecimal(支持任何精度的定點數)。

2.3 永遠不須要銷燬對象

  • 做用域
    • 做用域由花括號的位置決定。
    • 做用域裏定義的變量只可用於做用域結束以前。
  • 對象的做用域
    • 當new建立一個java對象時,它能夠存活於做用域以外。
    • java有一個垃圾回收器,用來監視用new建立的全部對象,並辨別那些不會再被引用的對象。隨後,釋放這些對象的內存空間,以便提供其餘新的對象使用。

2.4 建立新的數據類型:類

  • class這個關鍵字以後緊跟的是新類型的名稱。
  • 在java中你所作的所有工做就是定義類,產生那些類的對象,以及發送消息給這些對象。
  • 字段能夠是任何類型,能夠經過其引用與其進行通訊,也能夠是基本類型的一種。
  • 若是字段是對某個對象的引用,那麼必須初始化該引用,以便使其與一個實際的對象相關聯。

2.5 方法、參數和返回值

  • java的方法決定了一個對象可以接收什麼樣的消息,組成(名稱、參數、返回值、方法)。
  • 方法名和參數列表惟一地標識出某個方法。
  • 調用方法的行爲一般被稱爲發送消息給對象。
  • 面向對象的程序設計一般簡單地概括爲「向對象發送消息」。
  • 一般,儘管傳遞的是對象,而實際上傳遞的是對象的引用。

2.6 構建一個java程序

  • java經過域名來保證每個類都是獨一無二的。
  • static關鍵字
    • 執行new來建立對象時,數據存儲空間才被分配,其方法才供外界調用。
    • new建立對象知足不了的兩種場景:
        1. 只想爲某特定域分配單一存儲空間,而不去考慮究竟要建立多少對象,甚至根本就不建立任何對象。
        1. 但願某個方法不與包含它的類的任何對象關聯在一塊兒。也就是說沒有建立對象,也可以調用這個方法。
      • 【解決】當聲明一個事物是static時,就意味着這個域或方法不會與包含它的類的任何對象實例關聯在一塊兒。
    • 使用static方法(或域)前不須要建立任何對象。
    • 一個static字段對每一個類來講只有一份存儲空間,而非static字段則是對每一個對象都有一個存儲空間

第3章 操做符

3.7 關係操做符

  • new出來的兩個Integer,儘管對象內容相同,但對象的引用倒是不一樣的,== 和 != 比較的就是對象的引用。
  • 若是想比較兩個對象實際內容是否相同,必須使用全部對象都適用的equals()
  • 基本類型直接使用== 和 !=

第4章 控制執行流程

  • java不容許咱們將一個數字做爲布爾值使用!
  • return關鍵字有兩方面的用途:
    • 一方面指定一個方法返回什麼值
    • 另外一方面它會致使當前的方法退出,並返回那個值。
  • break用於強行退出循環,不執行循環中剩餘的語句。
  • 而continue則中止執行當前的迭代,而後退回循環起止處,開始下一次迭代。

第5章 初始化與清理

5.1 用構造器確保初始化

  • 構造器採用與類相同的名稱,在建立對象時,new XXX()將會爲對象分配存儲空間,並調用相應的構造器。這就確保了在操做對象以前,它已經初始化了。
  • 每一類都會有一個默認構造器,java文檔中稱爲「無參構造器」。
  • 構造器是一種特殊類型的方法,沒有返回值。
  • 在java中,「初始化」和「建立」捆綁在一塊兒,二者不能分離!

5.2 方法重載

  • 重載:方法名相同而形式參數不一樣。
  • 每一個重載的方法都必須有一個獨一無二的參數類型列表。
  • 不能夠根據返回值來區分重載方法。
  • 重載最多見的應用場景就是構造器重載!

5.3 默認構造器

  • 默認構造器(又名「無參」構造器)是沒有形式參數的——它的做用是建立一個「默認對象」。
  • 假如類中沒有構造器的話,編譯器會自動幫你建立一個默認構造器。但假如你已寫了一個構造器(有參構造),則會自動覆蓋掉默認構造器(也就是說此時類裏面沒有默認的構造器(無參構造),若是你還須要無參構造這時你要本身手動添加一個無參構造)。

5.4 this關鍵字

class Banana { void peel(int i) {/*...*/} }

public class BananaPeel{
    public static void main(String[] args) {
        Banana a = new Banana();
        Banana b = new Banana();
        a.peel(1);
        b.peel(2);
    }
}
複製代碼

【問題】peel()如何知道是被a仍是被b調用的呢?

【答】:爲了能簡便面向對象的語法來編寫代碼,編譯器暗自把「操做對象的引用」做爲第一個參數傳遞給peel(),
       a.peel(a,1);這是內部表現形式。
複製代碼
  • 若是在方法內部的時候須要得到當前對象的引用,可使用this關鍵字!
  • this關鍵字只能在方法的內部調用!
  • 一般寫 this 的時候,都是指「這個對象」或者「當前對象」,並且它自己表示對當前對象的引用。
  • 能夠用this調用一個構造器,但卻不能調用兩個,並且必須將構造器置於最起始處,不然會報錯。
  • 除構造器之外,編譯器禁止在其餘任何方法中調用構造器!
  • static 就是沒有this的方法
  • static方法的內部不能調用非靜態方法
  • static能夠在沒有建立對象的前提下,僅僅經過類自己來調用static方法。

5.5 清理:終結處理與垃圾回收

  • java中的垃圾回收器負責回收無用對象佔據的內存資源。

  • 垃圾回收器只知道釋放由new分配的內存。

  • finalize():在垃圾回收器準備好釋放回收對象佔用的存儲空間以前調用的方法,能夠自定義作一些清理工做。

    【問題】finalize()和析構函數的區別:

    析構函數(C++中銷燬對象必須用這個函數):「析構」函數與構造函數相反,當對象結束其生命週期,
      如對象所在的函數已調用完畢時,系統自動執行析構函數。析構函數每每用來作「清理善後」的工做。
    複製代碼
  • Java對象並不是老是被垃圾回收:

    1. 對象可能不被垃圾回收。
    2. 垃圾回收並不等於「析構」。
    3. 垃圾回收只與內存有關。
  • 在java中,只要程序沒有瀕臨存儲用完的那一刻,對象佔用的空間就總也得不到釋放。

  • 使用垃圾回收器的惟一緣由是爲了回收程序再也不使用的內存。

  • finalize()的用途之——釋放空間:

    1. 不管對象是如何建立的,垃圾回收器都會負責釋放對象佔據的全部內存。

    當代碼中使用「本地方法」的狀況下,好比調用C的malloc()函數系列來分配存儲空間時,須要在finalize中調用free()來釋放內存空間。

    注:本地方法是一種在java中調用非java代碼,通常用「native」關鍵字修飾。

  • finalize()的用途之——終結條件驗證:

    在對象資源被釋放以前驗證對象的某個狀態,將驗證內容放在finalize()的方法中,能夠避免一些因爲代碼書寫問題致使的缺陷。

    注:【Effective Java】中「避免使用終結方法和清楚方法」一節中提到:終結方法(finalize)一般是不可預測的,也是很危險的,通常狀況下是沒必要要的。使用終結方法會致使行爲不穩定,性能下降,以及可移植性問題,根據經驗,應該避免使用終結方法。

  • 垃圾回收器如何工做

    在堆上分配對象代價是十分高昂的,所以java中全部對象的分配方式也是很是高昂的。然而垃圾回收器對於提升對象的建立速度,卻具備明顯的效果。

    • 在某些java虛擬機中,堆的實現就至關與一個傳送帶,每分配一個對象,它就往前移動一格,這意味着對象存儲的分配速度很是快。
    • java的堆並未徹底像傳送帶那樣工做。
    • 當它工做時,一面回收空間,一面使堆中的對象緊湊排列,這樣「堆指針」就能夠很容易移動到更靠近傳送帶的開始處,也就避免來頁面錯誤。經過垃圾回收器對對象重寫排列,實現了一種高速的,有無限空間可供分配的堆模型。
  • 垃圾回收器的實現:

    垃圾回收器依據的思想是:對任何「活」的對象,必定能最終追溯到其存在在堆棧或靜態存儲區之中的引用。

    • 引用計數器: 是一種簡單但速度很慢的垃圾回收技術。

      每一個對象都含有一個引用計數器,當有引用鏈接至對象時,引用計數加1。當引用離開做用域或設置爲null的時候,引用計數器減1。垃圾回收器會在含有所有對象的列表上便利,當發現某個對象的引用計數爲0時,就釋放其佔用的空間。但循環引用會致使「對象應該被回收,計數卻不爲0」。

      引用計數未被應用於任何一種java虛擬機實現中。

    • 中止,複製:

      先暫停程序的運行(不屬於後臺回收模式),而後將全部存活的對象從當前堆複製到另外一個堆,沒有被複制的所有都是垃圾。當把對象從一處搬到另外一處時,全部指向它的那些引用都必須修正了。位於堆或靜態存儲的引用能夠直接被修改,但還有其餘指向的引用,在遍歷的過程才能被找到。

      這種方式,效率會很低。一方面須要在兩個分離的堆之間來回倒騰;另外一方面是程序穩定後,可能只會產生少許垃圾,甚至沒有垃圾,但仍然會將全部的內存自一處複製到另外一處。

      垃圾回收動做不是在後臺進行的,垃圾回收動做發生時,程序會被暫停。

      「中止-複製」要求在釋放舊的對象以前,必須把全部存活的對象從舊堆裏複製到新堆。這將致使大量內存複製行爲。

    • 標記,清掃

      從堆棧和靜態存儲區出發,遍歷全部的引用,進而找出全部存活的對象。每當找到一個存活對象,就會給對象設一個標記,但這時不回收任何對象。只有所有標記工做完成,纔開始清理。沒有標記的將被釋放,有標記纔會進行復制動做。必須在程序暫停的狀況下才能進行。

    • 「自適應的,分代的,中止-複製,標記-清掃」式垃圾回收器

      • 內存分配以較大的「塊」爲單位,若是對象大,它會佔用獨立的塊。使用塊之後,垃圾回收器在回收的時候就能夠往廢棄的塊裏拷貝對象了。
      • 每一個塊都有相應的 代數(generation count) 來記錄它是否還存活。
      • 若是塊在某處被引用,其代數會增長,垃圾回收器將對上次回收動做以後新分配的塊進行整理(對於處理大量短命的臨時對象頗有益處)。
      • 垃圾回收器會按期進行完整的清理動做——大型對象仍然不會被複制(只是其代數會增長),內含小型對象的那些快則被複制並整理。
      • java虛擬機會進行監視,若是全部對象都很穩定,垃圾回收器效率下降的話,就切換到 「標記-清掃」 方式;
      • java虛擬機會跟蹤「標記-清掃」的效果,要是堆空間出現不少碎片,就會切換到 「中止-複製」 方式; 根據不一樣的狀況切換不一樣的方式,稱爲「自適應」技術。

5.7 構造器初始化

  • 類中的變量初始化在構造器以前

  • 不管建立多少個對象,靜態數據都只佔一份存儲區域。

  • static關鍵不能應用於局部變量,只能做用於域。

  • 若是是一個靜態的基本類型域,且沒有初始化,那麼它就會得到基本類型的標準初值。

    若是它是一個對象引用,那麼它的默認初始值就是null。

  • 靜態存儲初始化時間:

    類中的靜態成員都會隨着類的加載而加載,好比建立對象時,或者是被引用時!

    類中的靜態成員都會隨着類的加載而加載,好比建立對象時,或者是被引用時!

    類中的靜態成員都會隨着類的加載而加載,好比建立對象時,或者是被引用時!

  • 初始化的順序是先靜態對象,然後「非靜態」對象。

  • 對象的建立過程

    1. 若沒有顯示地使用static方法,構造器實際上也是static方法,當對象被建立或者類的靜態方法/靜態域被首次訪問時,java解釋器要找到類路徑,而後定位.class文件。
    2. 載入.class文件,有關靜態初始化的全部動做都會執行。所以,靜態初始文件只在Class對象首次加載的時候進行一次。
    3. 當使用new()建立的時候,將在堆上爲對象分配足夠的空間。
    4. 這塊存儲空間會被清零,將全部基本數據都設置爲默認值,引用被設置爲null。
    5. 執行全部出現於字段定義處的初始化動做。
    6. 執行構造器。

5.10 總結

  • 構造器能保證正確的初始化和清理(沒有正確的構造器調用,編譯器就不容許建立對象),因此有了徹底的控制,也很安全。
  • 垃圾回收器會自動爲對象釋放內存,因此在不少場合下,相似的清理方法在java中就不太須要了。
  • java的垃圾回收器能夠極大地簡化編程工做,並且在處理內存的時候也更安全。

【推薦篇】- 書籍內容整理筆記 連接地址
【推薦】【Java編程思想】【筆記】 juejin.im/post/5dbb7a…
【推薦】【Java核心技術 卷Ⅰ】【筆記】 juejin.im/post/5dbb7b…

後期持續更新中。。。。。。

如有書寫錯誤的地方,歡迎留言,但願咱們能夠一塊兒進步,一塊兒加油!😜😜

相關文章
相關標籤/搜索