面試官常問的Java 基礎題(二)

11.靜態變量和實例變量的區別?

  1. 靜態標量前面有static,實例變量沒有;

  2. 靜態變量可通過類名調用,實例變量通過對象名調用

  • 在語法定義上的區別:

    靜態變量前要加 static 關鍵字,而實例變量前則不加。

  • 在程序運行時的區別:

    實例變量屬於某個對象的屬性,必須創建了實例對象,其中的實例變量纔會被分配空間,才能進行使用。
    靜態變量不屬於某個實例對象,而是屬於類,所以也稱爲類變量,只要程序加載了類的字節碼,不用創建任何實例對象,靜態變量就會被分配空間,就可以使用。
    總之,實例變量必須創建對象後纔可以通過這個對象來使用,靜態變量則可以直接使用類名來引用。

    例如 :
    在這裏插入圖片描述
    無論創建多少個實例對象,永遠都只分配了一個 staticVar 變量,並且每創建一個實例對象,這個 staticVar 就會加 1;但是,每創建一個實例對象,就會分配一個 instanceVar,即可能分配多個 instanceVar,並且每個 instanceVar 的值都只自加 了 1 次。

    備註:這個解答除了說清楚兩者的區別外,最後還用一個具體的應用例子來說明兩者的差異,體現了自己有很好的解說問題和設計案例的能力,思維敏捷,超過一般程序員,有寫作能力!

12.是否可以從一個 static 方法內部發出對非 static 方法的調用?

不可以從一個 static 方法內部發出對非 static 方法的調用。

靜態方法內部只能調用靜態方法。

因爲非靜態方法是要與對象關聯在一起的,必須創建一個對象後,纔可以在該對象上進行方法調用,而靜態方法調用時不需要創建對象,可以直接調用。
也就是說,當一個 static 方法被調用時,可能還沒有創建任何實例對象,如果從一個 static 方法中發出對非 static 方法的調用,那個非 static 方法是關聯到哪個對象上的呢?這個邏輯無法成立,所以,一個 static 方法內部不能發出對非 static 方法的調用。


13.Integer 與 int 的區別?

  1. int 是 java 的基本數據類型;
    Integer 是 java 爲 int 提供的封裝類。

  2. int 的默認值爲 0,
    Integer 的默認值爲 null,

Integer 可以區分出未賦值和值爲 0 的區別,int 則無法表達出未賦值的情況,
例如,要想表達出沒有參加考試和考試成績爲 0 的區別,則只能使用 Integer。
在 JSP 開發中,Integer 的默認爲 null,所以用 el 表達式在文本框中顯示時,值爲空白字符串,而 int 默認的默認值爲 0,所以用 el 表達式在文本框中顯示時,結果爲 0,所以,int 不適合作爲 web 層的表單數據的 類型。

Integer 提供了多個與整數相關的操作方法,
例如,將一個字符串轉換成整數,Integer 中還定義了表示整數的最大值和最小值的常量。

14.Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

Math.round(11.5) 結果爲 12,Math.round(-11.5) 結果爲 -11。

Math 類中提供了三個與取整有關的方法:ceil、floor、round,這些方法的作用與它們的英文名稱的含義相對應。

例如:

ceil 的英文意義是天花板,該方法表示向上取整,
Math.ceil(11.3)的結果爲 12,Math.ceil(-11.3)的結果是-11;

floor 的英文意義是地板,該方法表示向下取整,
Math.floor(11.6)的結果爲 11,Math.floor(-11.6)的結果是-12;

Math.round(x) , 算法:Math.floor(x+0.5)

即將原來的數字加上 0.5 後再向下取整,所以,
Math.round(11.5)的結果爲 12,Math.round(-11.5)的結果爲-11。
在這裏插入圖片描述

15.作用域 public,private,protected,以及不寫(friendly)時的區別

用 public 修飾時,在當前類、同一包內、子孫類、其他包內中都可調用;
用 protected 修飾時,在當前類、同一包內、子孫類中可調用,在其他包內不可調用;
用 friendly 修飾(不寫)時,在當前類、同一包內中可調用,在子孫類、其他包內不可調用;
用 private 修飾時,只能在當前類中調用;

這四個作用域的可見範圍如下表所示。
在這裏插入圖片描述
如果在修飾的元素上面沒有寫任何訪問修飾符,則表示 friendly。

