java基礎(chǔ)-面向?qū)ο?/h1>

面向?qū)ο蠊P記

一、 對(duì)象在內(nèi)存中的存放方法以及被調(diào)用過程

  1. class文件首先被加載到方法區(qū)中的class文件內(nèi)容區(qū)域,類的成員變量成員方法自然也隨著類的加載而被加載到方法區(qū)。
  2. 創(chuàng)建對(duì)象的時(shí)候,首先在棧中開辟空間,用于存放對(duì)對(duì)象的引用地址(即 Phone p的地址);
  3. 在堆中開辟空間存放對(duì)象實(shí)體(即new Phone()),同時(shí)會(huì)給該對(duì)象的屬性分配內(nèi)存空間來存放該對(duì)象的屬性值,即會(huì)把方法區(qū)中該類的成員變量復(fù)制一份到堆內(nèi)存中(首先是默認(rèn)值,然后才是調(diào)用者賦給的值),用于存放該對(duì)象的屬性值,但該類的方法就不會(huì)被復(fù)制到堆中,而是通過堆中一個(gè)指針的引用指向方法區(qū)中該方法。(其實(shí)這一點(diǎn)很好理解,每個(gè)對(duì)象的屬性值不一樣,但是每個(gè)對(duì)象的行為卻是一樣的,因此每個(gè)對(duì)象需要有自己的成員變量來保存自己的屬性值信息,而方法不用,只用調(diào)用同一個(gè)方法即可。)
  4. 在調(diào)用對(duì)象的成員變量時(shí),實(shí)際上是給該成員變量進(jìn)行復(fù)制,因此是在堆中執(zhí)行的。
  5. 在調(diào)用對(duì)象的成員方法時(shí),該方法會(huì)被加載到棧中(實(shí)際上在棧中有個(gè)方法棧專門用來保存對(duì)方法的引用),該方法被調(diào)用完成后,立刻就被銷毀了,因此對(duì)成員方法的調(diào)用發(fā)生在棧內(nèi)存中。

注意:棧的特點(diǎn)是先進(jìn)后出,畫圖的時(shí)候因從下往上,這里只是為了方便解釋,畫圖的時(shí)候從上往下。

  • 一個(gè)對(duì)象的引用圖解


    一個(gè)對(duì)象的內(nèi)存圖解

  • 兩個(gè)對(duì)象的內(nèi)存圖解


    兩個(gè)對(duì)象的內(nèi)存圖解

    注意到:

    1. 兩個(gè)對(duì)象分別有自己的成員變量空間;
    2. 兩個(gè)對(duì)象通過地址指向方法區(qū)的同一個(gè)地址,即成員方法的地址;

  • 三個(gè)對(duì)象的內(nèi)存圖解

    三個(gè)對(duì)象的內(nèi)存圖解

    注意到:兩個(gè)引用指向同一個(gè)對(duì)象時(shí),實(shí)際上是對(duì)同一個(gè)對(duì)像進(jìn)行操作

二、成員變量、局部變量、靜態(tài)變量的區(qū)別

(一) 成員變量和局部變量的區(qū)別

  1. 在類中的位置不同
    • 成員變量:在類中方法外
    • 局部變量:在方法定義中或方法聲明上
  2. 在內(nèi)存中的位置不同
    • 成員變量:在堆內(nèi)存中(對(duì)象的實(shí)體在堆內(nèi)存中,成員變量是跟隨著對(duì)象的實(shí)體,因此也就在堆內(nèi)存中)
    • 局部變量:在棧內(nèi)存中(局部變量在方法內(nèi)部,方法在被調(diào)用的時(shí)候會(huì)被加載到棧中,因此局部變量存在于棧內(nèi)存中)
  3. 生命周期不同(在內(nèi)存中的位置不同,生命周期自然不同)
    • 成員變量:隨著對(duì)象的創(chuàng)建而存在,隨著對(duì)象的消失而消失;
    • 局部變量:隨著方法的調(diào)用而存在,隨著方法的調(diào)用完畢而消失;
  4. 初始化值不同(在內(nèi)存中的位置不同,初始化值自然不同)
    • 成員變量:有默認(rèn)初始值;
    • 局部變量:沒有默認(rèn)初始化值,必須定義、賦值,然后才能使用;

