JAVA基礎_Java面向對象三大特徵

封裝(面向對象特徵之一)

首先,屬性可用來描述同一類事物的特徵,方法可描述一類事物可做的操作。封裝就是把屬於同一類事物的共性(包括屬性與方法)歸到一個類中,以方便使用。
1.概念:封裝也稱爲信息隱藏,是指利用抽象數據類型將數據和基於數據的操作封裝在一起,使其構成一個不可分割的獨立實體,數據被保護在抽象數據類型的內部,儘可能地隱藏內部的細節,只保留一些對外接口使之與外部發生聯繫。系統的其他部分只有通過包裹在數據外面的被授權的操作來與這個抽象數據類型交流與交互。也就是說,用戶無需知道對象內部方法的實現細節,但可以根據對象提供的外部接口(對象名和參數)訪問該對象。
2.好處:(1)實現了專業的分工。將能實現某一特定功能的代碼封裝成一個獨立的實體後,各程序員可以在需要的時候調用,從而實現了專業的分工。(2)隱藏信息,實現細節。通過控制訪問權限可以將可以將不想讓客戶端程序員看到的信息隱藏起來,如某客戶的銀行的密碼需要保密,只能對該客戶開發權限。

import java.io.*;

class OperationAttridute

{

       private double numberA=0;

       private double numberB=0;

       private double result=0;

       public double setNumberA(double i)

       {

              return numberA=i;

       }

       public double getNumberA()

       {

              return numberA;

       }

       public double setNumberB(double j)

       {

              return numberB=j;

       }

       public double getNumberB()

       {

              return numberB;

       }

       public double setResult(double z)

       {

              return result=z;

       }

       public double getResult(double a,double b)

       {

              return result;

       }

}
//將要運算的2個數字和運算結果進行封裝。

繼 承(面向對象特徵之二)

好處:
1:提高了代碼的複用性。
2:讓類與類之間產生了關係,提供了另一個特徵多態的前提。

父類的由來:其實是由多個類不斷向上抽取共性內容而來的。
java中對於繼承,java只支持單繼承。java雖然不直接支持多繼承,但是保留了這種多繼承機制,進行改良。

單繼承:一個類只能有一個父類。
多繼承:一個類可以有多個父類。

爲什麼不支持多繼承呢?
因爲當一個類同時繼承兩個父類時,兩個父類中有相同的功能,那麼子類對象調用該功能時,運行哪一個呢?因爲父類中的方法中存在方法體。
但是java支持多重繼承。A繼承B B繼承C C繼承D。
多重繼承的出現,就有了繼承體系。體系中的頂層父類是通過不斷向上抽取而來的。它裏面定義的該體系最基本最共性內容的功能。
所以,一個體系要想被使用,直接查閱該系統中的父類的功能即可知道該體系的基本用法。那麼想要使用一個體系時,需要建立對象。建議建立最子類對象,因爲最子類不僅可以使用父類中的功能。還可以使用子類特有的一些功能。

簡單說:對於一個繼承體系的使用,查閱頂層父類中的內容,創建最底層子類的對象。

子父類出現後,類中的成員都有了哪些特點:
1:成員變量。
當子父類中出現一樣的屬性時,子類類型的對象,調用該屬性,值是子類的屬性值。
如果想要調用父類中的屬性值,需要使用一個關鍵字:super
This:代表是本類類型的對象引用。
Super:代表是子類所屬的父類中的內存空間引用。
注意:子父類中通常是不會出現同名成員變量的,因爲父類中只要定義了,子類就不用在定義了,直接繼承過來用就可以了。
2:成員函數。
當子父類中出現了一模一樣的方法時,建立子類對象會運行子類中的方法。好像父類中的方法被覆蓋掉一樣。所以這種情況,是函數的另一個特性:覆蓋(複寫,重寫)
什麼時候使用覆蓋呢?當一個類的功能內容需要修改時,可以通過覆蓋來實現。
3:構造函數。
發現子類構造函數運行時,先運行了父類的構造函數。爲什麼呢?
原因:子類的所有構造函數中的第一行,其實都有一條隱身的語句super();
super(): 表示父類的構造函數,並會調用於參數相對應的父類中的構造函數。而super():是在調用父類中空參數的構造函數。
爲什麼子類對象初始化時,都需要調用父類中的函數?(爲什麼要在子類構造函數的第一行加入這個super()?)
因爲子類繼承父類,會繼承到父類中的數據,所以必須要看父類是如何對自己的數據進行初始化的。所以子類在進行對象初始化時,先調用父類的構造函數,這就是子類的實例化過程。