備註:只要記住了有 4 種訪問權限,4 個訪問範圍,然後將全選和範圍在水平和垂直方向上分別按排從小到大或從大到小的順序排列,就很容易畫出上面的圖了。

16.Overload 重載 和 Override 重寫 的區別。重載的方法是否可以改變返回值的類型?

重載:類中的構造方法同名不同參(多個方法,方法名相同,但參數列表不同(個數、類型));
重寫:子類重寫父類方法(子類的方法名、返回值、參數與父類一致)可補充父類的方法,刪除重寫方法中的 super.() ,即推翻父類的寫法,異常修飾符只可高或相等。

Overload 是重載的意思,Override 是覆蓋的意思,也就是重寫。

重載 :表示同一個類中可以有多個名稱相同的方法,但這些方法的參數列表各不相同(即參數個數或類型不同)。

重寫 :表示子類中的方法可以與父類中的某個方法的名稱和參數完全相同,通過子類創建的實例對象調用這個方法時,將調用子類中的定義方法,這相當於把父類中定義的那個完全相同的方法給覆蓋了,這也是面向對象編程的多態性的一種表現。
子類覆蓋父類的方法時,只能比父類拋出更少的異常,或者是拋出父類拋出的異常的子異常,因爲子類可以解決父類的一些問題,不能比父類有更多的問題。子類方法的訪問權限只能比父類的更大,不能更小。

重載 的方法是否可以改變返回值的類型?

  • 如果幾個重載方法的參數列表不一樣,它們的返回者類型當然也可以不一樣;

  • 如果兩個方法的參數列表完全一樣,是否可以讓它們的返回值不同來實現重載?這是不行的。

    我們可以用反證法來說明這個問題,因爲我們有時候調用一個方法時也可以不定義返回結果變量,即不要關心其返回結果,

    例如:
    我們調用 map.remove(key) 方法時,雖然 remove 方法有返回值,但是我們 通常都不會定義接收返回結果的變量,這時候假設該類中有兩個名稱和參數列表完全相同的方法,僅僅是返回類型不同,java 就無法 確定編程者倒底是想調用哪個方法了,因爲它無法通過返回結果類型來判斷。

17.構造器 Constructor 是否可被 override 重寫?

構造器不能被重寫

構造器是不能被繼承的,因爲每個類的類名都不相同,而構造器名稱與類名相同,所以根本談不上繼承。

又由於構造器不能繼承,所以就不能被重寫。但是,在同一個類中,構造器是可以被重載的。

18.接口是否可繼承接口? 抽象類是否可實現接口? 抽象類是否可繼承具體類? 抽象類中是否可以有靜態的 main 方法?

接口可以繼承接口(接口多繼承)。
抽象類可以實現(implements)接口,
抽象類可繼承實體類,但前提是實體類必須有明確的構造函數。
抽象類中可以有靜態的 main 方法。

備註:只要明白了接口和抽象類的本質和作用,這些問題都很好回答,你想想,如果你是 java 語言的設計者,你是否會提供這樣 的支持,如果不提供的話,有什麼理由嗎?如果你沒有道理不提供,那答案就是肯定的了。


19.寫 clone() 方法時,通常都有一行代碼,是什麼?

clone 有缺省行爲,super.clone();
因爲首先要把父類中的成員複製到位,然後纔是複製自己的成員。

20.面向對象的特徵有哪些方面?

計算機軟件系統是現實生活中的業務在計算機中的映射,而現實生活中的業務其實就是一個個對象協作的過程。
面向對象編程就是按現實業務一樣的方式將程序代碼按一個個對象進行組織和編寫,讓計算機系統能夠識別和理解用對象方式組織和編寫的程序代碼,這樣就可以把現實生活中的業務對象映射到計算機系統中。

