java 面對對象(抽象 繼承 接口 多態)

什麼是繼承?

多個類中存在相同屬性和行爲時,將這些內容抽取到單獨一個類中,那麼多個類無需再定義這些屬性和行爲,只要繼承那個類便可。java

多個類能夠稱爲子類,單獨這個類稱爲父類超類或者基類模塊化

子類能夠直接訪問父類中的非私有的屬性和行爲。函數

經過 extends 關鍵字讓類與類之間產生繼承關係。工具

class SubDemo extends Demo{} //SubDemo是子類,Demo是父類

繼承有什麼好處?

  • 提升代碼的複用性
  • 讓類與類之間產生了關係,是多態的前提

繼承的特色

1.Java只支持單繼承,不支持多繼承。學習

//一個類只能有一個父類,不能夠有多個父類。
class SubDemo extends Demo{} //ok class SubDemo extends Demo1,Demo2...//error

2.Java支持多層(重)繼承(繼承體系)。this

class A{} class B extends A{} class C extends B{}

使用繼承時的注意事項

  • 若是類之間存在着:is a 的關係,就能夠考慮使用繼承。
  • 不要爲了繼承部分功能,而去使用繼承。

super和this有什麼區別?

super是一個關鍵字,表明父類的存儲空間標識。(能夠理解爲父親的引用)spa

super和this的用法類似。模塊化開發

this表明對象的引用(誰調用就表明誰);
super表明當前子類父類的引用。對象

使用場景繼承

  • 當子父類出現同名成員時,能夠用super進行區分;
  • 子類要調用父類構造函數時,可使用super語句。

區別

1.成員變量

this.變量    --    本類的
super.變量 -- 父類的

2.構造方法

this(...)    --    本類的
super(...) -- 父類的

3.成員方法

this.方法名()    --    本類的    
super.方法名() -- 父類的

super();和this();都是在構造函數的第一行,不能同時出現。

方法的重寫(覆蓋)

子類中出現與父類如出一轍的方法時(除了權限修飾符,權限修飾符大於等於不包括private,返回值類型,方法名和參數列表相同),會出現覆蓋操做,也稱爲重寫或者複寫。

父類私有方法,子類看不到,所以父類私有方法的重寫也就無從談起。

覆蓋注意事項

  • 覆蓋時,子類方法權限必定要大於等於父類方法權限;
  • 靜態只能覆蓋靜態。

覆蓋的使用場景

當子類須要父類的功能,而功能主體子類有本身特有內容時,能夠複寫父類中的方法,這樣,既沿襲了父類的功能,又定義了子類特有的內容。

方法重寫和重載有什麼區別

方法的重寫用在子類方法與父類方法如出一轍時,除權限修飾符,返回值類型,方法名和參數列表都是相同的。
重載用在同一個類中各方法方法名相同,參數列表不一樣(與返回值類型沒有關係)的狀況。

子父類中構造方法的用法

  1. 子類的初始化過程當中,首先回去執行父類的初始化動做。由於子類的構造方法中默認有一個super()。子類要使用父類的成員變量,這個初始化,必須在子類初始化以前完成。因此,子類的初始化過程當中,會先執行父類的初始化。
  2. 若是父類沒有無參構造方法
  • 使用super調用父類的帶參構造。推薦方式。
  • 使用this調用自己的其餘構造。

靜態代碼塊、構造代碼塊,構造方法的執行順序

父類靜態代碼塊→子類靜態代碼塊→父類構造代碼塊→父類構造方法→子類構造代碼塊→子類構造方法

final關鍵字

final是一個關鍵字,能夠用於修飾類,成員變量,成員方法。

特色

  1. 它修飾的類不能被繼承。
  2. 它修飾的成員變量是一個常量。
  3. 它修飾的成員方法是不能被子類重寫的。

final修飾的常量定義通常都有書寫規範,被final修飾的常量名稱,全部字母都大寫

final修飾成員變量,必須初始化,初始化有兩種

  • 顯示初始化;
  • 構造方法初始化。
    可是不能兩個一塊兒初始化

final和private的區別

  1. final修飾的類能夠訪問;
    private不能夠修飾外部類,但能夠修飾內部類(其實把外部類私有化是沒有意義的)。
  2. final修飾的方法不能夠被子類重寫;
    private修飾的方法表面上看是能夠被子類重寫的,其實不能夠,子類是看不到父類的私有方法的。
  3. final修飾的變量只能在顯示初始化或者構造函數初始化的時候賦值一次,之後不容許更改;
    private修飾的變量,也不容許直接被子類或一個包中的其它類訪問或修改,可是他能夠經過set和get方法對其改值和取值。

多態

概念

對象在不一樣時刻表現出來的不一樣狀態。

