怎麼理解java的面向對象及三個特性


9bb62d90cd49b640e63a990ba9a31361.jpeg


首先,Java中,除了8種基本數據類型。其餘皆爲對象。
java

Java的8種基本數據類型:byte  short  int  long  float  double  char  boolean. 
基本數據類型的值,是直接存儲在線程的方法棧中的
而對象的值存儲在堆(Heap)中,在方法棧的棧幀裏,只存了對象的地址引用
PS:詳見JVM內存模型

面向對象主要有
三個基本特徵:封裝繼承多態
五個基本原則: SOLID原則,即:編程

  • 單一職責原則(SRP)
  • 開放封閉原則(OCP)
  • 里氏替換原則(LSP)
  • 接口隔離原則(ISP)
  • 依賴倒置原則(DIP)

三個基本特徵


5b41cb725803803e94abb91f9d831f78.jpeg


基本特徵的體現安全


封裝

主要概念是指:隱藏對象的屬性和實現細節,僅對外暴露公共的訪問方式。封裝是面向對象最基本的特徵之一,是類和對象概念的主要特性。框架

良好的封裝所具備的優勢:
1,隱藏信息和細節,提升安全性
2,良好的封裝能夠減小耦合性,提升複用性
3,對類內部結構能夠隨意修改,只要保證公有接口始終返回正確的結果便可。ide

在Java中的體現:
public default protected private 等設置訪問權限的關鍵字
例如,類的屬性私有化 private修飾,提供公有的 setter getter 方法對值進行獲取和修改。
同時,還能夠在setter getter函數裏進行數據校驗和對返回值作限制。這就是提升安全性的體現。模塊化



繼承

繼承是一種聯結類的層次模型,Java容許而且鼓勵代碼的重用,繼承提供了一種明確表示共性的方法,來使代碼能夠進行復用。函數

繼承的出現,讓類與類之間產生了關聯,提供了多態的前提條件優化

講到繼承,就要提到三個東西:構造器,protected關鍵字,向上轉型:ui

1,構造器:咱們已經知道,父類中private修飾的屬性和方法子類是沒法繼承的,而還有一個沒法繼承的就是 構造器。構造器只能調用而不能被繼承。
類在實例化的時候會調用自身構造器,而java編譯器會默認在子類構造器的第一行用super()先調用父類的無參構造器。若是父類沒有無參構造器,則子類在實例化的時候會報錯。這個時候就須要顯示的在子類構造器第一行(必須在第一行)指定構造器super(args)來指定調用父類哪一個構造器。線程

2,protected關鍵字:proctected關鍵字修飾的屬性和方法,能夠隔絕外部其餘類的訪問,卻可讓子類有權限訪問。
可是最好仍是把屬性都以private修飾,父類中但願子類能夠訪問到,又不但願公有的方法,能夠用protected修飾

3,向上轉型:最典型的仍是List list = new ArrayList() 將子類的實例聲明爲父類的類型,提升了通用性,也隱藏了子類的具體實現。由於這是一個由專用向通用的轉換,因此老是安全的。惟一缺陷就是專有屬性和方法的丟失。

可是繼承同時又存在缺陷:
1),繼承是一種強耦合關係,子類會因爲父類的改變而改變
2),繼承破壞了封裝的特性,對於父類而言,它的實現和細節對於子類來講都是透明的
因此到底要不要繼承:《Thinking in java》提供了一個解決方案:問一問本身是否須要從子類向父類進行向上轉型。若是必須向上轉型,則繼承是必要的,可是若是不須要,則應當好好考慮本身是否須要繼承

使用繼承的時候,必定要注意,兩個類之間是 從屬關係,父子關係 的。子類應該是基於父類原有的特性,派生出來,並在無需編父類代碼的狀況下,提供擴展的功能和方法。
不要爲了使用某個類的其中一個特性,而去繼承該類。



多態

多態,指的就是:
程序中定義的引用變量所指向的具體類型,和經過該引用變量發出的方法調用,在編程期間並不肯定,而是在程序運行期間才肯定

如何理解多態
由於在程序運行時才肯定到具體的類,因此不用修改源碼,就能讓引用變量綁定到不一樣的類型實現上,從而致使引用調用的方法發生改變,即不修改具體代碼,就可讓程序在運行時改變綁定的具體代碼,表現不一樣的運行狀態。這就是多態性。

多態的好處
多態容許不一樣類對象,對同一個消息做出響應。即同一個消息能夠根據發送對象的不一樣而採用不一樣的行爲方式(發送消息就是函數調用)。
主要好處以下:

1)可替換性。多態對已存在的代碼具備可替換性。
2)可擴充性。新增長的子類不影響已經存在的類結構。
3)接口性。多態是父類經過方法簽名,向子類提供一個公共接口,由子類來完善或者重寫它來實現的。
4)靈活性。
5)簡化性。

Java中多態的體現

  • 重寫(覆蓋)
  • 動態連接(動態調用)
  • 重載

