您好,歡迎來電子發(fā)燒友網(wǎng)! ,新用戶?[免費(fèi)注冊]

您的位置:電子發(fā)燒友網(wǎng)>源碼下載>java源碼下載>

Java類的繼承與派生

大?。?/span>0.6 MB 人氣: 2017-09-27 需要積分:1

  對于面向?qū)ο蟮某绦蛟O(shè)計語言來說,類毫無疑問是其最重要的基礎(chǔ)。抽象、封裝、繼承、多態(tài)這四大特性都離不開類,只有存在類,才能體現(xiàn)面向?qū)ο?a target='_blank' class='arckwlink_none'>編程的特點(diǎn),今天我們就來了解一些類與繼承的相關(guān)知識。首先,我們講述一下與類的初始化相關(guān)的東西,然后再從幾個方面闡述繼承這一大特性。以下是本文的目錄大綱:

  一。你了解類嗎?

  二。你了解繼承嗎?

  三。常見的面試筆試題

  若有不正之處,請多多諒解并歡迎批評指正。

  一。你了解類嗎? 在Java中,類文件是以.java為后綴的代碼文件,在每個類文件中最多只允許出現(xiàn)一個public類,當(dāng)有public類的時候,類文件的名稱必須和public類的名稱相同,若不存在public,則類文件的名稱可以為任意的名稱(當(dāng)然以數(shù)字開頭的名稱是不允許的)。

  在類內(nèi)部,對于成員變量,如果在定義的時候沒有進(jìn)行顯示的賦值初始化,則Java會保證類的每個成員變量都得到恰當(dāng)?shù)某跏蓟?/p>

  1)對于 char、short、byte、int、long、float、double等基本數(shù)據(jù)類型的變量來說會默認(rèn)初始化為0(boolean變量默認(rèn)會被初始化為false);

  2)對于引用類型的變量,會默認(rèn)初始化為null。

  如果沒有顯示地定義構(gòu)造器,則編譯器會自動創(chuàng)建一個無參構(gòu)造器,但是要記住一點(diǎn),如果顯示地定義了構(gòu)造器,編譯器就不會自動添加構(gòu)造器。注意,所有的構(gòu)造器默認(rèn)為static的。

  下面我們著重講解一下 初始化 順序:

  當(dāng)程序執(zhí)行時,需要生成某個類的對象,Java執(zhí)行引擎會先檢查是否加載了這個類,如果沒有加載,則先執(zhí)行類的加載再生成對象,如果已經(jīng)加載,則直接生成對象。

  在類的加載過程中,類的static成員變量會被初始化,另外,如果類中有static語句塊,則會執(zhí)行static語句塊。static成員變量和static語句塊的執(zhí)行順序同代碼中的順序一致。記住,在Java中,類是按需加載,只有當(dāng)需要用到這個類的時候,才會加載這個類,并且只會加載一次??聪旅孢@個例子就明白了:

  publicclassTest { publicstaticvoidmain(String[] args) throws ClassNotFoundException { Bread bread1 = newBread(); Bread bread2 = newBread(); } } class Bread { static{ System.out.println( “Bread is loaded”); } publicBread() { System. out.println( “bread”); } }

  運(yùn)行這段代碼就會發(fā)現(xiàn)”Bread is loaded”只會被打印一次。

  在生成對象的過程中,會先初始化對象的成員變量,然后再執(zhí)行構(gòu)造器。也就是說類中的變量會在任何方法(包括構(gòu)造器)調(diào)用之前得到初始化,即使變量散步于方法定義之間。

  publicclassTest { publicstaticvoidmain(String[] args) { newMeal(); } } class Meal {publicMeal() { System. out.println( “meal”); } Bread bread = newBread(); } class Bread {publicBread() { System. out.println( “bread”); } }

  輸出結(jié)果為:

  bread meal二。你了解繼承嗎? 繼承是所有OOP語言不可缺少的部分,在java中使用extends關(guān)鍵字來表示繼承關(guān)系。當(dāng)創(chuàng)建一個類時,總是在繼承,如果沒有明確指出要繼承的類,就總是隱式地從根類Object進(jìn)行繼承。比如下面這段代碼:

  classPerson{publicPerson() { } } classManextendsPerson{publicMan() { } }

  類Man繼承于Person類,這樣一來的話,Person類稱為父類(基類),Man類稱為子類(導(dǎo)出類)。如果兩個類存在繼承關(guān)系,則子類會自動繼承父類的方法和變量,在子類中可以調(diào)用父類的方法和變量。在java中,只允許單繼承,也就是說 一個類最多只能顯示地繼承于一個父類。但是一個類卻可以被多個類繼承,也就是說一個類可以擁有多個子類。

  *1.子類繼承父類的成員變量

  當(dāng)子類繼承了某個類之后,便可以使用父類中的成員變量,但是并不是完全繼承父類的所有成員變量。具體的原則如下:

  1)能夠繼承父類的public和protected成員變量;不能夠繼承父類的private成員變量;

  2)對于父類的包訪問權(quán)限成員變量,如果子類和父類在同一個包下,則子類能夠繼承;否則,子類不能夠繼承;

  3)對于子類可以繼承的父類成員變量,如果在子類中出現(xiàn)了同名稱的成員變量,則會發(fā)生隱藏現(xiàn)象,即子類的成員變量會屏蔽掉父類的同名成員變量。如果要在子類中訪問父類中同名成員變量,需要使用super關(guān)鍵字來進(jìn)行引用。

  2.子類繼承父類的方法

  同樣地,子類也并不是完全繼承父類的所有方法。

  1)能夠繼承父類的public和protected成員方法;不能夠繼承父類的private成員方法;

  2)對于父類的包訪問權(quán)限成員方法,如果子類和父類在同一個包下,則子類能夠繼承;否則,子類不能夠繼承;

  3)對于子類可以繼承的父類成員方法,如果在子類中出現(xiàn)了同名稱的成員方法,則稱為覆蓋,即子類的成員方法會覆蓋掉父類的同名成員方法。如果要在子類中訪問父類中同名成員方法,需要使用super關(guān)鍵字來進(jìn)行引用。

  注意:隱藏和覆蓋是不同的。隱藏是針對成員變量和靜態(tài)方法的,而覆蓋是針對普通方法的。(后面會講到)

  3.構(gòu)造器

  子類是不能夠繼承父類的構(gòu)造器,但是要注意的是,如果父類的構(gòu)造器都是帶有參數(shù)的,則必須在子類的構(gòu)造器中顯示地通過super關(guān)鍵字調(diào)用父類的構(gòu)造器并配以適當(dāng)?shù)膮?shù)列表。如果父類有無參構(gòu)造器,則在子類的構(gòu)造器中用super關(guān)鍵字調(diào)用父類構(gòu)造器不是必須的,如果沒有使用super關(guān)鍵字,系統(tǒng)會自動調(diào)用父類的無參構(gòu)造器。看下面這個例子就清楚了:

  classShape{protectedString name; publicShape(){ name = “shape”; } publicShape(String name) { this.name = name; } } classCircleextendsShape{privatedoubleradius;publicCircle() { radius = 0; } publicCircle( doubleradius) { this.radius = radius; }publicCircle( doubleradius,String name) { this.radius = radius; this.name = name; } }

  這樣的代碼是沒有問題的,如果把父類的無參構(gòu)造器去掉,則下面的代碼必然會出錯:

  Java類的繼承與派生

  改成下面這樣就行了:

  Java類的繼承與派生

  4.super

  super主要有兩種用法:

  1)super.成員變量/super.成員方法;

  2)super(parameter1,parameter2…。)

  第一種用法主要用來在子類中調(diào)用父類的同名成員變量或者方法;第二種主要用在子類的構(gòu)造器中顯示地調(diào)用父類的構(gòu)造器,要注意的是,如果是用在子類構(gòu)造器中,則必須是子類構(gòu)造器的第一個語句。

  三。常見的面試筆試題

  1.下面這段代碼的輸出結(jié)果是什么?

  publicclassTest{publicstaticvoidmain(String[] args) { newCircle(); } }classDraw{publicDraw(String type) { System.out.println(type+ “ draw constructor”); } }classShape{privateDraw draw = newDraw( “shape”); publicShape(){ System.out.println(“shape constructor”); } } classCircleextendsShape{privateDraw draw = newDraw( “circle”);publicCircle() { System.out.println( “circle constructor”); } } shape drawconstructorshapeconstructorcircledrawconstructorcircleconstructor

  這道題目主要考察的是類繼承時構(gòu)造器的調(diào)用順序和初始化順序。要記住一點(diǎn):父類的構(gòu)造器調(diào)用以及初始化過程一定在子類的前面。由于Circle類的父類是Shape類,所以Shape類先進(jìn)行初始化,然后再執(zhí)行Shape類的構(gòu)造器。接著才是對子類Circle進(jìn)行初始化,最后執(zhí)行Circle的構(gòu)造器。

  2.下面這段代碼的輸出結(jié)果是什么?

  /** * Java學(xué)習(xí)交流QQ群:589809992 我們一起學(xué)Java! */publicclassTest{publicstaticvoidmain(String[] args) { Shape shape = newCircle(); System.out.println(shape.name); shape.printType(); shape.printName(); } } class Shape {publicString name = “shape”; publicShape(){ System.out.println( “shape constructor”); }publicvoidprintType() { System.out.println( “this is shape”); } publicstaticvoidprintName() { System.out.println( “shape”); } } class Circle extends Shape { publicString name = “circle”;publicCircle() { System.out.println( “circle constructor”); } publicvoidprintType() { System.out.println( “this is circle”); } publicstaticvoidprintName() { System.out.println(“circle”); } } shape constructorcircleconstructorshapethisiscircleshape

  這道題主要考察了隱藏和覆蓋的區(qū)別(當(dāng)然也和多態(tài)相關(guān),在后續(xù)博文中會繼續(xù)講到)。

  覆蓋只針對非靜態(tài)方法(終態(tài)方法不能被繼承,所以就存在覆蓋一說了),而隱藏是針對成員變量和靜態(tài)方法的。這2者之間的區(qū)別是:覆蓋受RTTI(Runtime type identification)約束的,而隱藏卻不受該約束。也就是說只有覆蓋方法才會進(jìn)行動態(tài)綁定,而隱藏是不會發(fā)生動態(tài)綁定的。在Java中,除了static方法和final方法,其他所有的方法都是動態(tài)綁定。因此,就會出現(xiàn)上面的輸出結(jié)果。

非常好我支持^.^

(0) 0%

不好我反對

(0) 0%

      發(fā)表評論

      用戶評論
      評價:好評中評差評

      發(fā)表評論,獲取積分! 請遵守相關(guān)規(guī)定!

      ?