(二)成員變量和靜態(tài)變量的區(qū)別

  1. 所屬不同
    • 成員變量:屬于對(duì)象,也叫實(shí)例變量(對(duì)象變量)
    • 靜態(tài)變量:屬于類,也叫類變量
  2. 內(nèi)存中位置不同
    • 成員變量:隨著對(duì)象的創(chuàng)建而存在于堆內(nèi)存中;
    • 靜態(tài)變量:隨著類的加載而存在于方法區(qū)的靜態(tài)區(qū)
  3. 生命周期不同
    • 成員變量:隨著對(duì)象的創(chuàng)建而存在,隨著對(duì)象的消失而消失;
    • 靜態(tài)變量:隨著的加載而加載,隨著類的消失而消失;
  4. 調(diào)用不同
    • 成員變量:只能通過對(duì)象名來調(diào)用;
    • 靜態(tài)變量:即可以通過類名來調(diào)用,也可以通過對(duì)象名來調(diào)用;

(三)靜態(tài)變量和局部變量的區(qū)別

  • 這個(gè)區(qū)別太明顯,不做區(qū)分;

注意事項(xiàng):因?yàn)樵趦?nèi)存中的位置不同,所以要注意形式參數(shù)問題

  1. 基本類型:形式參數(shù)的改變不影響實(shí)際參數(shù)
  2. 引用類型:形式參數(shù)的改變直接影響實(shí)際參數(shù)

三、構(gòu)造方法

構(gòu)造方法的注意事項(xiàng)

  1. 默認(rèn)構(gòu)造方法問題:
    1. 如果在類中沒有定義構(gòu)造方法,系統(tǒng)將自動(dòng)提供一個(gè)無參構(gòu)造方法;
    2. 如果在類中定義了構(gòu)造方法,系統(tǒng)將不再提供默認(rèn)的無參構(gòu)造方法;
  2. 構(gòu)造方法的重載問題:
    1. 只要我們給出了構(gòu)造方法,不管是無參還是代參構(gòu)造方法,系統(tǒng)都不在提供構(gòu)造方法,如果我們想使用無參構(gòu)造方法,就必須自己定義聲明;
    2. 建議永遠(yuǎn)自己給出無參構(gòu)造方法;

四、Student s=new Student()做了哪些事情

  1. Student.class文件加載到內(nèi)存中方法區(qū)的class文件區(qū)域
  2. 棧內(nèi)存中給s變量開辟一個(gè)內(nèi)存空間;
  3. 堆內(nèi)存中給new Student()對(duì)象申請(qǐng)一個(gè)空間;
  4. 成員變量進(jìn)行默認(rèn)初始化
  5. 成員變量進(jìn)行顯示初始化
  6. 成員變量進(jìn)行構(gòu)造方法初始化(即通過構(gòu)造方法給成員變量進(jìn)行初始化);
  7. 對(duì)象初始化完畢,把堆內(nèi)存地址值賦值給s變量;
  • 總結(jié):
    1. 構(gòu)造方法對(duì)類進(jìn)行初始化實(shí)際上是對(duì)類中的數(shù)據(jù)(即成員變量)進(jìn)行初始化;
    2. 對(duì)成員變量進(jìn)行初始化的時(shí)候,首先默認(rèn)初始化,然后是顯示初始化,最后才是構(gòu)造方法初始化
      1. 默認(rèn)初始化實(shí)際上就是給數(shù)據(jù)賦默認(rèn)值(即0,false,null,'\u0000',0.0f,0.0d,...)的過程,
      2. 顯示初始化實(shí)際上就是把手動(dòng)賦值的值賦值給成員變量,比如private int num=1;這個(gè)1就是顯示初始化,
      3. 構(gòu)造方法初始化就是通過構(gòu)造方法傳遞過來的值對(duì)成員變量進(jìn)行初始化;
        - 因此才是這個(gè)初始化順序,即默認(rèn)初始化--->顯示初始化--->構(gòu)造方法初始化

五、 成員變量的定義規(guī)則##

  1. 變量什么時(shí)候定義成成員變量?
    • 如果這個(gè)變量是用來修飾這個(gè)類的信息的,那么該變量就應(yīng)該定義為成員變量;
  2. 變量定義在哪里好呢?
    • 變量的范圍越小越好,因?yàn)槟芗皶r(shí)被回收;

六、static 關(guān)鍵字

  1. 特點(diǎn):
    1. 隨著類的加載而加載;
      • 因此被static修飾的成員變量/成員方法也叫類成員
    2. 優(yōu)先于對(duì)象而存在;(由第一點(diǎn)就可以推出第二點(diǎn))
      • 自然也就優(yōu)先于對(duì)象的成員變量和成員方法而存在;
    3. static修飾的成員變量成員方法被類的所有對(duì)象共享;
      • 即一個(gè)對(duì)象修改了某個(gè)成員變量的值,其他對(duì)象該成員變量的值也被修改了;
      • 這是我們判斷是否使用static關(guān)鍵字的條件;
        • 即如果某個(gè)成員變量或成員方法是被所有對(duì)象共享的,那么這個(gè)成員變量或成員方法就應(yīng)該被定義為靜態(tài)的;
    4. 因?yàn)殡S著類的加載而加載,所以可以直接通過類名來調(diào)用,不用通過對(duì)象來調(diào)用(當(dāng)然也可以通過對(duì)象名來調(diào)用);
  2. 注意事項(xiàng):
    1. 在靜態(tài)方法中沒有this關(guān)鍵字;
    2. 靜態(tài)方法只能訪問靜態(tài)的成員變量靜態(tài)的成員方法
      • 即靜態(tài)只能訪問靜態(tài),非靜態(tài)可以訪問靜態(tài)和非靜態(tài);
  3. static內(nèi)存圖解