多態的前提

  • 要有繼承或者實現關係。
  • 要有方法的重寫。
  • 要有父類引用指向子類對象。

程序中的體現
父類或者接口的引用指向或者接收本身的子類對象

好處和做用
多態的存在提升了程序的擴展性和後期可維護性

弊端:
父類調用的時候只能調用父類裏的方法,不能調用子類的特有方法,由於你並不清楚未來會有什麼樣的子類繼承你。

多態的成員特色

  • 成員變量:編譯時期:看引用型變量所屬的類中是否有所調用的變量;
    運行時期:也是看引用型變量所屬的類是否有調用的變量。
    成員變量不管編譯仍是運行都看引用型變量所屬的類,簡單記成員變量,編譯和運行都看等號左邊
  • 成員方法:編譯時期:要查看引用變量所屬的類中是否有所調用的成員;
    運行時期:要查看對象所屬的類中是否有所調用的成員。若是父子出現同名的方法,會運行子類中的方法,由於方法有覆蓋的特性。
    編譯看左邊運行看右邊
  • 靜態方法:編譯時期:看的引用型變量所屬的類中是否有所調用的變量;
    運行時期:也是看引用型變量所屬的類是否有調用的變量。
    編譯和運行都看等號左邊

必定不可以將父類的對象轉換成子類類型!

父類的引用指向子類對象,該引用能夠被提高,也能夠被強制轉換

多態自始至終都是子類對象在變化!

//多態向下轉型和向上轉型的例子,多態轉型解決了多態中父類引用不能使用子類特有成員的弊端。
class PolymorphicTest2 { public static void main(String[] args) { Phone p1 = new Nokia(); //向上轉型,類型提高 Nokia no = (Nokia)p1; //向下轉型,強制將父類的引用轉換成子類類型,不能將Nokia類型轉成Moto或Nexus類型 no.print(); //輸出結果爲Phone---null---0,由於繼承了父類的方法 Phone p2 = new Moto(); Moto m = (Moto)p2; m.print(); //輸出結果爲Moto---yellow---1599,方法重寫,子類方法覆蓋父類方法 Phone p3 = new Nexus(); Nexus ne = (Nexus)p3; ne.print(); } } class Phone{ String color; int price; public void print(){ System.out.println("Phone---" + color + "---" + price ); } } class Nokia extends Phone{ String color = "red"; int price = 1009; //public void print(){ // System.out.println("Nokia---" + color + "---" + price); //} } class Moto extends Phone{ String color = "yellow"; int price = 1599; public void print(){ System.out.println("Moto---" + color + "---" + price); } } class Nexus extends Phone{ String color = "black"; int price = 1999; public void print(){ System.out.println("Nexus---" + color + "---" + price); } } }

抽象(abstract)

抽象就是從多個事物中將共性的,本質的內容抽象出來。

抽象類

Java中能夠定義沒有方法體的方法,該方法的具體實現由子類完成,該方法稱爲抽象方法,包含抽象方法的類就是抽象類。

由來

多個對象都具有相同的功能,可是功能具體內容有所不一樣,那麼在抽取過程當中,只抽取了功能定義,並未抽取功能主體,那麼只有功能聲明,沒有功能主體的方法稱爲抽象方法。

抽象類特色

  1. 抽象方法必定在抽象類中;
  2. 抽象方法和抽象類都必須被abstract關鍵字修飾;
  3. 抽象類不能夠用new建立對象,由於調用抽象方法沒意義;
  4. 抽象類中的抽象方法要被使用,必須由子類複寫其全部的抽象方法後,創建子類對象調用; 若是子類只覆蓋了部分的抽象方法,那麼該子類仍是一個抽象類;
  5. 抽象類中能夠有抽象方法,也能夠有非抽象方法,抽象方法用於子類實例化;
  6. 若是一個類是抽象類,那麼,繼承它的子類,要麼是抽象類,要麼重寫全部抽象方法。
    特殊:抽象類中能夠不定義抽象方法,這樣作僅僅是不讓該類創建對象。

抽象類的成員特色

  • 成員變量:能夠是變量,也能夠是常量;
  • 構造方法:有構造方法;
  • 成員方法:能夠是抽象方法,也能夠是非抽象方法。
abstract class 葵花寶典 { public abstract void 自宮(); } class 嶽不羣 extends 葵花寶典 { public void 自宮(){ System.out.println("剪刀"); } } class 林平之 extends 葵花寶典{ public void 自宮(){ System.out.println("指甲刀"); } } class AbstractTest { public static void main(String[] args) { 嶽不羣 嶽 = new 嶽不羣(); 嶽.自宮(); 林平之 林 = new 林平之(); 林.自宮(); } }

抽象類注意事項

抽象類不能被實例化,爲何還有構造函數

只要是class定義的類裏面就確定有構造函數。抽象類中的函數是給子類實例化的。

一個類沒有抽象方法,爲何定義爲抽象類?

不想被繼承,還不想被實例化。

抽象關鍵字abstract不能夠和哪些關鍵字共存

