1. 程式人生 > 程式設計 >java開發面試問答----基礎篇

java開發面試問答----基礎篇

重寫和過載的區別

  • 重寫(Override)是子類對父類的允許訪問的方法的實現過程進行重新編寫,返回值和形參都不能改變
  • 過載(overloading)是在一個類裡面,方法名字相同,而引數不同。

抽象類和介面有什麼區別

  • 抽象類是類的抽象,目的在於找出類的共同點,抽象類的不同點,介面是行為的抽象,每個行為的具體實現都是不同的。
  • 實現上,抽象類可以有建構函式和普通成員變數
  • 一個類只能繼承一個抽象類,但是可以實現多個介面

反射的用途和實現

  • 反射用於在jvm執行過程中動態的獲取物件的類資訊,通常用於框架開發如spring
    • 判斷任意一個物件所屬的類
    • 構造任意一個類的物件
    • 判斷任意一個類所具有的成員變數和方法,包括private,比如idea的輸入提示
    • 呼叫任意一個物件的方法
  • 實現可以通過物件的getclass方法獲取類,或者使用class包的class.forname通過類路徑找到類,然後可以使用class的newInstance方法建立新的物件,也可以通過獲取類的constructor物件使用指定的建構函式建立物件。

int 和 Integer 有什麼區別

  • Integer是int的包裝類,int則是java的一種基本資料型別
  • Integer實際是物件的引用,當new一個Integer時,實際上是生成一個指標指向此物件;而int則是直接儲存資料值
  • Integer的預設值是null,int的預設值是0

equals 和 == 有什麼區別

  • == 比較的是變數(棧)記憶體中存放的物件的(堆)記憶體地址,用來判斷兩個物件的地址是否相同,即是否是指相同一個物件。比較的是真正意義上的指標操作
  • equals用來比較的是兩個物件的內容是否相等

Integer使用==和int型比較為什麼在127以下是相等的而128不等

當Integer和int比較時,java會自動對int裝箱(Integer.valueOf),由於大多數int比較都在128以下,因此java將-128到127的數放入了快取,返回的是快取中的同一個物件而不是新的物件

類載入,隔離機制

類載入的過程

類載入主要有三個過程,裝載,連線,初始化;裝載是指查詢和匯入class檔案到記憶體中,連線則是根據class二進位制資料生成物件,這裡會進行類的校驗保證資料符合jvm規範,靜態變數記憶體分配和符號引用的解析;初始化則是類的初始化操作,這裡會進行靜態變數和靜態程式碼塊的初始化,執行類的構造器。

雙親委派機制

jvm中有三類載入器,啟動類載入器,擴充套件類載入器和應用類載入器,雙親委派機制是說當應用類載入器需要載入一個類時不會直接載入而是到父載入器中查詢,找不到就找祖載入器,只有都找不到時才會自己載入。

隔離機制

每個類載入器都有自己的載入範圍以保證記憶體隔離,對於同一個類的評判標準是:類名一致,類載入器一致,類載入器例項一致。

如果黑客手寫了一個string.class用自定義載入器載入會生效嗎

不會生效,因為父類載入器已經載入了string.class,當其他類載入時會直接載入系統的string.class

多執行緒環境如何保證只有一個class物件

擴充套件類載入器在載入類時使用了concurrentHashMap和synchronized,concurrentHashMap保證了只有一個執行緒能往裡面放物件,而synchronized則保證了載入時只有一個類能被載入

如何破壞雙親委派

自定義類載入器通常是繼承擴充套件類載入器,實現自身findclass方法,如果要破壞雙親委派則要重寫loadclass方法

序列化方式

有兩種方式,一種是使用OutputStream類的wirteobject方法,二種是實現Serializable介面

如何判斷一個檔案是否存在,如何讀取一個目錄下的所有檔案和子目錄

建立file類物件,呼叫exist方法判斷是否存在,並使用isfile方法判斷是否是檔案還是目錄,目錄的話可以使用listfile列出目錄下所有檔案和子目錄

nio aio bio

  • bio,同步阻塞io:客戶端發起一個請求,服務端起一個執行緒處理請求
  • nio,同步非阻塞io:客戶端發起一個請求時,服務端生成一個channel建立連線,channel註冊到多路複用器上,selector掃描channel,當channel有資料寫到buffer時扔給執行緒處理
  • aio,非同步非阻塞io:客戶端發起一個請求時,服務端標記這個io,當系統處理完時回撥服務端,服務端處理這個請求

select poll epoll

三種系統的io處理模式,他們都是同步io,使用的多路複用器,當有流需要處理時必須自己處理。

  • select 和nio很像,當有流需要io處理時,輪訓多路複用器上所有的檔案描述符,每個檔案描述符對應一個socket,找到需要處理的流
  • poll 是對select的優化,select由於在使用者空間操作,每個埠對應的連線數有限制,而poll是將資料移到核心空間處理,只需要檢查檔案描述符對應的裝置狀態即可,因為處理連結串列儲存fd因此沒有連線數的限制
  • epoll 則是對poll的優化,當有流進來時會生成io事件通知,然後程式處理對應的io事件,當fd就緒時核心會通過回撥啟用fd