static內(nèi)存圖解

注意到:

  1. static修飾的方法(如main方法)不用創(chuàng)建對(duì)象直接通過靜態(tài)方法區(qū)加載到棧內(nèi)存中;
  2. 當(dāng)成員變量被static修飾的時(shí)候,該成員變量就存在于靜態(tài)方法區(qū)靜態(tài)區(qū),而不是堆中,對(duì)象通過地址來指向該變量,這里就是靜態(tài)標(biāo)記,而類的成員方法不被static修飾時(shí),存放在靜態(tài)方法區(qū)的該對(duì)象專有的方法區(qū),通過地址值指向這些方法,這就是方法標(biāo)記
  3. 靜態(tài)方法區(qū)中的靜態(tài)區(qū)專門用來存放被static修飾的變量和方法,同時(shí)在方法區(qū)中專門有一個(gè)區(qū)域用來存放類的構(gòu)造方法非靜態(tài)成員方法

七、JVM內(nèi)存簡單區(qū)分

    • 特點(diǎn):
      1. 每個(gè)線程都包含一個(gè)棧區(qū),每個(gè)棧中的數(shù)據(jù)(基本類型,引用類型)都是私有的,其他棧不能訪問,所以線程中的數(shù)據(jù)也是私有的;
      2. 棧中只存放基本數(shù)據(jù)類型以及引用數(shù)據(jù)類型的引用;
    • 特點(diǎn):
      1. JVM只有一個(gè)堆區(qū)(heap),且被所有線程共享;
      2. 堆內(nèi)存中存放的全是對(duì)象,且每個(gè)對(duì)象都包含一個(gè)與之對(duì)應(yīng)的class的信息(class的目的是為了得到操作指令);
  1. 靜態(tài)方法區(qū)

    • 特點(diǎn):
      1. 被所有的線程共享;
      2. 靜態(tài)方法區(qū)中包含的都是在整個(gè)程序中永遠(yuǎn)唯一的元素,如所有的class文件,static修飾的變量;
    • 靜態(tài)方法區(qū)細(xì)分:
      1. class文件區(qū)域
        • 特點(diǎn):
        1. java編譯生成的所有class文件首先被加到該區(qū)域,然后該class文件中的成員信息再被加載到棧或者堆中;
      2. 靜態(tài)區(qū)
        • 特點(diǎn):
        1. 所有被`static`修飾的`變量`和`方法`存放區(qū)域,通過地址值進(jìn)行引用;
        
      3. 方法區(qū)
        • 特點(diǎn):
          1. 對(duì)象的構(gòu)造方法非靜態(tài)方法存放區(qū)域,通過地址值進(jìn)行引用;
      4. 常量池
        • 特點(diǎn):
          1. 存放一些常量;

八、代碼塊

  • 定義:在java中,用{}括起來的代碼被稱為代碼塊,根據(jù)位置和聲明的不同,可以被分為以下幾類:
    1. 局部代碼塊
      • 在方法中出現(xiàn),用于限定變量生命周期,及早釋放,提高內(nèi)存利用率;
    2. 構(gòu)造代碼塊
      • 定義:在構(gòu)造方法的位置(即類中成員位置),用{}括起來的代碼。每次調(diào)用構(gòu)造方法前,都會(huì)先執(zhí)行構(gòu)造代碼塊,即先執(zhí)行構(gòu)造代碼塊,再執(zhí)行構(gòu)造方法;
      • 作用:
        1. 可以把多個(gè)構(gòu)造方法中相同的代碼放到一起,提高代碼復(fù)用性;
        2. 對(duì)對(duì)象進(jìn)行初始化
      • 說明:每調(diào)用一次構(gòu)造方法,構(gòu)造代碼塊就會(huì)被執(zhí)行一次,因此構(gòu)造代碼塊會(huì)被執(zhí)行多次;
    3. 靜態(tài)代碼塊
      • 定義:在類中成員位置,用{}括起來的代碼,并且加了static修飾;
      • 作用:對(duì)類進(jìn)行初始化
      • 說明:靜態(tài)代碼塊只執(zhí)行一次;
    4. 同步代碼塊
      • 定義: 在方法中出現(xiàn),用{}括起來的代碼,被synchroized修飾的代碼塊;
      • 作用:在多線程中保證{}中的代碼是原子性操作,即保證線程安全;
  • 注意:
    1. 靜態(tài)代碼塊,構(gòu)造代碼塊,構(gòu)造方法的執(zhí)行順序
      • 靜態(tài)代碼塊 > 構(gòu)造代碼塊 > 構(gòu)造方法
    2. 靜態(tài)代碼塊,構(gòu)造代碼塊,構(gòu)造方法的執(zhí)行次數(shù)
      • 靜態(tài)代碼塊:只執(zhí)行一次;
      • 構(gòu)造代碼塊:執(zhí)行多次,構(gòu)造方法被調(diào)用幾次,構(gòu)造代碼塊就執(zhí)行幾次;
      • 構(gòu)造方法:執(zhí)行多次;

