天天看點

android面試之java篇

一,基礎部分

1,Java中==和equals和hashCode的差別

java資料類型分為兩類: 基本資料類型(byte,short,char,int,long,float,double,boolean),引用資料類型(類,接口,數組)。

①,* == * 是運算符,用于比較兩個變量是否相等,用于比較基本資料類型的值。

②,equals,是Objec類的方法,預設Object類的equals方法是比較兩個對象的位址(堆),跟==的結果一樣。equals(Object)方法的特殊之處就在于它可以被覆寫,可以通過覆寫的方法讓它比較資料内容(棧)。比如:Double,Date,Integer等類對equals方法進行了重寫,比較的是所指向的對象的内容

③,hashCode也是Object類的一個方法。傳回一個離散的int型整數。在集合類操作中使用,為了提高查詢速度。

說明:hashCode()方法傳回的就是一個數值,生成一個hash碼。hash碼的用途是在對對象進行散列的時候作為key輸入,Object類提供的預設實作保證每個對象的hash碼不同,這樣才能保證散列的存取性能。Java類中的集合有兩類:一是List(有序,元素可重複),二是Set(無序,元素不可重複)。既然Set中的元素不可重複,那麼在存入資料時必須要檢查比對,如果資料多對比次數多會降低效率。于是,Java采用了哈希表的原理。這樣在添加元素時,調用元素的hashCode方法,一下子就能定位到應該放置的實體位置。如果這個位置上沒有元素,直接存入,如果有元素就調用equals方法做對比,相同的話就不存,不同的話就散列存放其他位址,這樣降低了equals方法調用次數,進而提高效率。

2,int、char、long各占多少位元組數

1位元組: byte , boolean

2位元組: short , char

4位元組: int , float

8位元組: long , double

3,int與Integer的差別

①,Integer是int的包裝類,int則是java的一種基本資料類型

②,Integer變量必須執行個體化後才能使用,而int變量不需要

③,Integer實際是對象的引用,當new一個Integer時,實際上是生成一個指針指向此對象;而int則是直接存儲資料值 。

④,Integer的預設值是null,int的預設值是0。

4,談談對Java多态的了解

  • 多态:指允許不同類的對象對同一消息做出響應。即同一消息可以根據發送對象的不同而采用多種不同的行為方式
  • 實作多态的技術稱為:動态綁定(dynamic binding),是指在執行期間判斷所引用對象的實際類型,根據其實際的類型調用其相應的方法
  • 作用:消除類型之間的耦合關系
  • 條件:繼承,重寫,父類引用指向子類對象
  • 好處:可替換性,可擴充性,接口性,靈活性,簡化性
  • Java中多态的實作方式:接口實作,繼承父類進行方法重寫,同一個類中進行方法重載

5,String、StringBuffer、StringBuilder差別

String和兩者的主要差別在于,String是不可變對象,每次對 String 進行改變的時候都會生成一個新的 String 對象

  • 執行速度方面:StringBuilder > StringBuffer > String
  • String:适用于操作少量資料,是不可變的對象。
  • StringBuilder :非線程安全的,适用于操作大量資料,可變對象
  • StringBuffer:線程安全的,适用于操作大量資料,可變對象

6,什麼是内部類?内部類的作用

Java中内部類主要分為成員内部類、局部内部類(嵌套在方法和作用域内)、匿名内部類(沒構造方法)、靜态内部類(static修飾的類,不能使用任何外圍類的非static成員變量和方法, 不依賴外圍類)

7,抽象類和接口差別

接口:接口是一序列方法的聲明,接口隻有方法的形狀而沒有方法的具體實作,接口是Java面向對象提供的一種機制。

抽象類:抽象類是描述許多類的公共的地方,它是一個基類。

差別:

  • 抽象類可以有構造方法, 而接口不能有
  • 抽象類可以有普通成員變量,而接口不能有
  • 抽象類可以包含非抽象的普通方法,而接口中所有的方法必須是抽象的,不能有非抽象的普通方法
  • 抽象類的抽象方法的通路類型可以是public、protected和預設類型,但接口中的抽象方法必須是public類型的
  • 抽象類可以包含靜态方法,而接口中不能包含
  • 一個類可以實作多個接口,隻能繼承一個抽象類

8,final,finally,finalize的差別

final:修飾類、成員變量和成員方法,類不可被繼承,成員變量不可變,成員方法不可重寫。

finally:與try…catch…共同使用,確定無論是否出現異常都能被調用到。

finalize:類的方法,垃圾回收之前會調用此方法,子類可以重寫finalize()方法實作對資源的回收。

9,Serializable 和Parcelable 的差別