堆,棧,gc

jvm的作用

java程式碼編譯成.class存在作業系統相容問題,而jdk是根據作業系統安裝的,所以jdk中的jvm載入class檔案可以遮蔽掉作業系統的相容性問題

jmm是什麼

jmm是java記憶體模型,和cpu硬體結構相似,每個執行緒有自己的工作記憶體空間,並與主記憶體互動,當有新的變數時首先寫入主記憶體然後拷貝到工作記憶體,好處是可以提高處理速度,並且執行緒之間記憶體隔離。

堆,棧

堆存放動態產生的資料,如new的物件,而棧存放區域性變數,包括基礎資料型別的值和物件的引用

一次gc的過程

堆分為新生代,老年代,永久代(常量池,元資料),java 記憶體分配和回收的策略是分代分配分代回收,java young gc採用的是停止-複製清理法。新生代分為eden區和兩個存活區,當一個物件被建立時首先分配到eden區中,當eden區滿時觸發young gc將消亡的物件清理掉並把存活的物件複製到存活區0;之後,young gc在清理eden的同時清理存活區0,把存活的物件複製到存活區1,此時存活區0清空;如此反覆,兩個存活區總有一個是空的,每切換一次存活物件的年齡加1,當多次切換後(預設年齡是8)仍存活的物件將複製到老年代;當老年代滿時觸發full gc。如果存入eden區的物件非常大,超過eden區的大小則會直接放入老年代。

如何主動觸發gc

jvm判斷是否是垃圾物件用的是可達性分析法,判斷這個物件是否有引用; 使用system.gc主動觸發full gc;

jvm相關命令jstak,jmap,jstat,如何dump記憶體

  • jstat:記憶體管理工具,可以檢視gc和當前記憶體使用統計情況;
  • jstack:用來跟蹤堆疊,分析當前程式的執行情況 ,可以dump出當前的堆疊資訊
  • jmap:可以dump出堆資訊,分析當前gc情況。

排查頻繁gc

  • 思路:引起gc的原因通常有2類,一類是記憶體洩漏,一類是大物件儲存,因此可以從這2個方向去排查問題
    • 首先jmap dump出記憶體檔案,jstack dump出堆疊資訊
    • 使用MAT工具分析記憶體dump檔案,找到大量建立的物件和記憶體佔用最大的物件
    • 到堆疊dump資訊中找尋問題物件相關的堆疊資訊還原現場
    • 優化程式碼,針對記憶體洩漏修改程式碼邏輯及時釋放物件,針對大物件要分拆

資料結構

ArrayList,LinkedList,SynchronizedList and Vector,CopyAndWriteArrayList

ArrayList,LinkedList 和Vector都實現了List介面,區別在於:

  • ArrayList內部實際上是一個陣列,當更多元素加入時,其大小會動態的增長,每次增長50%,在使用時如果能預估陣列的大小進行初始化,能大幅減少調整容量的開銷。
  • LinkedList內部是一個雙連結串列,其和ArrayList相比優勢在於增刪操作比較快,而get和set操作比較慢
  • Vector和ArrayList一樣內部是一個陣列,區別在於Vector是執行緒安全的,當Vector資料增長時預設每次擴容一倍但是長度可控。
  • SynchronizedList和Vector一樣是執行緒安全的,他的區別在於可以將任意List轉成執行緒安全的類,但是缺點在於其內部實現機制上遍歷操作不是執行緒安全的需要手動加鎖。
  • CopyAndWriteArrayList是對vector做的優化,vector使用Synchronized鎖住讀寫操作,而CopyAndWriteArrayList不鎖讀操作,寫操作時使用lock上鎖當寫操作完成時替換整個array。

HashMap原理

  • hashmap concurrenthashmap
    • hashmap
      • java7是由陣列和連結串列組成的,每一個陣列元素存的是entry
      • get: 根據key的hash值找到陣列的位置,然後比較連結串列中每個元素的key得到value
      • put: 根據key的hash值找到陣列的位置,然後比較連結串列中是否存在該key,沒有存在則將該 entry存入連結串列
      • resize: hashmap初始化時有陣列容量和負載因子,負載因子預設0.75,當陣列中存放個數大 於容量*負載因子時進行擴容操作容量翻倍
      • java8加入紅黑樹,當連結串列長度大於8時會變成紅黑樹
    • concurrenthashmap
      • 採用分段設計,每個段其實就是一個加了同步鎖的hashmap
  • ConcurrentHashMap 和 hashtable
    • hashtable同步會鎖住整個資料,而ConcurrentHashMap採用分段設計,每次只會鎖住一段資料