九、繼承

1. 繼承注意事項(xiàng)

  1. 父類的私有成員(成員變量,成員方法)不能被繼承;
  2. 子類不能繼承父類的構(gòu)造方法,但是可以通過super關(guān)鍵字訪問父類的構(gòu)造方法;
  3. 不要為了部分功能而去繼承;
  4. 繼承使用條件:是兩個(gè)對(duì)象是集合中的屬于關(guān)系時(shí)(兩個(gè)類之間如果可以用is a來表述),就可以使用繼承;

2.繼承中類中成員之間的關(guān)系

1)繼承中成員變量之間的關(guān)系

  1. 當(dāng)子類和父類中的成員變量名稱一樣時(shí),遵循就近原則,即
    1. 首先到子類的局部變量中找,有就使用,沒有執(zhí)行下一步;
    2. 在子類的成員變量中找,有就使用,沒有執(zhí)行下一步;
    3. 在父類的的成員變量中找,有就使用,沒有就報(bào)錯(cuò);

2)繼承中構(gòu)造方法之間的關(guān)系

  1. 子類中所有的構(gòu)造方法默認(rèn)都會(huì)訪問父類的空參構(gòu)造方法
    • 因?yàn)樽宇悤?huì)繼承父類中的數(shù)據(jù),可能還會(huì)使用父類的數(shù)據(jù)。所以子類初始化之前,一定要先完成父類數(shù)據(jù)的初始化;
    • 子類每個(gè)構(gòu)造方法的第一條語句默認(rèn)是super();,不寫也默認(rèn)有;
  2. 如果父類沒有無參構(gòu)造方法,那么子類的構(gòu)造方法就會(huì)報(bào)錯(cuò),解決方法:
    1. 方法一:在父類中加一個(gè)無參構(gòu)造方法;
    2. 方法二:通過super(...)去顯式調(diào)用父類的帶參構(gòu)造方法;
    3. 方法三:子類通過this去調(diào)用本類的其他構(gòu)造方法,從而間接調(diào)用父類的構(gòu)造方法;
    • 總結(jié):
      1. 子類中一定要有一個(gè)構(gòu)造方法去訪問父類的構(gòu)造方法,否則父類數(shù)據(jù)就無法初始化;
      2. 實(shí)際上這里是分層初始化,即先初始化爺爺類,在初始化父親類,最后才是初始化子類,而super()僅僅表示先初始化父類;
    • 注意事項(xiàng):

    this(...)或者super(...)必須出現(xiàn)在第一條語句上;

    如果不是放在第一條語句上,就可能對(duì)父類的數(shù)據(jù)進(jìn)行了多次初始化,所以必須放在第一條語句上;

4)繼承中成員方法的關(guān)系

  1. 方法重寫(和方法重載分開):
    • 子類中出現(xiàn)了和父類中一模一樣的方法聲明(即返回值類型,方法名,參數(shù)列表均相同);
    • 使用特點(diǎn):
      1. 在訪問重寫方法時(shí),如果子類有就先訪問子類的,子類中沒有,就到父類中找,如果沒有找到,就報(bào)錯(cuò);

      簡單記:就近原則,先找自己的,有就用;如果沒有再找父類的;

  2. 什么時(shí)候使用方法重寫:
    • 當(dāng)子類需要父類的功能,而功能主體子類有自己特有內(nèi)容時(shí),可以重寫父類中的方法,這樣既沿襲了父類的功能(通過super.成員方法()來調(diào)用父類的功能),又定義了子類特有的功能;
  3. 方法重寫注意事項(xiàng):
    1. 父類的私有方法不能被重寫;

      因?yàn)楦割愃接蟹椒ň筒荒鼙焕^承,自然就不能被重寫;
      2. 子類重寫父類的方法時(shí),訪問權(quán)限不能更低,即子類方法的訪問權(quán)限必須大于等于父類方法的訪問權(quán)限;
      >子類重寫父類方法的時(shí)候,最好聲明一模一樣。
      3. 父類是靜態(tài)方法,子類也必須通過靜態(tài)方法進(jìn)行重寫
      >父類是靜態(tài),子類重寫時(shí)也必須是靜態(tài),否則會(huì)報(bào)錯(cuò);
      >
      >父類是非靜態(tài),子類重寫時(shí)也必須是非靜態(tài),否則會(huì)報(bào)錯(cuò);