Serializable Java 序列化接口 在硬碟上讀寫 讀寫過程中有大量臨時變量的生成,内部執行大量的i/o操作,效率很低。

Parcelable Android 序列化接口 效率高 使用麻煩 在記憶體中讀寫(AS有相關插件 一鍵生成所需方法) ,對象不能儲存到磁盤中。

10,靜态屬性和靜态方法是否可以被繼承?是否可以被重寫?以及原因?

可繼承 不可重寫 而是被隐藏

如果子類裡面定義了靜态方法和屬性,那麼這時候父類的靜态方法或屬性稱之為"隐藏"。如果你想要調用父類的靜态方法和屬性,直接通過父類名.方法或變量名完成。

11,哪些情況下的對象會被垃圾回收機制處理掉?

①,所有執行個體都沒有活動線程通路。

②,沒有被其他任何執行個體通路的循環引用執行個體。

③,Java 中有不同的引用類型。判斷執行個體是否符合垃圾收集的條件都依賴于它的引用類型。

要判斷怎樣的對象是沒用的對象。這裡有2種方法:

①,采用标記計數的方法:

給記憶體中的對象給打上标記,對象被引用一次,計數就加1,引用被釋放了,計數就減一,當這個計數為0的時候,這個對象就可以被回收了。當然,這也就引發了一個問題:循環引用的對象是無法被識别出來并且被回收的。是以就有了第二種方法:

②,采用根搜尋算法:

從一個根出發,搜尋所有的可達對象,這樣剩下的那些對象就是需要被回收的。

12、靜态代理和動态代理的差別,什麼場景使用?

①,靜态代理:由程式員建立或由特定工具自動生成源代碼,再對其編譯。在程式運作前,代理類的.class檔案就已經存在了。使用場景:

②,動态代理類:在程式運作時,運用反射機制動态建立而成。

13、Java中實作多态的機制是什麼?

方法的重寫Overriding和重載Overloading是Java多态性的不同表現,重寫Overriding是父類與子類之間多态性的一種表現,重載Overloading是一個類中多态性的一種表現。

14、說說你對Java反射的了解

JAVA反射機制是在運作狀态中, 對于任意一個類, 都能夠知道這個類的所有屬性和方法; 對于任意一個對象, 都能夠調用它的任意一個方法和屬性。 從對象出發,通過反射(Class類)可以取得取得類的完整資訊(類名 Class類型,所在包、具有的所有方法 Method[]類型、某個方法的完整資訊(包括修飾符、傳回值類型、異常、參數類型)、所有屬性 Field[]、某個屬性的完整資訊、構造器 Constructors),調用類的屬性或方法

總結: 在運作過程中獲得類、對象、方法的所有資訊。

15,數組和連結清單的差別

數組:是将元素在記憶體中連續存儲的;它的優點:因為資料是連續存儲的,記憶體位址連續,是以在查找資料的時候效率比較高;它的缺點:在存儲之前,我們需要申請一塊連續的記憶體空間,并且在編譯的時候就必須确定好它的空間的大小。在運作的時候空間的大小是無法随着你的需要進行增加和減少而改變的,當資料兩比較大的時候,有可能會出現越界的情況,資料比較小的時候,又有可能會浪費掉記憶體空間。在改變資料個數時,增加、插入、删除資料效率比較低。

連結清單:是動态申請記憶體空間,不需要像數組需要提前申請好記憶體的大小,連結清單隻需在用的時候申請就可以,根據需要來動态申請或者删除記憶體空間,對于資料增加和删除以及插入比數組靈活。還有就是連結清單中資料在記憶體中可以在任意的位置,通過應用來關聯資料(就是通過存在元素的指針來聯系)

16,Java中堆和棧有什麼不同

因為棧是一塊和線程緊密相關的記憶體區域。每個線程都有自己的棧記憶體,用于存儲本地變量,方法參數和棧調用,一個線程中存儲的變量對其它線程是不可見的。而堆是所有線程共享的一片公用記憶體區域。對象都在堆裡建立,為了提升效率線程會從堆中弄一個緩存到自己的棧,如果多個線程使用該變量就可能引發問題,這時volatile 變量就可以發揮作用了,它要求線程從主存中讀取變量的值。

二,集合部分

1,List,Set,Map的差別

①,Set是最簡單的一種集合。集合中的對象不按特定的方式排序,并且沒有重複對象。 Set接口主要實作了兩個實作類:HashSet: HashSet類按照雜湊演算法來存取集合中的對象,存取速度比較快

TreeSet :TreeSet類實作了SortedSet接口,能夠對集合中的對象進行排序。

