2019年Android開發者常見面試題(三)

對Java面試點的分享,已經總結了兩篇文章了,這篇我們繼續關於Java的總結。

 

問題 15:靜態內部類的使用目的與限制

答案【答案不唯一,可自己衡量】:

在開發過程中,內部類中使用的最多的還是非靜態地成員內部類。不過在特定的情況下,靜態內部類也能夠發揮其獨特的作用。

一、靜態內部類的使用目的。

  在定義內部類的時候,可以在其前面加上一個權限修飾符static。此時這個內部類就變爲了靜態內部類。不過由於種種的原因,如使用上的限制等 等因素(具體的使用限制,筆者在下面的內容中會詳細闡述),在實際工作中用的並不是很多。但是並不是說其沒有價值。在某些特殊的情況下,少了這個靜態內部 類還真是不行。如在進行代碼程序測試的時候,如果在每一個Java源文件中都設置一個主方法(主方法是某個應用程序的入口,必須具有),那麼會出現很多額 外的代碼。而且最主要的時這段主程序的代碼對於Java文件來說,只是一個形式,其本身並不需要這種主方法。但是少了這個主方法又是萬萬不行的。在這種情 況下,就可以將主方法寫入到靜態內部類中,從而不用爲每個Java源文件都設置一個類似的主方法。這對於代碼測試是非常有用的。在一些中大型的應用程序開 發中,則是一個常用的技術手段。爲此,這個靜態內部類雖然不怎麼常用,但是程序開發人員還必須要掌握它。也許在某個關鍵的時刻,其還可以發揮巨大的作用也 說不定。

二、靜態內部類的使用限制。

  將某個內部類定義爲靜態類,跟將其他類定義爲靜態類的方法基本相同,引用規則也基本一致。不過其細節方面仍然有很大的不同。具體來說,主要有如下幾個地方要引起各位程序開發人員的注意。

  一是靜態成員(包括靜態變量與靜態成員)的定義。一般情況下,如果一個內部類不是被定義成靜態內部類,那麼在定義成員變量或者成員方法的時候, 是不能夠被定義成靜態成員變量與靜態成員方法的。也就是說,在非靜態內部類中不可以聲明靜態成員。如現在在一個student類中定義了一個內部類 age,如果沒有將這個類利用static關鍵字修飾,即沒有定義爲靜態類,那麼在這個內部類中如果要利用static關鍵字來修飾某個成員方法或者成員 變量是不允許的。在編譯的時候就通不過。故程序開發人員需要注意,只有將某個內部類修飾爲靜態類,然後才能夠在這個類中定義靜態的成員變量與成員方法。這 是靜態內部類都有的一個特性。也正是因爲這個原因,有時候少了這個靜態的內部類,很多工作就無法完成。或者說要繞一個大圈才能夠實現某個用戶的需求。這也 是靜態的內部類之所以要存在的一個重要原因。

二是在成員的引用上,有比較大的限制。一般的非靜態內部類,可以隨意的訪問外部類中的成員變量與成員方法。即使這些成員方法被修飾爲 private(私有的成員變量或者方法),其非靜態內部類都可以隨意的訪問。則是非靜態內部類的特權。因爲在其他類中是無法訪問被定義爲私有的成員變量 或則方法。但是如果一個內部類被定義爲靜態的,那麼在銀用外部類的成員方法或則成員變量的時候,就會有諸多的限制。如不能夠從靜態內部類的對象中訪問外部 類的非靜態成員(包括成員變量與成員方法)。這是什麼意思呢?如果在外部類中定義了兩個變量,一個是非靜態的變量,一個是靜態的變量。那麼在靜態內部類 中,無論在成員方法內部還是在其他地方,都只能夠引用外部類中的靜態的變量,而不能夠訪問非靜態的變量。在靜態內部類中,可以定義靜態的方法(也只有在靜 態的內部類中可以定義靜態的方法),在靜態方法中引用外部類的成員。但是無論在內部類的什麼地方引用,有一個共同點,即都只能夠引用外部類中的靜態成員方 法或者成員變量。對於那些非靜態的成員變量與成員方法,在靜態內部類中是無法訪問的。這就是靜態內部類的最大使用限制。在普通的非靜態內部類中是沒有這個 限制的。也正是這個原因,決定了靜態內部類只應用在一些特定的場合。其應用範圍遠遠沒有像非靜態的內部類那樣廣泛。