5)thissuper的區(qū)別與聯(lián)系

  1. 表示的意義

    • this: 代表本類對(duì)象的引用;
    • super:代碼父類對(duì)象的引用(實(shí)際上是父類存儲(chǔ)空間的標(biāo)識(shí));
  2. 用法

    • 訪問成員變量

    //表示訪問本類的成員變量

    this.成員變量

    //表示訪問本類的成員變量

    super.成員變量
    - 訪問構(gòu)造方法
    >//表示訪問本類的構(gòu)造方法
    >
    >this(...)
    >
    >//表示訪問父類的構(gòu)造方法,雖然不能繼承父類的構(gòu)造方法,但是可以通過super來訪問
    >
    >//實(shí)際開發(fā)中,經(jīng)常使用這種方法給父類的參數(shù)賦值,而且即使父類的參數(shù)是private修飾的,也不影響通過子類進(jìn)行賦值;
    >
    >super(...)

    • 訪問成員方法

    //表示訪問本類的成員方法

    this.成員方法()

    //表示訪問父類的成員方法

    super.成員方法()

成員變量屬于每個(gè)對(duì)象 (而不是類)私有的值,它表征了該對(duì)象的某種狀態(tài),因此父類的成員變量子類可以訪問,卻不能修改,而成員方法表征了某一系列對(duì)象所具有的行為,因此子類可以覆蓋父類的方法,實(shí)現(xiàn)自己的特有的功能,但是JVM是如何實(shí)現(xiàn)方法重寫時(shí),調(diào)用的是子類的方法的了?

十、final關(guān)鍵字

  1. final使用場景
    • 如果父類的某個(gè)成員變量只能被子類訪問,但是不能被修改值;
    • 如果父類的某個(gè)成員方法只能被子類調(diào)用,但是不能被子類重寫,
    • 如果某個(gè)就是最終類,不能有子類;
  2. final特點(diǎn):final可以修飾成員變量成員方法
    1. final修飾,該類不能被繼承;
    2. final修飾成員變量,這個(gè)成員變量只能被使用,不能被子類重新賦值;

      當(dāng)一個(gè)變量被final修飾時(shí),不能修改實(shí)際上就是常量,這是自定義常量,
      字面值常量就是字符串,true,10這種形式的;
      3. final修飾成員方法,這個(gè)成員方法只能被調(diào)用,不能被子類重寫;

  3. final修飾局部變量
    1. 首先final可以修飾局部變量;

      區(qū)別于private等權(quán)限修飾符,這四個(gè)權(quán)限修飾符不能修飾局部變量,因?yàn)榫植孔兞勘緛砭椭荒茉诜椒▋?nèi)部可以使用,方法外部不能使用,即本來就被封裝起來了,權(quán)限修飾符再來修飾沒有任何意義。
      2. final修飾基本數(shù)據(jù)類型時(shí),基本類型的值不能發(fā)生改變;
      3. final修飾引用數(shù)據(jù)類型時(shí),引用類型的地址值不能發(fā)生改變,但是該對(duì)象的堆內(nèi)存的值是可以改變的,即該對(duì)象的成員變量的值是可以改變的,成員方法是可以被重寫的;

  4. final修飾變量的初始化時(shí)機(jī)
    1. final修飾的變量只能賦值一次;
    2. 對(duì)于非靜態(tài)常量而言,賦值在構(gòu)造方法完畢之前完成;

    即case 1:如果被final修飾的變量已經(jīng)賦值(例如private int num=10;),就不能在構(gòu)造方法中給該常量賦值,否則會(huì)報(bào)錯(cuò),

    case 2:如果被final修飾的變量未賦值(例如private int num;),可以在構(gòu)造代碼塊中賦值,但不能再在構(gòu)造方法中賦值,否則會(huì)報(bào)錯(cuò);

    case 3:如果被final修飾的變量未賦值(例如private int num;),同時(shí)也沒有在構(gòu)造代碼塊中賦值,就可以在構(gòu)造方法中賦值,此時(shí)不會(huì)報(bào)錯(cuò);

十一、多態(tài)

1. 多態(tài):同一個(gè)事物(對(duì)象),在不同時(shí)刻體現(xiàn)出來的不同狀態(tài)