注意:子類中所有的構造函數都會默認訪問父類中的空參數的構造函數,因爲每一個子類構造內第一行都有默認的語句super();
如果父類中沒有空參數的構造函數,那麼子類的構造函數內,必須通過super語句指定要訪問的父類中的構造函數。
如果子類構造函數中用this來指定調用子類自己的構造函數,那麼被調用的構造函數也一樣會訪問父類中的構造函數。

問題:super()和this()是否可以同時出現的構造函數中。
兩個語句只能有一個定義在第一行,所以只能出現其中一個。

super()或者this():爲什麼一定要定義在第一行?
因爲super()或者this()都是調用構造函數,構造函數用於初始化,所以初始化的動作要先完成。

繼承的細節:
什麼時候使用繼承呢?
當類與類之間存在着所屬關係時,才具備了繼承的前提。a是b中的一種。a繼承b。狼是犬科中的一種。
英文書中,所屬關係:” is a ”
注意:不要僅僅爲了獲取其他類中的已有成員進行繼承。

所以判斷所屬關係,可以簡單看,如果繼承後,被繼承的類中的功能,都可以被該子類所具備,那麼繼承成立。如果不是,不可以繼承。

細節二:
在方法覆蓋時,注意兩點:
1:子類覆蓋父類時,必須要保證,子類方法的權限必須大於等於父類方法權限可以實現繼承。否則,編譯失敗。
2:覆蓋時,要麼都靜態,要麼都不靜態。 (靜態只能覆蓋靜態,或者被靜態覆蓋)

繼承的一個弊端:打破了封裝性。對於一些類,或者類中功能,是需要被繼承,或者複寫的。
這時如何解決問題呢?介紹一個關鍵字,final:最終。

final特點:
1:這個關鍵字是一個修飾符,可以修飾類,方法,變量。
2:被final修飾的類是一個最終類,不可以被繼承。
3:被final修飾的方法是一個最終方法,不可以被覆蓋。
4:被final修飾的變量是一個常量,只能賦值一次。

其實這樣的原因的就是給一些固定的數據起個閱讀性較強的名稱。
不加final修飾不是也可以使用嗎?那麼這個值是一個變量,是可以更改的。加了final,程序更爲嚴謹。常量名稱定義時,有規範,所有字母都大寫,如果由多個單詞組成,中間用 _ 連接。
class OperationA extends OperationAttridute

{    

       public double getResult(double a,double b)

       {

              double result=0;

              result=a+b;

              return result;

       }    

}

//加法類:繼承OperationAttridute類並且覆蓋其getResult方法

class OperationS extends OperationAttridute

{

       public double getResult(double a,double b)

       {

              double result=0;

              result=a-b;

              return result;

       }

}

//減法類:繼承OperationAttridute類並且覆蓋其getResult方法

class OperationM extends OperationAttridute

{

       public double getResult(double a,double b)

       {

              double result=0;

              result=a*b;

              return result;

       }

}

//乘法類:繼承OperationAttridute類並且覆蓋其getResult方法

class OperationD extends OperationAttridute

{

       public double getResult(double a,double b)

       {

              double result=0;

              if(b==0)

              {

                     Throw new RuntimeException(“被除數不能爲0”);

              }

              result=a/b;

              return result;

       }

}

//除法類:繼承OperationAttridute類並且覆蓋其getResult方法,除法要對被除數進行判斷並拋出異常

多 態★★★★★(面向對象特徵之三):

函數本身就具備多態性,某一種事物有不同的具體的體現。