三是在創建靜態內部類時不需要將靜態內部類的實例綁定在外部類的實例上。

通常情況下,在一個類中創建成員內部類的時候,有一個強制性的規定,即內部類的實例一定要綁定在外部類的實例中。也就是說,在創建內部類之前要先在外部類 中要利用new關鍵字來創建這個內部類的對象。如此的話如果從外部類中初始化一個內部類對象,那麼內部類對象就會綁定在外部類對象上。也就是說,普通非靜 態內部類的對象是依附在外部類對象之中的。但是,如果成員開發人員創建的時靜態內部類,那麼這就又另當別論了。通常情況下,程序員在定義靜態內部類的時 候,是不需要定義綁定在外部類的實例上的。也就是說,要在一個外部類中定義一個靜態的內部類,不需要利用關鍵字new來創建內部類的實例。即在創建靜態類 內部對象時,不需要其外部類的對象。具體爲什麼會這樣,一般程序開發人員不需要了解這麼深入,只需要記住有這個規則即可。在定義靜態內部類的時候,千萬不 要犯畫蛇添足的錯誤。

  從以上的分析中可以看出,靜態內部類與非靜態的內部類還是有很大的不同的。一般程序開發人員可以這麼理解,非晶態的內部類對象隱式地在外部類中 保存了一個引用,指向創建它的外部類對象。不管這麼理解,程序開發人員都需要牢記靜態內部類與非靜態內部類的差異。如是否可以創建靜態的成員方法與成員變 量(靜態內部類可以創建靜態的成員而非靜態的內部類不可以)、對於訪問外部類的成員的限制(靜態內部類只可以訪問外部類中的靜態成員變量與成員方法而非靜 態的內部類即可以訪問靜態的也可以訪問非靜態的外部類成員方法與成員變量)。這兩個差異是靜態內部類與非靜態外部類最大的差異,也是靜態內部類之所以存在 的原因。瞭解了這個差異之後,程序開發人員還需要知道,在什麼情況下該使用靜態內部類。如在程序測試的時候,爲了避免在各個Java源文件中書寫主方法的 代碼,可以將主方法寫入到靜態內部類中,以減少代碼的書寫量,讓代碼更加的簡潔。

  總之,靜態內部類在Java語言中是一個很特殊的類,跟普通的靜態類以及非靜態的內部類都有很大的差異。作爲程序開發人員,必須要知道他們之間 的差異,並在實際工作中在合適的地方採用合適的類。不過總的來說,靜態內部類的使用頻率並不是很高。但是在有一些場合,如果沒有這個內部靜態類的話,可能 會起到事倍功半的反面效果。

 

問題 16:內部類和閉包相關問題

答案【答案不唯一,可自己衡量】:

在《Think in java》中有這樣一句話:使用內部類最吸引人的原因是:每個內部類都能獨立地繼承一個(接口的)實現,所以無論外圍類是否已經繼承了某個(接口的)實現,對於內部類都沒有影響。

因爲Java不支持多繼承,支持實現多個接口。但有時候會存在一些使用接口很難解決的問題,這個時候我們可以利用內部類提供的、可以繼承多個具體的或者抽象的類的能力來解決這些程序設計問題。可以這樣說,接口只是解決了部分問題,而內部類使得多重繼承的解決方案變得更加完整。

閉包

閉包是指在匿名內部類,能夠訪問外部類的全部變量和方法,換句話說,就是這個類裏面含有外部類的相關信息,能夠調用到外部類中的全部屬性和方法。

內部類的一些知識點

1、在創建非靜態內部類對象時,一定要先創建其相應的外部類對象。原因是:非靜態內部類對象有着指向其外部類對象的引用,可以引用其外部類中的所有public protected private的變量和方法。

2、內部類可以是靜態的,即內部類可分爲靜態內部類和非靜態內部類(即普通類)。區別在於靜態內部類沒有了指向其外部類的引用。

3、非靜態內部類中不能有靜態屬性、靜態方法或者又一個靜態內部類(內部類的嵌套可以不止一層);但靜態內部類可以擁有這一切,即靜態屬性、靜態方法或者靜態內部類。