2. 多態(tài)的前提:

  1. 要有繼承關(guān)系;
  2. 要有方法重寫;
  3. 要有父類引用指向子類對(duì)象;

    Fu f=new Zi();

3. 多態(tài)中的成員訪問特點(diǎn)

  1. 成員變量
>編譯能否通過看左邊,運(yùn)行看左邊;
>
>成員變量不存在重寫概念,所以只能訪問的父類的成員變量;
  1. 構(gòu)造方法
>在創(chuàng)建子類對(duì)象(調(diào)用子類構(gòu)造方法)的時(shí)候,會(huì)默認(rèn)訪問父類的構(gòu)造方法(會(huì)先對(duì)父類進(jìn)行初始化),對(duì)父類的數(shù)據(jù)進(jìn)行初始化;
  1. 成員方法
>編譯能否通過看左邊,運(yùn)行看右邊;
>
>由于父類的成員方法可以子類重寫,所以實(shí)際上調(diào)用的是子類的方法;
  1. 靜態(tài)方法
>編譯能否通過看左邊,運(yùn)行看左邊
>
>靜態(tài)和類相關(guān),算不上重寫,所以訪問還是父類的;

總結(jié):由于成員方法存在重寫,所以他運(yùn)行看子類的,成員變量靜態(tài)方法均不存在重寫概念,所以運(yùn)行看父類的

4. 多態(tài)的優(yōu)點(diǎn)與缺點(diǎn)

1)優(yōu)點(diǎn)

  1. 提高了代碼的維護(hù)性(通過繼承實(shí)現(xiàn));

  2. 提高了代碼的擴(kuò)展性(通過多態(tài)保證);

    由于子類可以重寫父類的方法,所在在父類中調(diào)用父類的方法,在子類中重寫這些方法,這樣就保證了擴(kuò)展性

     //父類
     class Animal {
        public void eat(){
           System.out.println("eat");
        }
    
        public void sleep(){
           System.out.println("sleep");
        }
     }
    
     class Dog extends Animal {
        public void eat(){
           System.out.println("狗吃肉");
        }
    
        public void sleep(){
           System.out.println("狗站著睡覺");
        }
     }
    
     class Cat extends Animal {
        public void eat() {
           System.out.println("貓吃魚");
        }
    
        public void sleep() {
           System.out.println("貓趴著睡覺");
        }
     }
     
     class AnimalTool {
         private AnimalTool(){}
         
         //這里就體現(xiàn)出了由于多態(tài)而保證擴(kuò)展性,如果這里傳入Cat,Dog,就沒有擴(kuò)展性了,
         //每新添加一個(gè)Animal的子類,就需要把這個(gè)方法復(fù)制一份,擴(kuò)展性就差了
         //擴(kuò)展性就體現(xiàn)在這里傳入的是Animal,而不是Animal的子類      
         public static void useAnimal(Animal a) {
             a.eat();
             a.sleep();
         }
     }
    

2)缺點(diǎn)

  1. 不能使用子類中的特有功能;
    • 解決:將父類的引用強(qiáng)制轉(zhuǎn)換成對(duì)子類的引用(向下轉(zhuǎn)型);

      對(duì)象間的轉(zhuǎn)型問題

      向上轉(zhuǎn)型

      Fu f=new Zi();

      向下轉(zhuǎn)型

      Zi zi=(Zi)f;

3)多態(tài)繼承中內(nèi)存圖解

多態(tài)繼承中內(nèi)存圖解
  1. 這里應(yīng)該可以理解super表示父類存儲(chǔ)空間的標(biāo)識(shí)這句話了吧;
  2. JVM是如何實(shí)現(xiàn)方法重寫時(shí),調(diào)用的是子類的方法的了?當(dāng)沒有重寫時(shí),調(diào)用的是父類的方法了?這里不明白;

4)多態(tài)中的對(duì)象變化內(nèi)存圖解

多態(tài)中的對(duì)象變化內(nèi)存圖解

注意:

  1. ClassCastException是在運(yùn)行時(shí)才拋出的,因?yàn)樵诰幾g的時(shí)候,地址的指向沒有出錯(cuò),類是在運(yùn)行時(shí)才加載到內(nèi)存中去的,因此才會(huì)檢測類的相關(guān)信息;

5)多態(tài)的種類

  1. 具體類多態(tài)(基本沒用)

    即左邊是一個(gè)具體類,右邊是具體類的子類

  2. 抽象類多態(tài)(常用)

    即左邊是一個(gè)抽象類,右邊是抽象類的具體實(shí)現(xiàn)類

  3. 接口類多態(tài) (用的最多)

    即左邊是一個(gè)接口,右邊是接口的具體實(shí)現(xiàn)類

十二、抽象類