②,List的特征是其元素以線性方式存儲,集合中可以存放重複對象。ArrayList() : 代表長度可以改變得數組。可以對元素進行随機的通路,向ArrayList()中插入與删除元素的速度慢。LinkedList(): 在實作中采用連結清單資料結構。插入和删除速度快,通路速度慢。

③,Map 是一種把鍵對象和值對象映射的集合,它的每一個元素都包含一對鍵對象和值對象。 Map沒有繼承于Collection接口 從Map集合中檢索元素時,隻要給出鍵對象,就會傳回對應的值對象。

HashMap:Map基于散清單的實作。插入和查詢“鍵值對”的開銷是固定的。可以通過構造器設定容量capacity和負載因子load factor,以調整容器的性能。

LinkedHashMap: 類似于HashMap,但是疊代周遊它時,取得“鍵值對”的順序是其插入次序,或者是最近最少使用(LRU)的次序。隻比HashMap慢一點。而在疊代通路時發而更快,因為它使用連結清單維護内部次序。

TreeMap : 基于紅黑樹資料結構的實作。檢視“鍵”或“鍵值對”時,它們會被排序(次序由Comparabel或Comparator決定)。TreeMap的特點在 于,你得到的結果是經過排序的。TreeMap是唯一的帶有subMap()方法的Map,它可以傳回一個子樹。

WeakHashMap :弱鍵(weak key)Map,Map中使用的對象也被允許釋放: 這是為解決特殊問題設計的。如果沒有map之外的引用指向某個“鍵”,則此“鍵”可以被垃圾收集器回收。

2,ArrayMap和HashMap的對比

①、存儲方式不同HashMap内部有一個HashMapEntry<K, V>[]對象,每一個鍵值對都存儲在這個對象裡,當使用put方法添加鍵值對時,就會new一個HashMapEntry對象。

②、添加資料時擴容時的處理不一樣,進行了new操作,重新建立對象,開銷很大。ArrayMap用的是copy資料,是以效率相對要高。

③、ArrayMap提供了數組收縮的功能,在clear或remove後,會重新收縮數組,是否空間。

④、ArrayMap采用二分法查找。

3,HashMap和HashTable的差別

①, HashMap不是線程安全的,效率高一點、方法不是Synchronize的要提供外同步,有containsvalue和containsKey方法。

②,HashTable是線程安全的,不允許有null的鍵和值,效率稍低,方法是是Synchronize的。有contains方法方法。Hashtable 繼承于Dictionary 類。

4,HashMap與HashSet的差別

①,HashMap:HashMap實作了Map接口,HashMap儲存鍵值對,使用put()方法将元素放入map中,HashMap中使用鍵對象來計算hashcode值,HashMap比較快,因為是使用唯一的鍵來擷取對象。

②,HashSet實作了Set接口,HashSet僅僅存儲對象,使用add()方法将元素放入set中,HashSet使用成員對象來計算hashcode值,對于兩個對象來說hashcode可能相同,是以equals()方法用來判斷對象的相等性,如果兩個對象不同的話,那麼傳回false。HashSet較HashMap來說比較慢。

三,線程部分

1,開啟線程的三種方式

繼承Thread類、實作Runable接口和使用線程池

2,程序和線程的差別

程序是cpu資源配置設定的最小機關,線程是cpu排程的最小機關。

程序之間不能共享資源,而線程共享所在程序的位址空間和其它資源。

一個程序内可擁有多個線程,程序可開啟程序,也可開啟線程。

一個線程隻能屬于一個程序,線程可直接使用同程序的資源,線程依賴于程序而存在。

3,run()和start()方法差別

start()方法被用來啟動新建立的線程,而且start()内部調用了run()方法,這和直接調用run()方法的效果不一樣。當你調用run()方法的時候,隻會是在原來的線程中調用,沒有新的線程啟動,start()方法才會啟動新線程。

4,如何控制某個方法允許并發通路線程的個數

semaphore.acquire() 請求一個信号量,這時候的信号量個數-1(一旦沒有可使用的信号量,也即信号量個數變為負數時,再次請求的時候就會阻塞,直到其他線程釋放了信号量)

semaphore.release() 釋放一個信号量,此時信号量個數+1

5,在Java中wait和seelp方法的不同

Java程式中wait 和 sleep都會造成某種形式的暫停,它們可以滿足不同的需要。wait()方法用于線程間通信,如果等待條件為真且其它線程被喚醒時它會釋放鎖,而sleep()方法僅僅釋放CPU資源或者讓目前線程停止執行一段時間,但不會釋放鎖。

6,談談wait/notify關鍵字的了解

等待對象的同步鎖,需要獲得該對象的同步鎖才可以調用這個方法,否則編譯可以通過,但運作時會收到一個異常:IllegalMonitorStateException。