4、局部內部類 即Java的內部類可以是局部的,它可以定義在一個方法甚至一個代碼塊之內。

5、匿名內部類 Java的匿名內部類的語法規則比較簡單,如同匿名數組一樣,用於當你只需要創建一個類的對象而並不需要使用它的名字時,這樣,匿名內部類的使用能使代碼看上去更簡潔、更清楚。

6、匿名內部類由於沒有名字,所以它沒有構造函數(但是如果這個匿名內部類繼承了一個只含有帶參數構造函數的父類,創建它的時候必須帶上這些參數,並在實現的過程中使用super關鍵字調用相應的內容)。如果你想要初始化它的成員變量,有下面幾種方法:a) 如果是在一個方法的匿名內部類,可以利用這個方法傳進你想要的參數,不過記住,這些參數必須被聲明爲final;b) 將匿名內部類改造成有名字的局部內部類,這樣它就可以擁有構造函數了;c) 在這個匿名內部類中使用初始化代碼塊。

 

問題 17:靜態屬性和靜態方法是否可以被繼承?是否可以被重寫?以及原因

答案【答案不唯一,可自己衡量】:

java中靜態屬性和靜態方法可以被繼承,但是沒有被重寫(overwrite)而是被隱藏.

原因:


1). 靜態方法和屬性是屬於類的,調用的時候直接通過類名.方法名完成對,不需要繼承機制及可以調用。如果子類裏面定義了靜態方法和屬性,那麼這時候父類的靜態方法或屬性稱之爲"隱藏"。如果你想要調用父類的靜態方法和屬性,直接通過父類名.方法或變量名完成,至於是否繼承一說,子類是有繼承靜態方法和屬性,但是跟實例方法和屬性不太一樣,存在"隱藏"的這種情況。
2). 多態之所以能夠實現依賴於繼承、接口和重寫、重載(繼承和重寫最爲關鍵)。有了繼承和重寫就可以實現父類的引用指向不同子類的對象。重寫的功能是:"重寫"後子類的優先級要高於父類的優先級,但是“隱藏”是沒有這個優先級之分的。

3). 靜態屬性、靜態方法和非靜態的屬性都可以被繼承和隱藏而不能被重寫,因此不能實現多態,不能實現父類的引用可以指向不同子類的對象。非靜態方法可以被繼承和重寫,因此可以實現多態。

靜態屬性和靜態方法可以被繼承
靜態方法不可以被重寫,不能實現多態

 

問題 18:Serializable 和Parcelable 的區別

答案【答案不唯一,可自己衡量】

一、對象爲什麼需要序列化

1.永久性保存對象,保存對象的字節序列到本地文件。

2.通過序列化對象在網絡中傳遞對象。

3.通過序列化對象在進程間傳遞對象。

二、當對象需要被序列化時如何選擇所使用的接口

1.在使用內存的時候Parcelable比Serializable的性能高。

2.Serializable在序列化的時候會產生大量的臨時變量,從而引起頻繁的GC(內存回收)。

3.Parcelable不能使用在將對象存儲在磁盤上這種情況,因爲在外界的變化下Parcelable不能很好的保證數據的持續性。

 

問題 19:final,finally,finalize的區別

答案【答案不唯一,可自己衡量】

final是修飾符,修飾類、方法和變量,意爲不可修改的。當修飾類的時候不可以派生出新的子類,因此一個類的修飾符不可以既是final和abstract;修飾方法的時候該方法不可以被重載;修飾變量的時候需要給變量賦初值,在接下來只能對其讀取不可以重新賦值。

finally是在異常處理時提供finally塊來執行任何清除操作的,如果try語句中發生了catch塊中的異常,則跳轉到catch中進行異常處理,而finally中的內容則是無論異常是否發生都要執行的。如果finally中有return,則會先執行finally再執行return,如果此時try中也有return,則try中的return不會執行,但是,如果只有try中有return也是先執行finally中的語句再執行return;

finalize是方法名,在垃圾回收器將對象從內存中清理出去之前做的必要工作。是由垃圾回收器在確定這個對象沒有被引用的時候調用的,它是在Object中定義的,子類重寫finalize方法整理系統資源或其他清理工作finalize方法是在垃圾收集器刪除對象之前調用的。

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