(一)為什么會(huì)有抽象類

由于現(xiàn)實(shí)世界的復(fù)雜性,有些事物雖然是對(duì)象,但是是對(duì)一類事物的總結(jié)(如水果,動(dòng)物),本身是一個(gè)抽象的對(duì)象,沒有具體的屬性值和具體的功能實(shí)現(xiàn),如果這個(gè)時(shí)候我們給這種對(duì)象具體屬性值和具體的功能,就違反了對(duì)現(xiàn)實(shí)事物的描述,所以是不對(duì)的,因此我只能對(duì)這種事物進(jìn)行聲明,表明他有某個(gè)功能,只要是這個(gè)事物的子類,就一定有這個(gè)功能,就要實(shí)現(xiàn)這個(gè)功能,這就是抽象類的來源;

(二)抽象類的特點(diǎn)

  1. 抽象類和抽象方法必須用abstract來修飾;
  2. 抽象類中不一定有抽象方法,但是有抽象方法的類一定是抽象類;
  3. 抽象類不能實(shí)例化,即不能用抽象類來創(chuàng)建對(duì)象;
    1. 因?yàn)槌橄箢惒皇蔷唧w的,不能造出具體的對(duì)象,否則就違反了現(xiàn)實(shí)上面的說明;
    2. 但是抽象類是有構(gòu)造方法的,只是不能實(shí)例化對(duì)象而已;
    3. 抽象類的構(gòu)造方法專門用來給子類訪問,對(duì)父類進(jìn)行數(shù)據(jù)初始化;
  4. 抽象類的子類
    1. 如果不想重寫抽象方法,該子類可以是個(gè)抽象類;
    2. 如果子類是一個(gè)具體的類,就必須重寫所有的抽象方法;
  5. 抽象類的實(shí)例化是通過具體的子類來實(shí)現(xiàn)的,是多態(tài)的方式,因此多態(tài)的所有特點(diǎn),使用規(guī)則均適合抽象的實(shí)例化;

(三)抽象類的成員特點(diǎn)

  1. 成員變量
    • 既可以有變量,也可以有常量;(要和接口做區(qū)別)
  2. 構(gòu)造方法
    • 有構(gòu)造方法,用于子類訪問父類數(shù)據(jù)的初始化;
  3. 成員方法
    • 抽象方法:強(qiáng)制要求子類做的事情
    • 非抽象方法:子類繼承的事情,提高代碼復(fù)用性;

(四)抽象類的注意事項(xiàng)

  1. 一個(gè)抽象類中可以沒有抽象方法,這樣做是為了不然抽象類創(chuàng)建對(duì)象(抽象類本來就不能創(chuàng)建對(duì)象),必須由其具體實(shí)現(xiàn)類創(chuàng)建對(duì)象
  2. abstract關(guān)鍵字不能和那些關(guān)鍵字一起出現(xiàn)
    1. abstract不能和private一起出現(xiàn)

      沖突,abstract修改的方法必須由具體子類實(shí)現(xiàn),而private修飾的方法,子類無法訪問;
      2. abstractfinal不能一起出現(xiàn)
      >沖突,abstract修飾的方法必須由具體子類實(shí)現(xiàn),而final修飾的方法不能被子類重寫;
      3. abstractstatic不能一起出現(xiàn)
      >無意義,abstract修飾的方法沒有方法體,而static修飾的方法可以直接用類名調(diào)方法,這樣相當(dāng)于調(diào)的空方法;
      4. 抽象類中的非抽象方法可以用static修飾,這樣用類名調(diào)方法就不會(huì)出現(xiàn)上述問題;

十三、接口

(一)接口的作用

提高事物功能的擴(kuò)展性,彌補(bǔ)類的不足;

比如被訓(xùn)練的猴子可以表演雜技,但是表演雜技并不是動(dòng)物和猴子固有的功能,因此不能寫到動(dòng)物類,猴子類,只能是被訓(xùn)練過的猴子擁有表演雜技的功能,這種表演雜技的功能就是額外的功能,既然不能寫在類中,就通過接口實(shí)現(xiàn)這種功能;

(二)接口的特點(diǎn)

  1. 接口不能被實(shí)例化

    接口中的方法都是抽象的,不給出具體實(shí)現(xiàn);(JDK 8中接口中的方法可以有方法實(shí)現(xiàn))

    接口的實(shí)例化通過具體子類來實(shí)現(xiàn),即通過多態(tài)的方式來實(shí)例化;

  2. 接口的子類
    1. 接口的子類可以是抽象類,但是沒有意義
    2. 接口的子類可以是具體類,但是必須實(shí)現(xiàn)所有的抽象方法;