體現:父類引用或者接口的引用指向了自己的子類對象。//Animal a = new Cat();
多態的好處:提高了程序的擴展性。
多態的弊端:當父類引用指向子類對象時,雖然提高了擴展性,但是隻能訪問父類中具備的方法,不可以訪問子類中特有的方法。(前期不能使用後期產生的功能,即訪問的侷限性)
多態的前提:
1:必須要有關係,比如繼承、或者實現。
2:通常會有覆蓋操作。

多態的出現思想上也做着變化:以前是創建對象並指揮對象做事情。有了多態以後,我們可以找到對象的共性類型,直接操作共性類型做事情即可,這樣可以指揮一批對象做事情,即通過操作父類或接口實現。

class 畢姥爺{
void 講課(){
System.out.println(“企業管理”);
}
void 釣魚(){
System.out.println(“釣魚”);
}
}
class 畢老師 extends 畢姥爺{
void 講課(){
System.out.println(“JAVA”);
}
void 看電影(){
System.out.println(“看電影”);
}
}
class {
public static void main(String[] args) {
畢姥爺 x = new 畢老師(); //畢老師對象被提升爲了畢姥爺類型。
// x.講課();
// x.看電影(); //錯誤.
畢老師 y = (畢老師)x; //將畢姥爺類型強制轉換成畢老師類型。
y.看電影();//在多態中,自始自終都是子類對象在做着類型的變化。
}

}

如果想用子類對象的特有方法,如何判斷對象是哪個具體的子類類型呢?
可以可以通過一個關鍵字 instanceof ;//判斷對象是否實現了指定的接口或繼承了指定的類

格式:<對象 instanceof 類型> ,判斷一個對象是否所屬於指定的類型。
Student instanceof Person = true;//student繼承了person類

多態在子父類中的成員上的體現的特點:
1,成員變量:在多態中,子父類成員變量同名。
在編譯時期:參考的是引用型變量所屬的類中是否有調用的成員。(編譯時不產生對象,只檢查語法錯誤)
運行時期:也是參考引用型變量所屬的類中是否有調用的成員。
簡單一句話:無論編譯和運行,成員變量參考的都是引用變量所屬的類中的成員變量。
再說的更容易記憶一些:成員變量 — 編譯運行都看 = 左邊。
2,成員函數。
編譯時期:參考引用型變量所屬的類中是否有調用的方法。
運行事情:參考的是對象所屬的類中是否有調用的方法。
爲什麼是這樣的呢?因爲在子父類中,對於一模一樣的成員函數,有一個特性:覆蓋。
簡單一句:成員函數,編譯看引用型變量所屬的類,運行看對象所屬的類。
更簡單:成員函數 — 編譯看 = 左邊,運行看 = 右邊。
3,靜態函數。
編譯時期:參考的是引用型變量所屬的類中是否有調用的成員。
運行時期:也是參考引用型變量所屬的類中是否有調用的成員。
爲什麼是這樣的呢?因爲靜態方法,其實不所屬於對象,而是所屬於該方法所在的類。
調用靜態的方法引用是哪個類的引用調用的就是哪個類中的靜態方法。
簡單說:靜態函數 — 編譯運行都看 = 左邊。

class Operationdo

{

       public static Object expression_r(char r)

       {

              OperationAttridute oa=new OperationAttridute();       

              switch(r)

              {

                     case '+':

                     oa=new OperationA();                

                     break;

                     case '-':

                     oa=new OperationS();                 

                     break;

                     case '*':

                     oa=new OperationM();         

                     break;

                     case '/':

                     oa=new OperationD();         

                     break;                  

              }

              return oa;             

       }

}

//運算類:通過傳進來的參數,來調用運算方法

class Account

{

       public static void main(String []args)throws Exception

       {

              char r='*';                   

              OperationAttridute oa=(OperationAttridute)Operationdo.expression_r(r);

              double a=oa.setNumberA(9);

              double b=oa.setNumberB(2);

              System.out.println(oa.getResult(a,b));  

       }

}

//主程序

這樣,只需要輸入運算符號,通過多態,返回父類的方式實現了計算器的結果。
發佈了36 篇原創文章 · 獲贊 33 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章