多態的三個必要條件

  • 繼承
  • 重寫
  • 向上轉型。

多態的做用
咱們知道,封裝能夠隱藏細節,使得代碼模塊化,繼承能夠擴展已存在的模塊化代碼(父類),實現代碼的複用。

而多態,則是實現了接口的複用,多態的做用,就是在類的實現和派生的時候,保證使用基類下面,任意一個子類實例的屬性和方法,均可以正確調用。

虛擬機如何實現多態
在JVM中,是使用了動態綁定技術(dynamic binding),執行期間判斷所引用對象的實際類型,根據實際類型調用對應的方法.

重載嚴格意義上並不屬於多態,重載的具體實現是:編譯器根據不一樣的參數表,對同名函數的名稱作修飾,而後這些同名函數就變成了不一樣的函數。對重載函數的調用,在編譯期間就已經肯定了,是 靜態的(注意!是靜態的),所以,重載和多態無關。
真正和多態相關的是 重寫,當子類重寫了父類中的函數後,父類的 指針,根據賦值給它不一樣的子類對象指針, 動態的調用屬於子類的該函數,這樣在編譯期間是沒法肯定的,只有在運行期間,纔會把動態連接轉變爲直接引用(稱爲動態連接,詳見JVM內存模型-棧幀)



五個基本原則


  • 單一職責原則(Single-Resposibility Principle  SRP)
    對一個而言,應該僅有一個引發它變化的緣由

本原則是咱們很是熟悉的"高內聚原則"的引伸。同時,本原則還揭示了內聚性和耦合性:若是一個類承擔的職責過多,那麼這些職責就會相互依賴,一個職責的變化可能會影響另外一個職責的履行。其實OOP的實質,就是合理進行類的職責分配


  • 開—閉原則(Open-Closed principle  OCP)
    軟件應該是能夠擴展的,可是不能夠修改

也就是對擴展開放,對修改封閉。當變化來臨時,不須要(或者不容許)修改原來的代碼,只須要在原有的基礎上擴展(同時原有的代碼也要求支持擴展),那麼這個軟件設計就是知足開閉原則的。
此原則在Java中最典型的體現就是:抽象類 抽象基類接口。經過抽象類,把一些不可變的操做封裝起來,而提供抽象接口供子類實現,來實現各自變化的需求。
這個原則應用在類的設計中,要知足該原則就要充分的考慮到接口封裝,抽象機制和多態。


  • 里氏替換原則(Liskov-Substituion Principle  LSP)
    子類型必須可以替換掉它們的基類型

本原則和開閉原則關係密切,正是基於子類的可替換性,才使得基類能夠無需修改,只要子類繼承就能夠實現擴展特性。這是保證繼承複用的基礎

在Java中的典型體現就是 基於接口的框架設計,例如JDBC集合類
JDBC只提供了基本的接口,返回的對象類型也是接口,這樣就在選擇返回對象的時候,有了更大的靈活性:只要是繼承了返回接口類型的子類實例,均可以做爲結果返回。而服務提供者無需暴露子類的實現,調用者也無需關心子類的實現。而提供者在對實現進行優化升級時,對調用者也是不可見,同時也沒有影響的。

集合類提供了一些基本集合的接口,例如 List Map Set。咱們能夠在聲明時用這些接口類型做爲聲明對象,無需關心具體的實現類型是如何操做的,集合框架能夠很好的把實現類型和代碼隱藏起來,對調用者透明。例如List能夠用來接收ArrayList,也能夠用來接收LinkedList。能夠用來接收任何實現了List接口的類的實例。
以上兩點,充分的利用了里氏替換原則的特性,實現了封裝的基本特徵。


  • 接口隔離原則(Interface-Segregation Principle ISP)
    多個專用接口優於一個單一的通用接口

本原則是單一職責原則用於接口設計的天然結果。基本思想就是,不要讓客戶端依賴他們不須要的接口。
一個接口應該保證,實現該接口的實例對象能夠只呈現一個單一的角色。這樣當接口發生改變時,對其餘客戶端形成的影響會更小。
把多個不一樣職責的功能分到不一樣的接口中去,提升代碼的靈活性和穩定性,下降耦合性。


  • 依賴倒置原則(Dependecy-Inversion Principle DIP)
    抽象不該該依賴於細節,細節應該依賴於抽象

具體來講就是,軟件設計中,高層不依賴於低層,二者都依賴於抽象。抽象應該依賴於抽象,而不依賴於具體實現細節。即:對接口編程

在Java中的體現仍是,接口抽象類
拿最簡單的Spring IOC來講,當咱們注入的時候,接收參數類型應該是接口,而注入的對象,能夠是實現了接口的各類子類,當咱們想改變接口表現的特性的時候,無需修改代碼,只要修改注入的實現類對象就能夠。

RPC框架(例如Dubbo)開放的接口也一樣基於這個原則。上面說的JDBC,集合類框架 都基於這個原則來提供實現。提供接口對象,而把實現類隱藏在內部。

相關文章
相關標籤/搜索