(三)接口的成員特點(diǎn)

  1. 成員變量
    • 接口中的變量默認(rèn)public static final修飾,即接口中的成員變量只能是常量;
  2. 構(gòu)造方法
    • 接口沒有構(gòu)造方法,因?yàn)榻涌谥饕菙U(kuò)展功能的,而沒有具體存在,必須依附于某個(gè)主體(實(shí)際上就是對(duì)象);

    所有的類都默認(rèn)繼承Object類,而Object類唯一構(gòu)造方法就是Object(),因此如果在接口的實(shí)現(xiàn)類的構(gòu)造方法中如果出現(xiàn)super()時(shí),并不是訪問的接口的接口的構(gòu)造方法(接口本來就沒有構(gòu)造方法),而是訪問的是Object類的構(gòu)造方法;

  3. 成員方法
    • 只能是抽象方法,而且默認(rèn)public abstract修飾;

注意:類與類之間只能是單繼承關(guān)系,但是接口與接口之間可以是多繼承的關(guān)系,即一個(gè)接口可以繼承自多個(gè)接口;

(四)接口與抽象類的區(qū)別

  1. 成員不同
    • 抽象類
      1. 成員變量:可以是變量,也可以是常量;
      2. 構(gòu)造方法:有
      3. 成員方法:可以有抽象方法,也可以有非抽象方法;
    • 接口
      1. 成員變量:只能是常量;
      2. 構(gòu)造方法:無
      3. 成員方法:只能是抽象方法;
  2. 關(guān)系不同
    • 類與類:繼承,單繼承;
    • 類與接口:實(shí)現(xiàn),可以多實(shí)現(xiàn);
    • 接口與接口:單繼承,多繼承均可;
  3. 設(shè)計(jì)理念不同
    • 抽象類:被繼承體現(xiàn)的是is a的關(guān)系,抽象類中定義的是該繼承體系中的共性功能
    • 接口:被實(shí)現(xiàn)體現(xiàn)的是like a(像什么)的關(guān)系,接口中定義的是該繼承體系的擴(kuò)展功能(個(gè)性功能)

十四、內(nèi)部類

(一)內(nèi)部類的訪問特點(diǎn)

  1. 內(nèi)部類可以直接訪問外部類的成員,包括private修飾的成員;
  2. 外部類要訪問內(nèi)部類的成員,必須創(chuàng)建內(nèi)部類對(duì)象;

(二)成員內(nèi)部類特點(diǎn)

  1. 如何直接訪問內(nèi)部類的成員變量,成員方法;

    外部類名.內(nèi)部類名 對(duì)象名=外部類對(duì)象.內(nèi)部類對(duì)象;

    Outer.Innner oi=new Outer().new Inner();

  2. 內(nèi)部類用private修飾(為了保證數(shù)據(jù)安全),這時(shí)內(nèi)部類就不能被訪問,通常做法是,在外部類中定義一個(gè)方法,在方法內(nèi)部訪問內(nèi)部類(當(dāng)然有邏輯控制),這樣就可以通過外部類來訪問內(nèi)部類;
  3. 當(dāng)內(nèi)部類被static修飾時(shí)(這樣做是為了方便數(shù)據(jù)訪問),內(nèi)部類就不能訪問外部類非靜態(tài)成員,因?yàn)殪o態(tài)只能訪問靜態(tài);

    成員內(nèi)部類被static修飾時(shí),訪問方式為

    外部類名.內(nèi)部類名 對(duì)象名=new 外部類名.內(nèi)部類名();
    Outer.Inner oi=new Outer.Inner();

  4. 內(nèi)部類的方法訪問外部類的成員:通過外部類名限定this對(duì)象;Outer.this.method()Outer.this.params

(三)局部內(nèi)部類

  1. 可以直接訪問外部類的成員;
  2. 在局部位置(即方法內(nèi)部),可以創(chuàng)建內(nèi)部類對(duì)象,通過對(duì)象名調(diào)用內(nèi)部類方法,來使用局部內(nèi)部類的功能;
  3. 局部內(nèi)部類訪問局部變量時(shí),局部變量必須被final修飾;
    • 因?yàn)榫植孔兞侩S著方法的調(diào)用而調(diào)用,隨著方法的調(diào)用結(jié)束而消失,而堆內(nèi)存的內(nèi)容并不會(huì)立即消失,所以通過final修飾變成常量,即使局部變量消失了,常量的值還存在,依然可以使用。實(shí)際上,通過反編譯class文件可以發(fā)現(xiàn),被final修飾的局部變量,在內(nèi)部類中直接是常量,而不是局部變量的變量名。

(四)匿名內(nèi)部類

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,401評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,635評(píng)論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,128評(píng)論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,365評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,881評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,733評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,935評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,172評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評(píng)論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,595評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,908評(píng)論 2 372