  • final:若是方法被抽象,就須要被覆蓋,而final是不能夠被覆蓋,因此衝突。
  • private:若是函數被私有了,子類沒法直接訪問,怎麼覆蓋呢?
  • static:不須要對象,類名就能夠調用抽象方法。而調用抽象方法沒有意義。

接口(interface)

接口抽象方法常量值的集合。從本質上講,接口是一種特殊的抽象類,這種抽象類只包含常量和方法的定義,而沒有變量和方法的實現。

格式:interface 接口名{}

接口的出現將」多繼承「經過另外一種形式體現出來,即」多實現「。

實現(implements)

格式:class 類名 implements 接口名 {}

特色

  • 接口不能被實例化。
  • 一個類若是實現了接口,要麼是抽象類,要麼實現接口中的全部方法。

接口的成員特色

接口中的成員修飾符是固定的!

  • 成員常量:public static final,接口裏定義的變量是全局常量,並且修飾符只能是這三個關鍵字,均可以省略,常量名要大寫。
  • 成員方法:public abstract,接口裏定義的方法都是抽象的,兩個修飾符關鍵字可省略。
  • 推薦:永遠手動給出修飾符。

繼承與實現的區別

  • 類與類之間稱爲繼承關係:由於該類不管是抽象的仍是非抽象的,它的內部均可以定義非抽象方法,這個方法能夠直接被子類使用,子類繼承便可。只能單繼承,能夠多層繼承。((class)
  • 類與接口之間是實現關係:由於接口中的方法都是抽象的,必須由子類實現才能夠實例化。能夠單實現,也能夠多實現;還能夠在繼承一個類的同時實現多個接口。((class) extends (class) implements (interface1,interface2…)
  • 接口與接口之間是繼承關係:一個接口能夠繼承另外一個接口,並添加新的屬性和抽象方法,而且接口能夠多繼承。((interface) extends (interface1,interface2…)

抽象類和接口的區別

成員變量

  • 抽象類能有變量也能夠有常量
  • 接口只能有常量

成員方法

  • 抽象類能夠有非抽象的方法,也能夠有抽象的方法
  • 接口只能有抽象的方法

構造方法

-抽象類有構造方法
-接口沒有構造方法

類與抽象類和接口的關係

  • 類與抽象類的關係是繼承 extends
  • 類與接口的關係是實現 implements

接口的思想特色

  1. 接口是對外暴露的規則;
  2. 接口是程序的功能擴展
  3. 接口的出現下降耦合性;(實現了模塊化開發,定義好規則,每一個人實現本身的模塊,大大提升了開發效率)
  4. 接口能夠用來多實現
  5. 多個無關的類能夠實現同一個接口;
  6. 一個類能夠實現多個相互直接沒有關係的接口;
  7. 與繼承關係相似,接口與實現類之間存在多態性
//運動員和教練的案例(下圖是思路分析)

/* 籃球運動員和教練 乒乓球運動員和教練 如今籃球運動員和教練要出國訪問,須要學習英語 請根據你所學的知識,分析出來哪些是類,哪些是抽象類,哪些是接口 */ interface SpeakEnglish { public abstract void speak(); } interface GoAboard{ public abstract void aboard(); } abstract class Person { private String name; private int age; public Person(){} public Person(String name,int age){ this.name = name; this.age = age; } public void setName(String name){ this.name = name; } public String getName(){ return name; } public void setAge(int age){ this.age = age; } public int getAge(){ return age; } //吃飯 public abstract void eat(); //睡覺 public void sleep(){ System.out.println("Zzz..."); } } //運動員 abstract class Player extends Person { public abstract void study(); } //教練 abstract class Coach extends Person { public abstract void teach(); } //籃球運動員 class BasketballPlayer extends Player implements SpeakEnglish,GoAboard{ public void eat(){ System.out.println(getAge() + "歲的" + getName() + "吃雞腿"); } public void study(){ System.out.println(getAge() + "歲的" + getName() + "學扣籃"); } public void speak(){ System.out.println(getAge() + "歲的" + getName() + " Say Hello World"); } public void aboard(){ System.out.println(getAge() + "歲的" + getName() + " Go Aboard"); } } //乒乓運動員 class PingPangPlayer extends Player{ public void eat(){ System.out.println(getAge() + "歲的" + getName() + "吃雞蛋"); } public void study(){ System.out.println(getAge() + "歲的" + getName() + "學扣球"); } } //籃球教練 class BasketballCoach extends Coach implements SpeakEnglish { public void eat(){ System.out.println(getAge() + "歲的" + getName() + "啃雞爪"); } public void teach(){ System.out.println(getAge() + "歲的" + getName() + "教扣籃"); } public void speak(){ System.out.println(getAge() + "歲的" + getName() + " Say Hello Java"); } public void aboard(){ System.out.println(getAge() + "歲的" + getName() + " Go Aboard"); } } //乒乓球教練 class PingPangCoach extends Coach{ public void eat(){ System.out.println(getAge() + "歲的" + getName() + "吃雞蛋皮"); } public void teach(){ System.out.println(getAge() + "歲的" + getName() + "教扣球"); } } class PlayerAndCoach { public static void main(String[] args) { //籃球運動員 BasketballPlayer bp = new BasketballPlayer(); bp.setName("郭艾倫"); bp.setAge(33); bp.eat(); bp.sleep(); bp.study(); bp.speak(); bp.aboard(); System.out.println("***********************"); //籃球教練 BasketballCoach bc = new BasketballCoach(); bc.setName("波波維奇"); bc.setAge(65); bc.eat(); bc.sleep(); bc.teach(); bc.speak(); bc.aboard(); System.out.println("***********************"); //多態 Person p = new BasketballPlayer(); p.setName("Kobe Bryant"); p.setAge(33); p.eat(); p.sleep(); //p.study(); //p.speak(); BasketballPlayer bp2 = (BasketballPlayer)p; bp2.study(); bp2.speak(); bp2.aboard(); System.out.println("***********************"); } }

內部類

將一個類定義在另外一個類裏面,裏面的那個類就稱爲內部類。內部類的出現,再次打破了Java單繼承的侷限性。

訪問特色

  • 內部類能夠直接訪問外部類的成員,包括私有成員。
  • 外部類要訪問內部類的成員,必需要創建內部類的對象。
    內部類分類及共性

共性

  • 內部類仍然是一個獨立的類,在編譯以後會內部類會被編譯成獨立的.class文件,可是前面冠之外部類的類名和$符號。
  • 內部類不能用普通的方式訪問。內部類是外部類的一個成員,所以內部類能夠自由地訪問外部類的成員變量,不管是不是private的。

成員內部類

在外部類中有成員變量和成員方法,成員內部類就是把整個一個類做爲了外部類的成員;
成員內部類是定義在類中方法外的類;
建立對象的格式爲:外部類名.內部類名 對象名 = 外部類對象.內部類對象
成員內部類之因此能夠直接訪問外部類的成員,那是由於內部類中都持有一個外部類對象的引用:外部類名.this
成員內部類能夠用的修飾符有final,abstract,public,private,protected,static.

靜態內部類

靜態內部類就是成員內部類加上靜態修飾符static,定義在類中方法外

在外部類中訪問靜態內部類有兩種場景:

  • 在外部類中訪問靜態內部類中非靜態成員:*外部類名.內部類名 對象名 = 外部類名.內部對象*,須要經過建立對象訪問;
  • 在外部類中訪問靜態內部類中的靜態成員:一樣可使用上面的格式進行訪問,也能夠直接使用外部類名.內部類名.成員

局部內部類

局部內部類是定義在方法中的類。

  • 方法內部類只能在定義該內部類的方法內實例化,不能夠在此方法外對其實例化。
  • 方法內部類對象不能使用該內部類所在方法的非final局部變量。

能夠用於方法內部類的修飾符有final,abstract

靜態方法中的方法內部類只能訪問外部的靜態成員

匿名內部類

匿名內部類是內部類的簡化寫法,是創建一個帶內容的外部類或者接口的子類匿名對象。
前提:
內部類能夠繼承或實現一個外部類或者接口。
格式:
new 外部類名或者接口名(){重寫方法};
一般在方法的形式參數是接口或者抽象類,而且該接口中的方法不超過三個時,能夠將匿名內部類做爲參數傳遞。

不一樣修飾符修飾的內容(和內部類無關)

  成員變量 成員方法 構造方法
private   Y Y Y
默認 Y Y Y Y
protected   Y Y Y
public Y Y Y Y
abstract Y   Y  
static   Y Y Y
final Y Y Y  

注意,常見規則以下:

  • 之後,全部的類都用public修飾。而且,在一個java文件中,只寫一個類。
  • 之後,全部的成員變量用private修飾。
  • 之後,全部的成員方法用public修飾。
    若是是抽象類或者接口:public abstract + …
  • 之後,全部的構造方法用public修飾。
    若是類是工具類或者單例類:構造用private修飾

四種權限修飾符

  本類 同包(無關類或子類) 不一樣包(子類) 不一樣包(無關類)
private Y      
默認 Y Y    
protected Y Y Y  
public Y Y Y Y

推薦:

    • 成員變量 private
    • 構造方法 public
    • 成員方法 public
相關文章
相關標籤/搜索