面向對象的編程語言有封裝、繼承 、抽象、多態等 4 個主要的特徵。

  • 封裝
    把對象內部的可透明性和隱藏的特性區分開。

    是保證軟件部件具有優良的模塊性的基礎,封裝的目標就是要實現軟件部件的“高內聚、低耦合” ,防止程序相互依賴性而帶來的變動影響。

    在面向對象的編程語言中,對象是封裝的最基本單位,面向對象的封裝比傳統語言的封裝更爲清晰、更爲有力。

    面向對象的封裝就是把描述一個對象的屬性和行爲的代碼封裝在一個“模塊”中,也就是一個類中,屬性用變量定義,行爲用方法進行定義,方法可以直接訪問同一個對象中的屬性。通常情況下,只要記住讓變量和訪問這個變量的方法放在一起,將一個類中的成員變量全部定義成私有的,只有這個類自己的方法纔可以訪問到這些成員變量,這就基本上實現對象的封裝,就很容易找出要分配到這個類上的方法了,就基本上算是會面向對象的編程了。

    例如,人要在黑板上畫圓,這一共涉及三個對象:人、黑板、圓,畫圓的方法要分配給哪個對象呢?由於畫圓需要使用到圓心和半徑,圓心和半徑顯然是圓的屬性,如果將它們在類中定義成了私有的成員變量,那麼,畫圓的方法必須分配給圓,它才能訪問到圓心和半徑這兩個屬性,人以後只是調用圓的畫圓方法、表示給圓發給消息而已,畫圓這個方法不應該分配在人這個對象上,這就是面向對象的封裝性,即將對象封裝成一個高度自治和相對封閉的個體,對象狀態(屬性)由這個對象自己的行爲(方法)來讀取和改變。

    一個更便於理解的例子就是,司機將火車剎住了,剎車的動作是分配給司機,還是分配給火車,顯然,應該分配給火車,因爲司機自身是不可能有那麼大的力氣將一個火車給停下來的,只有火車自己才能完成這一動作,火車需要調用內部的離合器和剎車片等多個器件協作才能完成剎車這個動作,司機剎車的過程只是給火車發了一個消息,通知火車要執行剎車動作而已。

  • 繼承
    子類繼承父類的特徵和行爲。

    在定義和實現一個類的時候,可以在一個已經存在的類的基礎之上來進行,把這個已經存在的類所定義的內容作爲自己的內容,並可以加入若干新的內容,或修改原來的方法使之更適合特殊的需要,這就是繼承。

    繼承是子類自動共享父類數據和方法的機制,這是類之間的一種關係,提高了軟件的可重用性和可擴展性。

  • 多態
    同一事物有不同的表現形式。

    多態是指程序中定義的引用變量所指向的具體類型和通過該引用變量發出的方法調用在編程時並不確定,而是在程序運行期間才確定,即一個引用變量倒底會指向哪個類的實例對象,該引用變量發出的方法調用到底是哪個類中實現的方法,必須在由程序運行期間才能決定。因爲在程序運行時才確定具體的類,這樣,不用修改源程序代碼,就可以讓引用變量綁定到各種不同的類實現上,從而導致該引用調用的具體方法隨之改變,即不修改程序代碼就可以改變程序運行時所綁定的具體代碼,讓程序可以選擇多個運行狀態, 這就是多態性。

    多態性增強了軟件的靈活性和擴展性。

    例如,下面代碼中的 UserDao 是一個接口,它定義引用變量 userDao 指向的實 例對象由 daofactory.getDao()在執行的時候返回,有時候指向的是 UserJdbcDao 這個實現,有時候指向的是 UserHibernateDao 這個實現, 這樣,不用修改源代碼,就可以改變 userDao 指向的具體類實現,從而導致 userDao.insertUser()方法調用的具體代碼也隨之改變,即有 時候調用的是 UserJdbcDao 的 insertUser 方法,有時候調用的是 UserHibernateDao 的 insertUser 方法:
    在這裏插入圖片描述

  • 抽象
    找出事物的共性之處,將之爲一個類。

    就是找出一些事物的相似和共性之處,然後將這些事物歸爲一個類,這個類只考慮這些事物的相似和共性之處,並且會忽略與當前主題和目標無關的那些方面,將注意力集中在與當前目標有關的方面。

    抽象包括行爲抽象和狀態抽象兩個方面。

    例如,定義一 個 Person 類,
    在這裏插入圖片描述
    人本來是很複雜的事物,有很多方面,但因爲當前系統只需要瞭解人的姓名和年齡,所以上面定義的類中只包含姓名和年齡這兩個屬性,這就是一種抽像,使用抽象可以避免考慮一些與目標無關的細節。
    我對抽象的理解就是不要用顯微鏡去看一個事物的所有方面,這樣涉及的內容就太多了,而是要善於劃分問題的邊界,當前系統需要什麼,就只考慮什麼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章