java基本功16課:(2)對象與內(nèi)存控制

前言

上一節(jié)提到了實例變量和實例對象的區(qū)別,那么這節(jié)就繼續(xù)深入一下變量以及對象。
主要內(nèi)容:

  • 實例變量和類變量
  • 父,子類實例變量和內(nèi)存分配機制
  • final 的注意事項

1. 實例變量和類變量

1.1 定義

  • 實例變量:在類里面沒有使用static修飾的變量,例如:int i;也稱為非靜態(tài)變量
  • 類變量:在類里面使用了static修飾的變量,例如:static int i; 也稱為靜態(tài)變量

1.2 區(qū)別

  • 首先在同一個JVM內(nèi)每個類對應(yīng)一個Class對象,也就是說,只會給該類劃分一次內(nèi)存空間,因此類變量才會只有一次初始化。相對于實例變量,當(dāng)每次建立對象(實例),都會劃分一塊新的內(nèi)存空間。
    所以,所有的該類的實例對象,都是共用一個類變量。

1.3 初始化

  • 首先看一段代碼
class test{
    //1.weight 初始化的值是多小
    double weight=2.3;
    {
        weight=4.3;
    }   
    test(){
        this.weight=4.6;
    }


    // 2.向前引用(為什么)
    int num1=num2+2;
    static int num2=4;
    

    // 3.請說出name 初始化的值應(yīng)該是什么
    static{
        name="我愛java";
    }
    static String name="給我丶鼓勵";


}

  • 有答案了嗎?有疑問嗎?
    • 首先得把該類的初始化過程理解清楚。第一步是建立劃分一個類對象的內(nèi)存空間,然后把變量初始化(優(yōu)先是把類變量給初始化,然后再到實例變量初始化)。第二步,再對變量進(jìn)行賦值,在賦值的過程中,是按照代碼順序由上往下賦值的。
    • 在了解完類初始化過程之后,第一個問題weight=4.6就很顯然了。但是有趣的事,在編譯的時候,是可以看到,其實編輯器是把weight=2.3,和非靜態(tài)代碼塊放在構(gòu)造方法里面了。順序是由上往下排,所以結(jié)果還是4.6而已。
    • 為什么可以向前引用呢?那是因為在類初始化的時候,類變量是優(yōu)先與實例變量初始化的,所以才可以向前引用。
    • name=“給我丶鼓勵”,為什么呢?因為這里就很好地解釋了初始化其實是兩步。變量先初始化默認(rèn)的值,例如int 是0,然后再把變量給賦值。所以name=null,然后name="我愛java",然后name="給我丶鼓勵"。

2. 父,子類實例變量和內(nèi)存分配機制

2.1 繼承的初始化

  • 先看代碼
class father{
    int age=44;

   //構(gòu)造方法
    father(){
        System.out.println("父類的構(gòu)造輸出"+this.age);
        this.say();
    }
    public void say(){
        System.out.println("父類的say"+this.age);
    }
}

class son extends father{
    int age=33;
   //構(gòu)造方法
    son(){
      System.out.println("子類構(gòu)造方法");
    }
    public void say(){
        System.out.println("子類的say:"+this.age);
    }
}

public class second{
    public static void main(String[] ages){
       son myson=new son();

    }
}
  • 你覺得會輸出什么?
    • 答案是
父類的構(gòu)造輸出44
子類的say:0
子類構(gòu)造方法
  • 為什么同一個this。第一行輸出的是父類的44而第二行是子類的方法,而且是0呢? 這個首先涉及繼承的初始化問題,以及繼承變量的方法和變量的區(qū)別了。
  • 首先在初始化的時候,是優(yōu)先把父類給初始化,因為在子類構(gòu)造函數(shù)中,是先調(diào)用super()方法,此方法是把父類初始化。所以是整個初始化過程是 fater->son。所以首先輸出的是:父類的構(gòu)造方法輸出44;
  • 為什么第二句是子類的say:0呢?
"因為子類son把父類的say()重寫了,因此,當(dāng)調(diào)用的時候,是調(diào)用子類的say()的。"

恩~其實這個說話不正確的。首先需要理解這個this是誰。其實這個this是son。不信?

System.out.println(this.getClass());

輸出結(jié)果是:class son 。
所以,this.say()調(diào)用的自然是son的say()方法了。
那為什么輸出是0呢?
因為值此時賦值只是到父類,子類的age還沒賦值,還是初始值0呢。

2.2 繼承的變量和方法的區(qū)別以及內(nèi)存控制

  • 一句話,變量沒有重寫,方法有重寫。
    • 用起來有什么區(qū)別呢? 還是剛剛的son類和fater類:
       son myson=new son();
       father myfather=myson;

       System.out.println(myson.age);
       myson.say();
       System.out.println(myfather.age);
       myfather.say(); 
      //將會輸出什么
33
子類的say:33
44
子類的say:33
  • 為什么?因為,變量沒有重寫,方法有重寫。所以父類還是可以調(diào)用自己的變量,而方法是調(diào)用子類的方法。

  • 細(xì)心的同學(xué)注意到,為什么

father myfather=myson

明明是new 子類,但卻可以輸出父類的age呢?

  • 那是因為在建立子類對象的時候,在劃分地址的時候,也有一塊內(nèi)存地址是存父類的變量,因此。子類中的super(),也是可以調(diào)用父類的變量的值。(可以試試噢~)

3. final 的注意事項

3.1 final方法不能被重寫,只能被程序顯式地賦值一次。
3.2 final最大作用是"宏替換"
3.3 在內(nèi)部類中的局部變量,需要用final。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容