日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

为什么在子类中不重写超类的实例变量

發(fā)布時間:2023/12/3 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 为什么在子类中不重写超类的实例变量 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

當(dāng)我們在父類和子類中創(chuàng)建一個具有相同名稱的變量,并嘗試使用持有子類對象的父類引用訪問它時,我們會得到什么?

為了理解這一點,讓我們考慮下面的示例,其中在Parent和Child類中聲明一個具有相同名稱的變量x 。

class Parent {// Declaring instance variable by name `x`String x = "Parent`s Instance Variable";public void print() {System.out.println(x);} }class Child extends Parent {// Hiding Parent class's variable `x` by defining a variable in child class with same name.String x = "Child`s Instance Variable";@Overridepublic void print() {System.out.print(x);// If we still want to access variable from super class, we do that by using `super.x`System.out.print(", " + super.x + "\n");} }

現(xiàn)在,如果我們嘗試使用以下代碼訪問x ,將打印什么System.out.println(parent.x)

Parent parent = new Child(); System.out.println(parent.x) // Output -- Parent`s Instance Variable

一般而言,我們會說Child類將覆蓋Parent類中聲明的變量,并且parent.x將給我們?nèi)魏蜟hild's對象所持有的東西。 因為在方法上進行相同類型的操作時發(fā)生的是同一件事。

但是實際上并非如此, parent.x將為我們提供在Parent類中聲明的Parent實例變量的值,但是為什么呢?

因為Java中的變量不遵循多態(tài)性,所以重寫僅適用于方法,而不適用于變量。 并且,當(dāng)子類中的實例變量與父類中的實例變量具有相同的名稱時,則從引用類型中選擇該實例變量。

在Java中,當(dāng)我們在Child類中使用已經(jīng)用于在Parent類中定義變量的名稱定義變量時,Child類的變量將隱藏父類的變量,即使它們的類型不同。 這種概念稱為可變隱藏。

換句話說,當(dāng)子類和父類都具有相同名稱的變量時,子類的變量將隱藏父類的變量。 您可以在文章什么是Java中的變量陰影和隱藏中閱讀有關(guān)變量隱藏的更多信息。

變量隱藏與方法覆蓋不同

盡管變量隱藏看起來像是覆蓋變量,類似于方法覆蓋,但事實并非如此,但覆蓋僅適用于方法,而隱藏適用于變量。

方法覆蓋的情況下,覆蓋方法完全替代了繼承的方法,因此當(dāng)我們嘗試通過持有子對象來從父對象的引用訪問該方法時,將調(diào)用子類中的方法。 您可以在“方法重載與方法重載”一書中了解有關(guān)重載以及被重載的方法如何完全替代繼承的方法的知識,以及為什么要遵循方法 重載 規(guī)則 。

但是在變量隱藏中,子類將隱藏繼承的變量而不是替換它們,這基本上意味著子類的對象包含兩個變量,而子變量則隱藏了父變量。 因此,當(dāng)我們嘗試從Child類中訪問變量時,將從子類中訪問該變量。

如果我簡化了示例8.3.1.1-3。 隱藏 Java語言規(guī)范 的實例變量 :

當(dāng)我們在Child類中聲明一個具有相同名稱(例如x作為Parent類中的實例變量的變量時,

  • 子類的對象包含兩個變量(一個是從Parent類繼承的,另一個是在Child本身中聲明的),但是子類變量隱藏了父類的變量。
  • 由于聲明x類Child皮的定義x類Parent ,類的聲明中Child ,簡單名稱x總是指到外地類中聲明的Child 。 而且,如果Child類方法中的代碼想要引用Parent類的變量x ,則可以將其作為super.x來完成。
  • 如果我們嘗試訪問Parent和Child類之外的變量,則從引用類型中選擇實例變量。 因此,以下代碼中的表達式parent2.x給出了屬于父類的變量值,即使它持有Child的對象,但((Child) parent2).x可以從Child類訪問該值,因為我們進行了相同的轉(zhuǎn)換參考Child 。
  • 為什么以這種方式設(shè)計可變隱藏

    因此,我們知道實例變量是從引用類型而不是實例類型中選擇的,并且多態(tài)性不適用于變量,但是真正的問題是為什么? 為什么變量被設(shè)計為跟隨隱藏而不是覆蓋。

    因為如果我們在子類中更改其類型,則變量覆蓋可能會破壞從父級繼承的方法。

    我們知道每個子類都從其父類繼承變量和方法(狀態(tài)和行為)。 想象一下,如果Java允許變量覆蓋,并且我們在子類中將變量的類型從int更改為Object 。 它將破壞使用該變量的任何方法,并且由于子級已從父級繼承了這些方法,因此編譯器將在child級中給出錯誤。

    例如:

    class Parent {int x;public int increment() {return ++x;}public int getX() {return x;} }class Child extends Parent {Object x;// Child is inherting increment(), getX() from Parent and both methods returns an int // But in child class type of x is Object, so increment(), getX() will fail to compile. }

    如果Child.x覆蓋Parent.x , increment()和getX()工作? 在子類中,這些方法將嘗試返回錯誤類型的字段的值!

    如前所述,如果Java允許變量覆蓋,則Child的變量不能替代Parent的變量,這將破壞Liskov替代性原則(LSP)。

    為什么從引用類型而不是實例中選擇實例變量

    如JVM內(nèi)部如何處理方法重載和覆蓋中所述 ,在編譯時,覆蓋方法調(diào)用僅從引用類處理,但是所有覆蓋的方法在運行時都使用vtable被覆蓋方法替代,這種現(xiàn)象稱為運行時多態(tài)性。

    同樣,在編譯時,變量訪問也從引用類型處理,但是正如我們所討論的,變量不遵循重寫或運行時多態(tài)性,因此它們在運行時不會被子類變量替代,仍然引用引用類型。

    一般而言,沒有人會建議隱藏字段,因為這會使代碼難以閱讀并造成混亂。 如果我們始終堅持下去,這種混亂就不會出現(xiàn)。
    創(chuàng)建POJO并通過將它們聲明為私有并封裝我們的字段的一般準則,并根據(jù)需要提供getter / setter,以便在該類之外看不到變量,并且子類無法訪問它們。

    您可以在此Github存儲庫中找到完整的代碼,請隨時提供寶貴的反饋。

    翻譯自: https://www.javacodegeeks.com/2018/11/instance-variable-class-overridden-class.html

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

    總結(jié)

    以上是生活随笔為你收集整理的为什么在子类中不重写超类的实例变量的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。