調用任意對象的 wait() 方法導緻該線程阻塞,該線程不可繼續執行,并且該對象上的鎖被釋放。

喚醒在等待該對象同步鎖的線程(隻喚醒一個,如果有多個在等待),注意的是在調用此方法的時候,并不能确切的喚醒某一個等待狀态的線程,而是由JVM确定喚醒哪個線程,而且不是按優先級。

調用任意對象的notify()方法則導緻因調用該對象的 wait()方法而阻塞的線程中随機選擇的一個解除阻塞(但要等到獲得鎖後才真正可執行)。

7,什麼導緻線程阻塞?線程如何關閉

阻塞式方法是指程式會一直等待該方法完成期間不做其他事情,ServerSocket的accept()方法就是一直等待用戶端連接配接。這裡的阻塞是指調用結果傳回之前,目前線程會被挂起,直到得到結果之後才會傳回。此外,還有異步和非阻塞式方法在任務完成前就傳回。

一種是調用它裡面的stop()方法,另一種就是你自己設定一個停止線程的标記 (推薦這種)

8,談談對Synchronized關鍵字,類鎖,方法鎖,重入鎖的了解

java的對象鎖和類鎖:java的對象鎖和類鎖在鎖的概念上基本上和内置鎖是一緻的,但是,兩個鎖實際是有很大的差別的,對象鎖是用于對象執行個體方法,或者一個對象執行個體上的,類鎖是用于類的靜态方法或者一個類的class對象上的。我們知道,類的對象執行個體可以有很多個,但是每個類隻有一個class對象,是以不同對象執行個體的對象鎖是互不幹擾的,但是每個類隻有一個類鎖。但是有一點必須注意的是,其實類鎖隻是一個概念上的東西,并不是真實存在的,它隻是用來幫助我們了解鎖定執行個體方法和靜态方法的差別的

9,synchronized 和volatile 關鍵字的差別

①,volatile本質是在告訴jvm目前變量在寄存器(工作記憶體)中的值是不确定的,需要從主存中讀取;synchronized則是鎖定目前變量,隻有目前線程可以通路該變量,其他線程被阻塞住。

②,volatile僅能使用在變量級别;synchronized則可以使用在變量、方法、和類級别的。

③,volatile僅能實作變量的修改可見性,不能保證原子性;而synchronized則可以保證變量的修改可見性和原子性。

④,volatile不會造成線程的阻塞;synchronized可能會造成線程的阻塞。

⑤,volatile标記的變量不會被編譯器優化;synchronized标記的變量可以被編譯器優化。

10,死鎖的四個必要條件

系統資源的競争系統資源的競争導緻系統資源不足,以及資源配置設定不當,導緻死鎖。

程序運作推進順序不合适

互斥條件:一個資源每次隻能被一個程序使用,即在一段時間内某 資源僅為一個程序所占有。此時若有其他程序請求該資源,則請求程序隻能等待。

請求與保持條件:程序已經保持了至少一個資源,但又提出了新的資源請求,而該資源 已被其他程序占有,此時請求程序被阻塞,但對自己已獲得的資源保持不放。

不可剝奪條件:程序所獲得的資源在未使用完畢之前,不能被其他程序強行奪走,即隻能 由獲得該資源的程序自己來釋放(隻能是主動釋放)。

循環等待條件: 若幹程序間形成首尾相接循環等待資源的關系

這四個條件是死鎖的必要條件,隻要系統發生死鎖,這些條件必然成立,而隻要上述條件之一不滿足,就不會發生死鎖。

四,JVM部分

1,記憶體模型

  • 棧:儲存局部變量 (線程私有 使用完畢就會釋放)
  • 堆:儲存 new 出來的東西 成員方法等 (線程共享 使用完畢 等待gc清理)
  • 方法區: 對象的運作過程 (線程共享)
  • 本地方法區:為系統方法使用 (線程私有)
  • 寄存器:為CPU提供
  • 程式計數器:指向目前線程正在執行的指令的位址,確定多線程下正常運作(線程私有)

2,Jvm 調用方法過程

  • 在運作前确認方法中的 局部變量的數量、操作棧大小 和 方法參數數量
  • JVM在執行方法中 會将 局部變量,操作數,方法傳回位址等資訊 儲存在 棧幀中,一個線程中 隻有位于頂部的棧幀處于活動中

3,GC清理 及 清理算法

  • 程式計數法
  • 程式可達性

清理算法

  • 複制回收算法 :記憶體使用率50%,隻使用一半記憶體, 位址連貫,多用于新生代。
  • 标記清除算法:使用率100%,位址碎片化,多用于老年代
  • 标記整理算法:在标記清除基礎上,對于存活對象進行整理,多用于碎片較多的老年代。

繼續閱讀