面試題:各大公司Java後端開發面試題總結 已看1 背1 有用 連接有必要看看

ThreadLocal(線程變量副本)       --整理javascript

Synchronized實現內存共享,ThreadLocal爲每一個線程維護一個本地變量。php

採用空間換時間,它用於線程間的數據隔離,爲每個使用該變量的線程提供一個副本,每一個線程均可以獨立地改變本身的副本,副本之間不共享數據.而不會和其餘線程的副本衝突。css

ThreadLocal類中維護一個Map,用於存儲每個線程的變量副本,Map中元素的鍵爲線程對  象,而值爲對應線程的變量副本。html

ThreadLocal在Spring中發揮着巨大的做用,在管理Request做用域中的Bean、事務管理、任務調度、AOP等模塊都出現了它的身影。java

Spring中絕大部分Bean均可以聲明成Singleton做用域,採用ThreadLocal進行封裝,所以有狀態的Bean就可以以singleton的方式在多線程中正常工做了。web

友情連接:深刻研究java.lang.ThreadLocal類面試


Java內存模型:算法

Java虛擬機規範中將Java運行時數據分爲六種。spring

1.程序計數器:是一個數據結構,用於保存當前正常執行的程序的內存地址。Java虛擬機的多線程就是經過線程輪流切換並分配處理器時間來實現的,爲了線程切換後能恢復到正確的位置,每條線程都須要一個獨立的程序計數器,互不影響,該區域爲「線程私有」。sql

2.Java虛擬機棧:線程私有的,與線程生命週期相同,用於存儲局部變量表,操做棧,方法返回值局部變量表放着基本數據類型,還有對象的引用

3.本地方法棧:跟虛擬機棧很像,不過它是爲虛擬機使用到的Native方法服務

4.Java堆:全部線程共享的一塊內存區域,對象實例幾乎都在這分配內存

5.方法區:各個線程共享的區域儲存虛擬機加載的類信息,常量,靜態變量,編譯後的代碼

6.運行時常量池:表明運行時每一個class文件中的常量表。包括幾種常量:編譯時的數字常量、方法或者域的引用

友情連接: Java中JVM虛擬機詳解


「你能不能談談,java GC是在何時,對什麼東西,作了什麼事情?」

在何時:

1.新生代有一個Eden區和兩個survivor區,首先將對象放入Eden區,若是空間不足就向其中的一個survivor區上放,若是仍然放不下就會引起一次發生在新生代的minor GC,將存活的對象放入另外一個survivor區中,而後清空Eden和以前的那個survivor區的內存。在某次GC過程當中,若是發現仍然又放不下的對象,就將這些對象放入老年代內存裏去。

2.大對象以及長期存活的對象直接進入老年區

3.當每次執行minor GC的時候應該對要晉升到老年代的對象進行分析,若是這些立刻要到老年區的老年對象的大小超過了老年區的剩餘大小,那麼執行一次Full GC以儘量地得到老年區的空間。

對什麼東西:從GC Roots搜索不到,並且通過一次標記清理以後仍沒有復活的對象。

作什麼: 
新生代:複製清理; 
老年代:標記-清除和標記-壓縮算法; 
永久代:存放Java中的類和加載類的類加載器自己。

GC Roots都有哪些: 
1. 虛擬機棧中的引用的對象 
2. 方法區中靜態屬性引用的對象,常量引用的對象 
3. 本地方法棧中JNI(即通常說的Native方法)引用的對象

友情連接:Java GC的那些事(上)

友情連接:Java GC的那些事(下)

友情連接:CMS垃圾收集器介紹


Synchronized 與Lock都是可重入鎖同一個線程再次進入同步代碼的時候.可使用本身已經獲取到的鎖。

Synchronized是悲觀鎖機制,獨佔鎖。而Locks.ReentrantLock是樂觀鎖,每次不加鎖而是假設沒有衝突而去完成某項操做,若是由於衝突失敗就重試,直到成功爲止。 

b) tryLock(), 若是獲取了鎖當即返回true,若是別的線程正持有鎖,當即返回false;
c)tryLock(long timeout,TimeUnit unit), 若是獲取了鎖定當即返回true,若是別的線程正持有鎖,會等待參數給定的時間,在等待的過程當中,若是獲取了鎖定,就返回true,若是等待超時,返回false;
ReentrantLock適用場景

  1. 某個線程在等待一個鎖的控制權的這段時間須要中斷
  2. 須要分開處理一些wait-notify,ReentrantLock裏面的Condition應用,可以控制notify哪一個線程,鎖能夠綁定多個條件。
  3. 具備公平鎖功能,每一個到來的線程都將排隊等候。

友情連接: Synchronized關鍵字、Lock,並解釋它們之間的區別


StringBuffer是線程安全的,每次操做字符串,String會生成一個新的對象,而StringBuffer不會;StringBuilder是非線程安全的

友情連接:String、StringBuffer與StringBuilder之間區別


fail-fast:機制是java集合(Collection)中的一種錯誤機制。當多個線程對同一個集合的內容進行操做時,就可能會產生fail-fast事件。 
例如:當某一個線程A經過iterator去遍歷某集合的過程當中,若該集合的內容被其餘線程所改變了;那麼線程A訪問集合時,就會拋出ConcurrentModificationException異常,產生fail-fast事件


happens-before:若是兩個操做之間具備happens-before 關係,那麼前一個操做的結果就會對後面一個操做可見。 
1.程序順序規則:一個線程中的每一個操做,happens- before 於該線程中的任意後續操做。 
2.監視器鎖規則:對一個監視器鎖的解鎖,happens- before 於隨後對這個監視器鎖的加鎖。 
3.volatile變量規則:對一個volatile域的寫,happens- before於任意後續對這個volatile域的讀。 
4.傳遞性:若是A happens- before B,且B happens- before C,那麼A happens- before C。 
5.線程啓動規則:Thread對象的start()方法happens- before於此線程的每個動做。


Volatile和Synchronized四個不一樣點: 
1 粒度不一樣,前者針對變量 ,後者鎖對象和類 
2 syn阻塞,volatile線程不阻塞 
3 syn保證三大特性,volatile不保證原子性 
4 syn編譯器優化,volatile不優化 
volatile具有兩種特性: 
1. 保證此變量對全部線程的可見性,指一條線程修改了這個變量的值,新值對於其餘線程來講是可見的,但並非多線程安全的。 
2. 禁止指令重排序優化。 
Volatile如何保證內存可見性: 
1.當寫一個volatile變量時JMM會把該線程對應的本地內存中的共享變量刷新到主內存。 
2.當讀一個volatile變量時,JMM會把該線程對應的本地內存置爲無效。線程接下來將從主內存中讀取共享變量。

同步:就是一個任務的完成須要依賴另一個任務,只有等待被依賴的任務完成後,依賴任務才能完成。 
異步:不須要等待被依賴的任務完成,只是通知被依賴的任務要完成什麼工做,只要本身任務完成了就算完成了,被依賴的任務是否完成會通知回來。(異步的特色就是通知)。 
打電話和發短信來比喻同步和異步操做。 
阻塞:CPU停下來等一個慢的操做完成之後,纔會接着完成其餘的工做。 
非阻塞:非阻塞就是在這個慢的執行時,CPU去作其餘工做,等這個慢的完成後,CPU纔會接着完成後續的操做。 
非阻塞會形成線程切換增長,增長CPU的使用時間能不能補償系統的切換成本須要考慮。

友情連接:Java併發編程之volatile關鍵字解析


CAS(Compare And Swap) 無鎖算法: 
CAS是樂觀鎖技術,當多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程並不會被掛起,而是被告知此次競爭中失敗,並能夠再次嘗試CAS有3個操做數,內存值V,舊的預期值A,要修改的新值B。當且僅當預期值A和內存值V相同時,將內存值V修改成B,不然什麼都不作。

友情連接:非阻塞同步算法與CAS(Compare and Swap)無鎖算法


線程池的做用: 
程序啓動的時候就建立若干線程來響應處理,它們被稱爲線程池,裏面的線程叫工做線程 
第一:下降資源消耗。經過重複利用已建立的線程下降線程建立和銷燬形成的消耗。 
第二:提升響應速度。當任務到達時,任務能夠不須要等到e線程建立就能當即執行。 
第三:提升線程的可管理性。 
經常使用線程池:ExecutorService 是主要的實現類,其中經常使用的有 
Executors.newSingleThreadPool(),newFixedThreadPool(),newcachedTheadPool(),newScheduledThreadPool()。

友情連接:線程池原理

友情連接:線程池原理解析


類加載器工做機制: 
1.加載:將Java二進制代碼導入jvm中,生成Class文件。 
2.鏈接:a)校驗:檢查載入Class文件數據的正確性 (檢查數據結構)b)準備:給類的靜態變量分配存儲空間 c)解析:將符號引用轉成直接引用 (java類並不知道所引用的類的實際地址,所以只能使用符號引用來代替)
3:初始化:對類的靜態變量,靜態方法和靜態代碼塊執行初始化工做。

雙親委派模型:類加載器收到類加載請求,首先將請求委派給父類加載器完成  確保類的惟一性
用戶自定義加載器->應用程序加載器-appClassLoad用於加載自定義類的加載器>擴展類加載器-extClassLoad用於加載:%JDK%/jre/lib/ext目錄下的第三方jar包中的類>啓動類加載器bootstrapclassload 根類加載器:打印:null。用於加載Java類庫中的類

友情連接:深刻理解Java虛擬機筆記—雙親委派模型 

友情連接:JVM類加載的那些事

友情連接:JVM(1):Java 類的加載機制


一致性哈希:

Memcahed緩存: 
數據結構:key,value對 
使用方法:get,put等方法

友情連接:hashcode(),equal()方法深刻解析


Redis數據結構: String—字符串(key-value 類型) 
Hash—字典(hashmap) Redis的哈希結構能夠使你像在數據庫中更新一個屬性同樣只修改某一項屬性值 
List—列表 實現消息隊列 
Set—集合 利用惟一性   Zset 
Sorted Set—有序集合 能夠進行排序 
能夠實現數據持久化

友情連接: Spring + Redis 實現數據的緩存


java自動裝箱拆箱深刻剖析

談談Java反射機制

如何寫一個不可變類?

要建立不可變類,要實現下面幾個步驟:

  1. 將類聲明爲final,因此它不能被繼承
  2. 將全部的成員聲明爲私有的,這樣就不容許直接訪問這些成員
  3. 對變量不要提供setter方法
  4. 將全部可變的成員聲明爲final,這樣只能對它們賦值一次
  5. 經過構造器初始化全部成員,進行深拷貝(deep copy)
  6. 在getter方法中,不要直接返回對象自己,而是克隆對象,並返回對象的拷貝

索引:B+,B-,全文索引 
Mysql的索引是一個數據結構,旨在使數據庫高效的查找數據。 
經常使用的數據結構是B+Tree每一個葉子節點不但存放了索引鍵的相關信息還增長了指向相鄰葉子節點的指針,這樣就造成了帶有順序訪問指針的B+Tree,作這個優化的目的是提升不一樣區間訪問的性能。 
何時使用索引: 
1. 常常出如今group by,order by和distinc關鍵字後面的字段 
2. 常常與其餘表進行鏈接的表,在鏈接字段上應該創建索引 
3. 常常出如今Where子句中的字段 
4. 常常出現用做查詢選擇的字段

友情連接:MySQL:InnoDB存儲引擎的B+樹索引算法

友情連接:MySQL索引背後的數據結構及算法原理


Spring IOC (控制反轉,依賴注入)

Spring支持三種依賴注入方式,分別是屬性(Setter方法)注入,構造注入和對象注入。

在Spring中,那些組成應用的主體及由Spring IOC容器所管理的對象被稱之爲Bean

Spring的IOC容器經過反射的機制實例化Bean並創建Bean之間的依賴關係。 
簡單地講,Bean就是由Spring IOC容器初始化、裝配及被管理的對象。 
獲取Bean對象的過程,首先經過Resource加載配置文件並啓動IOC容器,而後經過getBean方法獲取bean對象,就能夠調用他的方法。 
Spring Bean的做用域: 
Singleton:Spring IOC容器中只有一個共享的Bean實例,通常都是Singleton做用域。 
Prototype:每個請求,會產生一個新的Bean實例。 
Request:每一次http請求會產生一個新的Bean實例。

友情連接: Spring框架IOC容器和AOP解析

友情連接:淺談Spring框架註解的用法分析

友情連接:關於Spring的69個面試問答——終極列表 

 
 
 
 
 

關於Spring的69個面試問答——終極列表

這篇文章總結了一些關於Spring框架的重要問題,這些問題都是你在面試或筆試過程當中可能會被問到的。下次你不再用擔憂你的面試了,Java Code Geeks這就幫你解答。

大多數你可能被問到的問題都列舉在下面的列表中了。全部的核心模塊,從基礎的Spring功能(如Spring Beans)到上層的Spring MVC框架,文章中都會進行簡短的講解。看完這些面試問題,你應該看看咱們的Spring教程

咱們開始吧!

目錄

Spring概述

依賴注入

Spring Beans

Spring註解

Spring的對象訪問

Spring面向切面編程

Spring MVC框架

Spring概述

1.什麼是Spring?

Spring是一個開源的Java EE開發框架。Spring框架的核心功能能夠應用在任何Java應用程序中,但對Java EE平臺上的Web應用程序有更好的擴展性。Spring框架的目標是使得Java EE應用程序的開發更加簡捷,經過使用POJO爲基礎的編程模型促進良好的編程風格。

2.Spring有哪些優勢?

  • 輕量級:Spring在大小和透明性方面絕對屬於輕量級的,基礎版本的Spring框架大約只有2MB。

  • 控制反轉(IOC):Spring使用控制反轉技術實現了鬆耦合。依賴被注入到對象,而不是建立或尋找依賴對象。

  • 面向切面編程(AOP): Spring支持面向切面編程,同時把應用的業務邏輯與系統的服務分離開來。

  • 容器:Spring包含並管理應用程序對象的配置及生命週期

  • MVC框架:Spring的web框架是一個設計優良的web MVC框架,很好的取代了一些web框架

  • 事務管理:Spring對下至本地業務上至全局業務(JAT)提供了統一的事務管理接口

  • 異常處理:Spring提供一個方便的API將特定技術的異常(由JDBC, Hibernate, 或JDO拋出)轉化爲一致的、Unchecked異常。


代理的共有優勢:業務類只須要關注業務邏輯自己,保證了業務類的重用性。 
Java靜態代理: 
代理對象和目標對象實現了相同的接口,目標對象做爲代理對象的一個屬性,具體接口實現中,代理對象能夠在調用目標對象相應方法先後加上其餘業務處理邏輯。 
缺點:一個代理類只能代理一個業務類。若是業務類增長方法時,相應的代理類也要增長方法。 
Java動態代理: 
Java動態代理是寫一個類實現InvocationHandler接口,重寫Invoke方法,在Invoke方法能夠進行加強處理的邏輯的編寫,這個公共代理類在運行的時候才能明確本身要代理的對象,同時能夠實現該被代理類的方法的實現,而後在實現類方法的時候能夠進行加強處理。 
實際上:代理對象的方法 = 加強處理 + 被代理對象的方法

JDK和CGLIB生成動態代理類的區別: 
JDK動態代理只能針對實現了接口的類生成代理(實例化一個類)。此時代理對象和目標對象實現了相同的接口,目標對象做爲代理對象的一個屬性,具體接口實現中,能夠在調用目標對象相應方法先後加上其餘業務處理邏輯 
CGLIB是針對類實現代理,主要是對指定的類生成一個子類(沒有實例化一個類),覆蓋其中的方法 。 
Spring AOP應用場景 
性能檢測訪問控制,日誌管理,事務等。 
默認的策略是若是目標類實現接口,則使用JDK動態代理技術,若是目標對象沒有實現接口,則默認會採用CGLIB代理


SpringMVC運行原理 
1. 客戶端請求提交到DispatcherServlet 
2. 由DispatcherServlet控制器查詢HandlerMapping,找到並分發到指定的Controller中。 
4. Controller調用業務邏輯處理後,返回ModelAndView 
5. DispatcherServlet查詢一個或多個ViewResoler視圖解析器,找到ModelAndView指定的視圖 
6. 視圖負責將結果顯示到客戶端

友情連接:Spring:基於註解的Spring MVC(上)

友情連接: Spring:基於註解的Spring MVC(下) 

友情連接:SpringMVC與Struts2區別與比較總結

友情連接:SpringMVC與Struts2的對比 


一個Http請求 
DNS域名解析 –> 發起TCP的三次握手 –> 創建TCP鏈接後發起http請求 –> 服務器響應http請求,瀏覽器獲得html代碼 –> 瀏覽器解析html代碼,並請求html代碼中的資源(如javascript、css、圖片等) –> 瀏覽器對頁面進行渲染呈現給用戶

設計存儲海量數據的存儲系統:設計一個叫「中間層」的一個邏輯層,在這個層,將數據庫的海量數據抓出來,作成緩存,運行在服務器的內存中,同理,當有新的數據到來,也先作成緩存,再想辦法,持久化到數據庫中,這是一個簡單的思路。主要的步驟是負載均衡,將不一樣用戶的請求分發到不一樣的處理節點上,而後先存入緩存,定時向主數據庫更新數據。讀寫的過程採用相似樂觀鎖的機制,能夠一直讀(在寫數據的時候也能夠),可是每次讀的時候會有個版本的標記,若是本次讀的版本低於緩存的版本,會從新讀數據,這樣的狀況並很少,能夠忍受。

友情連接: HTTP與HTTPS的區別

友情連接: HTTPS 爲何更安全,先看這些 

友情連接: HTTP請求報文和HTTP響應報文

友情連接: HTTP 請求方式: GET和POST的比較

什麼是HTTP?
超文本傳輸協議(HyperText Transfer Protocol -- HTTP)是一個設計來使客戶端和服務器順利進行通信的協議。
HTTP在客戶端和服務器之間以request-response protocol(請求-回覆協議)工做。
 
GET - 從指定的服務器中獲取數據
POST - 提交數據給指定的服務器處理
 
GET方法:
使用GET方法時,查詢字符串(鍵值對)被附加在URL地址後面一塊兒發送到服務器:
/test/demo_form.jsp?name1=value1&name2=value2
特色:
  • GET請求可以被緩存
  • GET請求會保存在瀏覽器的瀏覽記錄中
  • 以GET請求的URL可以保存爲瀏覽器書籤
  • GET請求有長度限制
  • GET請求主要用以獲取數據
POST方法:
使用POST方法時,查詢字符串在POST信息中單獨存在,和HTTP請求一塊兒發送到服務器:
POST /test/demo_form.jsp HTTP/1.1
Host: w3schools.com
name1=value1&name2=value2
特色:
  • POST請求不能被緩存下來
  • POST請求不會保存在瀏覽器瀏覽記錄中
  • 以POST請求的URL沒法保存爲瀏覽器書籤
  • POST請求沒有長度限制
GET和POST的區別:
  GET POST
點擊返回/刷新按鈕 沒有影響 數據會從新發送(瀏覽器將會提示用戶「數據被重新提交」)
添加書籤 能夠 不能夠
緩存 能夠 不能夠
編碼類型(Encoding type) application/x-www-form-urlencoded
application/x-www-form-urlencoded or multipart/form-data. 請爲二進制數據使用multipart編碼
歷史記錄 沒有
長度限制 沒有
數據類型限制 只容許ASCII字符類型 沒有限制。容許二進制數據
安全性 查詢字符串會顯示在地址欄的URL中,不安全,請不要使用GET請求提交敏感數據 由於數據不會顯示在地址欄中,也不會緩存下來或保存在瀏覽記錄中,因此看POST求情比GET請求安全,但也不是最安全的方式。如須要傳送敏感數據,請使用加密方式傳輸
可見性 查詢字符串顯示在地址欄的URL中,可見 查詢字符串不會顯示在地址欄中,不可見
其餘HTTP請求方式
方式 描述
HEAD 與GET請求相似,不一樣在與服務器只返回HTTP頭部信息,沒有頁面內容
PUT 上傳指定URL的描述
DELETE 刪除指定資源
OPTIONS 返回服務器支持的HTTP方法
CONNECT 轉換爲透明TCP/IP隧道的鏈接請求

Session與Cookie:Cookie可讓服務端跟蹤每一個客戶端的訪問,可是每次客戶端的訪問都必須傳回這些Cookie,若是Cookie不少,則無形的增長了客戶端與服務端的數據傳輸量, 
而Session則很好地解決了這個問題,同一個客戶端每次和服務端交互時,將數據存儲經過Session到服務端,不須要每次都傳回全部的Cookie值,而是傳回一個ID,每一個客戶端第一次訪問服務器生成的惟一的ID,客戶端只要傳回這個ID就好了,這個ID一般爲NAME爲JSESSIONID的一個Cookie。這樣服務端就能夠經過這個ID,來將存儲到服務端的KV值取出了。 
Session和Cookie的超時問題,Cookie的安全問題


分佈式Session框架 
1. 配置服務器,Zookeeper集羣管理服務器能夠統一管理全部服務器的配置文件 
2. 共享這些Session存儲在一個分佈式緩存中,能夠隨時寫入和讀取,並且性能要很好,如Memcache,Tair。 
3. 封裝一個類繼承自HttpSession,將Session存入到這個類中而後再存入分佈式緩存中 
4. 因爲Cookie不能跨域訪問,要實現Session同步,要同步SessionID寫到不一樣域名下。


適配器模式將一個接口適配到另外一個接口,Java I/O中InputStreamReader將Reader類適配到InputStream,從而實現了字節流到字符流的準換。 
裝飾者模式保持原來的接口,加強原來有的功能。 
FileInputStream 實現了InputStream的全部接口,BufferedInputStreams繼承自FileInputStream是具體的裝飾器實現者,將InputStream讀取的內容保存在內存中,而提升讀取的性能。


Spring事務配置方法: 
1. 切點信息,用於定位實施事物切面的業務類方法 
2. 控制事務行爲的事務屬性,這些屬性包括事物隔離級別,事務傳播行爲,超時時間,回滾規則。 
Spring經過aop/tx Schema 命名空間和@Transaction註解技術來進行聲明式事物配置


Mybatis 
每個Mybatis的應用程序都以一個SqlSessionFactory對象的實例爲核心。首先用字節流經過Resource將配置文件讀入,而後經過SqlSessionFactoryBuilder().build方法建立SqlSessionFactory,而後再經過SqlSessionFactory.openSession()方法建立一個SqlSession爲每個數據庫事務服務。 
經歷了Mybatis初始化 –>建立SqlSession –>運行SQL語句,返回結果三個過程


Servlet和Filter的區別: 
整個流程是:Filter對用戶請求進行預處理,接着將請求交給Servlet進行處理並生成響應,最後Filter再對服務器響應進行後處理。

Filter有以下幾個用處: 
Filter能夠進行對特定的url請求和相應作預處理和後處理。 
在HttpServletRequest到達Servlet以前,攔截客戶的HttpServletRequest。 
根據須要檢查HttpServletRequest,也能夠修改HttpServletRequest頭和數據。 
在HttpServletResponse到達客戶端以前,攔截HttpServletResponse。 
根據須要檢查HttpServletResponse,也能夠修改HttpServletResponse頭和數據。

實際上Filter和Servlet極其類似,區別只是Filter不能直接對用戶生成響應。實際上Filter裏doFilter()方法裏的代碼就是從多個Servlet的service()方法裏抽取的通用代碼,經過使用Filter能夠實現更好的複用。

Filter和Servlet的生命週期: 
1.Filter在web服務器啓動時初始化 
2.若是某個Servlet在web.xml配置了 1 ,(配置<load onstartup>)該Servlet也是在Tomcat(Servlet容器)啓動時初始化。 
3.若是Servlet沒有配置1 ,該Servlet不會在Tomcat啓動時初始化,而是在請求到來時初始化。 
4.每次請求, Request都會被初始化,響應請求後,請求被銷燬。   每次請求都會調用 servlet 單帶service()方法
5.Servlet初始化後,將不會隨着請求的結束而註銷。 
6.關閉Tomcat時,Servlet、Filter依次被註銷。


HashMap與HashTable的區別。 
一、HashMap是非線程安全的,HashTable是線程安全的。 
二、HashMap的鍵和值都容許有null值存在,而HashTable則不行。 
三、由於線程安全的問題,HashMap效率比HashTable的要高。

HashMap的實現機制: 
1. 維護一個每一個元素是一個鏈表的數組,並且鏈表中的每一個節點是一個Entry[]鍵值對的數據結構。 
2. 實現了數組+鏈表的特性,查找快,插入刪除也快。 
3. 對於每一個key,他對應的數組索引下標是 int i = hash(key.hashcode)&(len-1); 
4. 每一個新加入的節點放在鏈表首,而後該新加入的節點指向原鏈表首                     擴容2倍擴容 在插入元素後判斷元素是否已經到達容量的,若是到達了就進行擴容,可是頗有可能擴容以後沒有新元素插入,這時HashMap就進行了一次無效的擴容。

 containsKey 和 containsvalue 

containskey  能夠用於統計文本中 某個字符串的個數.

面試題: hashMap是怎樣實現key-value這樣鍵值對的保存?

 

HashMap中有一個內部類Entry

 

 

 

1
2
3
4
5
6
7
static  class  Entry<k,v> implements  Map.Entry<k,v> {
         final  K key;
         V value;
         Entry<k,v> next;
         int  hash;
         //.....
}</k,v></k,v></k,v>

 

主要有4個屬性,key ,hash,value,指向下一個節點的引用next ,看到這個實體類就明白了,在HashMap中存放的key-value實質是經過實體類Entry來保存的

 

 

 

面試題: hashMap的實現原理?

 

HashMap使用到的數據類型主要就是數組和鏈表,首先看原理圖

 

\

 

 
 

 

 

 

在hashMap的原理圖中,左邊是經過數組來存放鏈表的第一個節點,看懂這個圖這個問題就ok

 

面試題: hashMap的put過程?

 

面咱們提到過Entry類裏面有一個next屬性,做用是指向下一個Entry。好比說: 第一個鍵值對A進來,經過計算其key的hash獲得的index=0,記作:Entry[0] = A。一會後又進來一個鍵值對B,經過計算其index也等於0,如今怎麼辦?HashMap會這樣作:B.next = A,Entry[0] = B,若是又進來C,index也等於0,那麼C.next = B,Entry[0] = C;這樣咱們發現index=0的地方其實存取了A,B,C三個鍵值對,他們經過next這個屬性連接在一塊兒。也就是說數組中存儲的是最後插入的元素。

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public  V put(K key, V value) {
     if  (key == null )
         return  putForNullKey(value);
     int  hash = hash(key);
     int  i = indexFor(hash, table.length);
     for  (Entry<k,v> e = table[i]; e != null ; e = e.next) { //循環判斷插入的key是否已經存在,若存在就更新key對應的value
         Object k;
         if  (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
             V oldValue = e.value;
             e.value = value;
             e.recordAccess( this );
             return  oldValue;
         }
     }
 
     modCount++;
     addEntry(hash, key, value, i); //key不存在,那麼插入新的key-value
     return  null ;
}</k,v>

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void  addEntry( int  hash, K key, V value, int  bucketIndex) {
     if  ((size >= threshold) && ( null  != table[bucketIndex])) {
         resize( 2  * table.length);
         hash = ( null  != key) ? hash(key) : 0 ;
         bucketIndex = indexFor(hash, table.length);
     }
 
     createEntry(hash, key, value, bucketIndex);
}
 
void  createEntry( int  hash, K key, V value, int  bucketIndex) { //這個方法就驗證了上面說的<strong>數組中存儲的是最後插入的元素</strong>
     Entry<k,v> e = table[bucketIndex];
     table[bucketIndex] = new  Entry<>(hash, key, value, e);
     size++;
}</k,v>

 

面試題: hashMap的get過程?
這個過程比較簡單,直接看代碼:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public  V get(Object key) {
         if  (key == null )
             return  getForNullKey();
         int  hash = hash(key.hashCode());
         //先定位到數組元素,再遍歷該元素處的鏈表
         for  (Entry<k,v> e = table[indexFor(hash, table.length)];
              e != null ;
              e = e.next) {
             Object k;
             if  (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                 return  e.value;
         }
         return  null ;
}</k,v>

 HashMap其實就是一個Entry數組,Entry對象中包含了鍵和值,其中next也是一個Entry對象,它就是用來處理hash衝突的,造成一個鏈表。

  HashMap的底層主要是基於數組和鏈表來實現的,它之因此有至關快的查詢速度主要是由於它是經過計算散列碼來決定存儲的位置。HashMap中主要是經過key的hashCode來計算hash值的,只要hashCode相]同,計算出來的hash值就同樣。若是存儲的對象對多了,就有可能不一樣的對象所算出來的hash值是相同的,這就出現了所謂的hash衝突。學過數據結構的同窗都知道,解決hash衝突的方法有不少,HashMap底層是經過鏈表來解決hash衝突的。

 

 圖中,紫色部分即表明哈希表,也稱爲哈希數組,數組的每一個元素都是一個單鏈表的頭節點,鏈表是用來解決衝突的,若是不一樣的key映射到了數組的同一位置處,就將其放入單鏈表中。

保證hashmap線程安全

方法一:

優勢:代碼實現十分簡單,一看就懂.

缺點:從鎖的角度來看,方法一直接使用了鎖住方法,基本上是鎖住了儘量大的代碼塊.性能會比較差.

 

方法二:

優勢:須要互斥的代碼段比較少,性能會比較好. ConcurrentHashMap把整個Map切分紅了多個塊,發生鎖碰撞的概率大大下降,性能會比較好.

缺點:代碼實現稍稍複雜些.

HashMap和TreeMap區別 

友情連接: Java中HashMap和TreeMap的區別深刻理解

HashMap衝突

友情連接: HashMap衝突的解決方法以及原理分析

友情連接: HashMap的工做原理

友情連接: HashMap和Hashtable的區別

友情連接: 2種辦法讓HashMap線程安全


HashMap,ConcurrentHashMap與LinkedHashMap的區別

  1. ConcurrentHashMap是使用了鎖分段技術技術來保證線程安全的,鎖分段技術:首先將數據分紅一段一段的存儲而後給每一段數據配一把鎖,當一個線程佔用鎖訪問其中一個段數據的時候,其餘段的數據也能被其餘線程訪問(其餘線程也能夠分別對每段進行訪問)
  2. ConcurrentHashMap 是在每一個段(segment)中線程安全的
  3. LinkedHashMap維護一個雙鏈表,能夠將裏面的數據按寫入的順序讀出

ConcurrentHashMap應用場景

1:ConcurrentHashMap的應用場景是高併發,可是並不能保證線程安全,而同步的HashMap的是鎖住整個容器,而加鎖以後ConcurrentHashMap不須要鎖住整個容器,只須要鎖住對應的Segment就行了,因此能夠保證高併發同步訪問,提高了效率

2:能夠多線程寫。 
ConcurrentHashMap把HashMap分紅若干個Segmenet 
1.get時,不加鎖,先定位到segment而後在找到頭結點進行讀取操做而value是volatile變量,因此能夠保證在競爭條件時保證讀取最新的值,若是讀到的value是null,則可能正在修改,那麼就調用ReadValueUnderLock函數,加鎖保證讀到的數據是正確的。 
2.Put時會加鎖,一概添加到hash鏈的頭部。 
3.Remove時也會加鎖,因爲next是final類型不可改變,因此必須把刪除的節點以前的節點都複製一遍。 
4.ConcurrentHashMap容許多個修改操做併發進行,其關鍵在於使用了鎖分離技術。它使用了多個鎖來控制對Hash表的不一樣Segment進行的修改。

ConcurrentHashMap可以保證每一次調用都是原子操做,可是並不保證屢次調用之間也是原子操做。

友情連接:Java集合—ConcurrentHashMap原理分析


Vector和ArrayList的區別

友情連接:Java中Vector和ArrayList的區別


ExecutorService service = Executors…. 
ExecutorService service = new ThreadPoolExecutor() 
ExecutorService service = new ScheduledThreadPoolExecutor();

ThreadPoolExecutor源碼分析

線程池自己的狀態:

這裏寫圖片描述

等待任務隊列和工做集: 正在被執行的hashset集合 等待被執行的是 阻塞隊列

這裏寫圖片描述

線程池的主要狀態鎖:

這裏寫圖片描述

線程池的存活時間和大小:

這裏寫圖片描述

1.2 ThreadPoolExecutor 的內部工做原理 
有了以上定義好的數據,下面來看看內部是如何實現的 。 Doug Lea 的整個思路總結起來就是 5 句話: 
1. 若是當前池大小 poolSize 小於 corePoolSize ,則建立新線程執行任務。 
2. 若是當前池大小 poolSize 大於 corePoolSize ,且等待隊列未滿,則進入等待隊列 
3. 若是當前池大小 poolSize 大於 corePoolSize 且小於 maximumPoolSize ,且等待隊列已滿,則建立新線程執行任務。 
4. 若是當前池大小 poolSize 大於 corePoolSize 且大於 maximumPoolSize ,且等待隊列已滿,則調用拒絕策略來處理該任務。 
5. 線程池裏的每一個線程執行完任務後不會馬上退出,而是會去檢查下等待隊列裏是否還有線程任務須要執行,若是在 keepAliveTime 裏等不到新的任務了,那麼線程就會退出。

Executor包結構

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

CopyOnWriteArrayList : 寫時加鎖,當添加一個元素的時候,將原來的容器進行copy,複製出一個新的容器,而後在新的容器裏面寫,寫完以後再將原容器的引用指向新的容器,而讀的時候是讀舊容器的數據,因此能夠進行併發的讀,但這是一種弱一致性的策略。 
使用場景:CopyOnWriteArrayList適合使用在讀操做遠遠大於寫操做的場景裏,好比緩存。


Linux經常使用命令:cd,cp,mv,rm,ps(進程),tar,cat(查看內容),chmod,vim,find,ls


死鎖的必要條件 
1. 互斥 至少有一個資源處於非共享狀態 
2. 佔有並等待 
3. 非搶佔 
4. 循環等待 
解決死鎖,第一個是死鎖預防,就是不讓上面的四個條件同時成立。二是,合理分配資源。 
三是使用銀行家算法,若是該進程請求的資源操做系統剩餘量能夠知足,那麼就分配。


進程間的通訊方式

  1. 管道( pipe ):管道是一種半雙工的通訊方式,數據只能單向流動,並且只能在具備親緣關係的進程間使用。進程的親緣關係一般是指父子進程關係
  2. 有名管道 (named pipe) : 有名管道也是半雙工的通訊方式,可是它容許無親緣關係進程間的通訊。
  3. 信號量( semophore ) : 信號量是一個計數器,能夠用來控制多個進程對共享資源的訪問。它常做爲一種鎖機制,防止某進程正在訪問共享資源時,其餘進程也訪問該資源。所以,主要做爲進程間以及同一進程內不一樣線程之間的同步手段。
  4. 消息隊列( message queue )消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩衝區大小受限等缺點。
  5. 信號 ( sinal ) : 信號是一種比較複雜的通訊方式,用於通知接收進程某個事件已經發生。
  6. 共享內存( shared memory )共享內存就是映射一段能被其餘進程所訪問的內存,這段共享內存由一個進程建立,但多個進程均可以訪問。共享內存是最快的 IPC 方式,它是針對其餘進程間通訊方式運行效率低而專門設計的。它每每與其餘通訊機制,如信號量,配合使用,來實現進程間的同步和通訊。
  7. 套接字( socket )套解口也是一種進程間通訊機制,與其餘通訊機制不一樣的是,它可用於不一樣機器間的進程通訊。

進程與線程的區別和聯繫

進程概念

  進程是表示資源分配的基本單位,又是調度運行的基本單位。例如,用戶運行本身的程序,系統就建立一個進程,併爲它分配資源,包括各類表格、內存空間、磁盤空間、(讀寫)I/O設備等.

線程概念

  線程是進程中執行運算的最小單位,亦即CPU執行處理機調度的基本單位。若是把進程理解爲在邏輯上操做系統所完成的任務,那麼線程表示完成該任務的許多可能的子任務之一。例如,假設用戶啓動了一個窗口中的數據庫應用程序,操做系統就將對數據庫的調用表示爲一個進程假設用戶要從數據庫中產生一份工資單報表,並傳到一個文件中,這是一個子任務;在產生工資單報表的過程當中,用戶又能夠輸人數據庫查詢請求,這又是一個子任務。這樣,操做系統則把每個請求――工資單報表和新輸人的數據查詢表示爲數據庫進程中的獨立的線程。線程能夠在處理器上獨立調度執行,這樣,在多處理器環境下就容許幾個線程各自在單獨處理器上進行

 

引入線程的好處

(1)易於調度

(2)提升併發性。經過線程可方便有效地實現併發性。進程可建立多個線程來執行同一程序的不一樣部分

(3)開銷少。建立線程比建立進程要快,所需開銷不多。。

(4)利於充分發揮多處理器的功能。經過建立多線程進程(即一個進程可具備兩個或更多個線程),每一個線程在一個處理器上運行,從而實現應用程序的併發性,使每一個處理器都獲得充分運行。(例如多核CPU)

進程和線程的關係

(1)一個線程只能屬於一個進程,而一個進程能夠有多個線程,但至少有一個線程。線程是操做系統可識別的最小執行和調度單位。

(2)資源分配給進程,同一進程的全部線程共享該進程的全部資源。 同一進程中的多個線程共享代碼段(代碼和常量),數據段(全局變量和靜態變量),擴展段(堆存儲)。可是每一個線程擁有本身的棧段,棧段又叫運行時段,用來存放全部局部變量和臨時變量。

(3)處理機分給線程,即真正在處理機上運行的是線程。

(4)線程在執行過程當中,須要協做同步。不一樣進程的線程間要利用消息通訊的辦法實現同步。

 

線程與進程的比較

線程具備許多傳統進程所具備的特徵,故又稱爲輕型進程(Light—Weight Process)或進程元;而把傳統的進程稱爲重型進程(Heavy—Weight Process),它至關於只有一個線程的任務。在引入了線程的操做系統中,一般一個進程都有若干個線程,至少須要一個線程。下面,咱們從調度、併發性、 系統開銷、擁有資源等方面,來比較線程與進程。

1.調度

在傳統的操做系統中,擁有資源的基本單位和獨立調度、分派的基本單位都是進程。而在引入線程的操做系統中,則把線程做爲調度和分派的基本單位。而把進程做 爲資源擁有的基本單位,使傳統進程的兩個屬性分開,線程便能輕裝運行,從而可顯著地提升系統的併發程度。在同一進程中,線程的切換不會引發進程的切換,在 由一個進程中的線程切換到另外一個進程中的線程時,將會引發進程的切換。

2.併發性

在引入線程的操做系統中,不只進程之間能夠併發執行,並且在一個進程中的多個線程之間,亦可併發執行,於是使操做系統具備更好的併發性,從而能更有效地使 用系統資源和提升系統吞吐量。例如,在一個未引入線程的單CPU操做系統中,若僅設置一個文件服務進程,當它因爲某種緣由而被阻塞時,便沒有其它的文件服 務進程來提供服務。在引入了線程的操做系統中,能夠在一個文件服務進程中,設置多個服務線程,當第一個線程等待時,文件服務進程中的第二個線程能夠繼續運 行;當第二個線程阻塞時,第三個線程能夠繼續執行,從而顯著地提升了文件服務的質量以及系統吞吐量。

3.擁有資源

不管是傳統的操做系統,仍是設有線程的操做系統,進程都是擁有資源的一個獨立單位,它能夠擁有本身的資源。通常地說,線程本身不擁有系統資源(也有一點必 不可少的資源),但它能夠訪問其隸屬進程的資源。亦即,一個進程的代碼段、數據段以及系統資源,如已打開的文件、I/O設備等,可供問一進程的其它全部線 程共享。

4.系統開銷

因爲在建立或撤消進程時,系統都要爲之分配或回收資源,如內存空間、I/o設備等。所以,操做系統所付出的開銷將顯著地大於在建立或撤消線程時的開銷。類 似地,在進行進程切換時,涉及到整個當前進程CPU環境的保存以及新被調度運行的進程的CPU環境的設置。而線程切換隻須保存和設置少許寄存器的內容,並 不涉及存儲器管理方面的操做。可見,進程切換的開銷也遠大於線程切換的開銷。此外,因爲同一進程中的多個線程具備相同的地址空間,導致它們之間的同步和通訊的實現,也變得比較容易。在有的系統中,線程的切換、同步和通訊都無須

 

操做系統的進程調度算法

計算機系統的層次存儲結構詳解


數據庫事務是指做爲單個邏輯工做單元執行的一系列操做。

這裏寫圖片描述

友情連接:數據庫事務的四大特性以及事務的隔離級別


MySQL數據庫優化總結

MYSQL 優化經常使用方法

MySQL存儲引擎--MyISAM與InnoDB區別

關於SQL數據庫中的範式

第一範式(1NF):強調的是列的原子性,即列不可以再分紅其餘幾列

◆ 第二範式(2NF):首先是 1NF,另外包含兩部份內容,一是表必須有一個主鍵;二是沒有包含在主鍵中的列必須徹底依賴於主鍵,而不能只依賴於主鍵的一部分。

◆ 第三範式(3NF):首先是 2NF,另外非主鍵列必須直接依賴於主鍵,不能存在傳遞依賴。即不能存在:非主鍵列 A 依賴於非主鍵列 B,非主鍵列 B 依賴於主鍵的狀況。

第二範式(2NF)和第三範式(3NF)的概念很容易混淆,區分它們的關鍵點在於,2NF:非主鍵列是否徹底依賴於主鍵,仍是依賴於主鍵的一部分;3NF:非主鍵列是直接依賴於主鍵,仍是直接依賴於非主鍵列。


Hibernate的一級緩存是由Session提供的,所以它只存在於Session的生命週期中,當程序調用save(),update(),saveOrUpdate()等方法 及調用查詢接口list,filter,iterate時,如Session緩存中還不存在相應的對象,Hibernate會把該對象加入到一級緩存中,當Session關閉的時候緩存也會消失。 

Hibernate的一級緩存是Session所內置的不能被卸載,也不能進行任何配置一級緩存採用的是key-value的Map方式來實現的,在緩存實體對象時,對象的主關鍵字ID是Map的key,實體對象就是對應的值。 

Hibernate二級緩存:把得到的全部數據對象根據ID放入到第二級緩存中。Hibernate二級緩存策略,是針對於ID查詢的緩存策略刪除、更新、增長數據的時候,同時更新緩存


更新於2017/3/9

Java I/O 總結

程序須要讀取數據的時候,就會創建一個通向數據源的鏈接,這個數據源能夠是文件,內存,或是網絡鏈接。相似的,當程序須要寫入數據的時候,就會創建一個通向目的地的鏈接。

    1. 是否須要轉換流
      是,就使用轉換流,從Stream轉化爲Reader、Writer:InputStreamReader,OutputStreamWriter
    2. 是否須要緩衝提升效率
      是就加上Buffered:BufferedInputStream, BufferedOuputStream, BufferedReader, 
      1. 肯定是輸入仍是輸出
        輸入:輸入流 InputStream Reader
        輸出:輸出流 OutputStream Writer
      2. 明確操做的數據對象是不是純文本
        是:字符流 Reader,Writer
        否:字節流 InputStream,OutputStream
      3. 明確具體的設備。
        • 文件:
          讀:FileInputStream,, FileReader,
          寫:FileOutputStream,FileWriter
          •    讀的時候須要判斷是否讀到-1 證實讀完   寫的時候若是是Buffered 須要flush 才能寫入 由於有緩衝區 或者close

JVM(8):JVM知識點總覽-高級Java工程師面試必備

類加載

  • 加載,查找並加載類的二進制數據,在Java堆中也建立一個java.lang.Class類的對象
  • 鏈接,鏈接又包含三塊內容:驗證、準備、初始化。1)驗證,文件格式、元數據、字節碼、符號引用驗證;2)準備,爲類的靜態變量分配內存,並將其初始化爲默認值;3)解析,把類中的符號引用轉換爲直接引用
  • 初始化,爲類的靜態變量賦予正確的初始值
  • 使用,new出對象程序中使用
  • 卸載,執行垃圾回收

類初始化時機 ?

、建立類的實例。例如new語句建立實例,或者經過反射、克隆及序列號手段來建立實例。

二、調用類的靜態方法。

三、訪問某個類或接口的靜態變量或者對該靜態變量賦值。

四、調用java API中某些反射方法,好比調用Class.forName("Worker")方法,加入Worker類尚未被初始化,那麼forName()方法就會初始化Worker類,而後返回表明這個Worker類的Class實例。forName()方法是java.lang.Class類的靜態方法。

五、初始化一個類的子類。例如對Sub類的初始化,可看做是它對父類Base類的主動使用,所以會先初始化Base類。

六、java虛擬機啓動時被註明爲啓動類的類。例如對於「java Sample」命令,Sample類就是啓動類,java虛擬機會先初始化它。

•在以下幾種狀況下,Java虛擬機將結束生命週期

– 執行了System.exit()方法

– 程序正常執行結束

– 程序在執行過程當中遇到了異常或錯誤而異常終止

– 因爲操做系統出現錯誤而致使Java虛擬機進程終止

類加載器

  • 啓動類加載器:Bootstrap ClassLoader,負責加載存放在JDK\jre\lib(JDK表明JDK的安裝目錄,下同)下,或被-Xbootclasspath參數指定的路徑中的,而且能被虛擬機識別的類庫
  • 擴展類加載器:Extension ClassLoader,該加載器由sun.misc.Launcher$ExtClassLoader實現,它負責加載DK\jre\lib\ext目錄中,或者由java.ext.dirs系統變量指定的路徑中的全部類庫(如javax.*開頭的類),開發者能夠直接使用擴展類加載器。
  • 應用程序類加載器:Application ClassLoader,該類加載器由sun.misc.Launcher$AppClassLoader來實現,它負責加載用戶類路徑(ClassPath)所指定的類,開發者能夠直接使用該類加載器

類加載機制

  • 全盤負責,當一個類加載器負責加載某個Class時該Class所依賴的和引用的其餘Class也將由該類加載器負責載入,除非顯示使用另一個類加載器來載入
  • 父類委託,先讓父類加載器試圖加載該類,只有在父類加載器沒法加載該類時才嘗試從本身的類路徑中加載該類
  • 緩存機制,緩存機制將會保證全部加載過的Class都會被緩存,當程序中須要使用某個Class時,類加載器先從緩存區尋找該Class,只有緩存區不存在,系統纔會讀取該類對應的二進制數據,並將其轉換成Class對象,存入緩存區。這就是爲何修改了Class後,必須重啓JVM,程序的修改纔會生效

細數JDK裏的設計模式

Java中建立對象的5種不一樣方法

關於Java Collections的幾個常見問題

類在何時加載和初始化

兩個棧實現隊列 兩個隊列實現棧


更新於2017/3/12

java collection.sort()根據時間排序list

單點登陸原理與簡單實現


更新於2017/3/13

AQS詳解

Java的concurrent包

Java 併發工具包 java.util.concurrent 用戶指南


更新於2017/6/12

進程和線程的區別:

  進程:每一個進程都有獨立的代碼和數據空間(進程上下文),進程間的切換會有較大的開銷,一個進程包含1–n個線程。

  線程:同一類線程共享代碼和數據空間,每一個線程有獨立的運行棧和程序計數器(PC),線程切換開銷小。

  線程和進程同樣分爲五個階段:建立、就緒、運行、阻塞、終止。

  多進程是指操做系統能同時運行多個任務(程序)。

  多線程是指在同一程序中有多個順序流在執行。

在java中要想實現多線程,有三種手段,一種是繼續Thread類,另一種是實現Runable接口,還有就是實現Callable接口。


Switch可否用string作參數?

a.在 Java 7 以前, switch 只能支持byte,short,char,int 或者其對應的封裝類以及 Enum 類型。在Java 7中,String 支持被加上了。


Object有哪些公用方法?

a.方法equals測試的是兩個對象是否相等

b.方法clone進行對象拷貝

c.方法getClass返回和當前對象相關的Class對象

d.方法notify,notifyall,wait都是用來對給定對象進行線程同步的

e.toString  方法


Java的四種引用,強弱軟虛,以及用到的場景

a.利用軟引用和弱引用解決OOM問題:用一個HashMap來保存圖片的路徑和相應圖片對象關聯的軟引用之間的映射關係,在內存不足時,JVM會自動回收這些緩存圖片對象所佔用的空間,從而有效地避免了OOM的問題。

b.經過軟可及對象重獲方法實現Java對象的高速緩存:好比咱們建立了一Employee的類,若是每次須要查詢一個僱員的信息。哪怕是幾秒中以前剛剛查詢過的,都要從新構建一個實例,這是須要消耗不少時間的。咱們能夠經過軟引用和 HashMap 的結合,先是保存引用方面:以軟引用的方式對一個Employee對象的實例進行引用並保存該引用到HashMap 上,key 爲此僱員的 id,value爲這個對象的軟引用,另外一方面是取出引用,緩存中是否有該Employee實例的軟引用,若是有,從軟引用中取得。若是沒有軟引用,或者從軟引用中獲得的實例是null,從新構建一個實例,並保存對這個新建實例的軟引用。

c.強引用:若是一個對象具備強引用,它就不會被垃圾回收器回收。即便當前內存空間不足,JVM也不會回收它,而是拋出 OutOfMemoryError 錯誤,使程序異常終止。若是想中斷強引用和某個對象之間的關聯,能夠顯式地將引用賦值爲null,這樣一來的話,JVM在合適的時間就會回收該對象。

d.軟引用:在使用軟引用時,若是內存的空間足夠,軟引用就能繼續被使用,而不會被垃圾回收器回收,只有在內存不足時,軟引用纔會被垃圾回收器回收。

e.弱引用:具備弱引用的對象擁有的生命週期更短暫。由於當 JVM 進行垃圾回收,一旦發現弱引用對象,不管當前內存空間是否充足,都會將弱引用回收。不過因爲垃圾回收器是一個優先級較低的線程,因此並不必定能迅速發現弱引用對象。

f.虛引用:顧名思義,就是形同虛設,若是一個對象僅持有虛引用,那麼它至關於沒有引用,在任什麼時候候均可能被垃圾回收器回收。


Hashcode的做用,與 equal 有什麼區別?

a.一樣用於鑑定2個對象是否相等的,java集合中有 list 和 set 兩類,其中 set不容許元素重複實現,那個這個不容許重複實現的方法,若是用 equal 去比較的話,若是存在1000個元素,你 new 一個新的元素出來,須要去調用1000次 equal 去逐個和他們比較是不是同一個對象,這樣會大大下降效率。hashcode其實是返回對象的存儲地址,若是這個位置上沒有元素,就把元素直接存儲在上面,若是這個位置上已經存在元素,這個時候纔去調用equal方法與新元素進行比較,相同的話就不存了,散列到其餘地址上。


Override和Overload的含義以及區別

a.Overload顧名思義是從新加載,它能夠表現類的多態性,能夠是函數裏面能夠有相同的函數名可是參數名、返回值、類型不能相同;或者說能夠改變參數、類型、返回值可是函數名字依然不變。

b.就是ride(重寫)的意思,在子類繼承父類的時候子類中能夠定義某方法與其父類有相同的名稱和參數,當子類在調用這一函數時自動調用子類的方法,而父類至關於被覆蓋(重寫)了。

具體可前往C++中重載、重寫(覆蓋)的區別實例分析查看


抽象類和接口的區別

a.一個類只能繼承單個類,可是能夠實現多個接口

b.抽象類中能夠有構造方法,接口中不能有構造方法

c.抽象類中的全部方法並不必定要是抽象的,你能夠選擇在抽象類中實現一些基本的方法。而接口要求全部的方法都必須是抽象的

d.抽象類中能夠包含靜態方法,接口中不能夠

e.抽象類中能夠有普通成員變量,接口中不能夠


解析XML的幾種方式的原理與特色:DOM、SAX、PULL

a.DOM:消耗內存:先把xml文檔都讀到內存中,而後再用DOM API來訪問樹形結構,並獲取數據。這個寫起來很簡單,可是很消耗內存。要是數據過大,手機不夠牛逼,可能手機直接死機  xml文檔的層級結構, 能夠進行增刪操做

b.SAX:解析效率高,佔用內存少,基於事件驅動的:更加簡單地說就是對文檔進行順序掃描,當掃描到文檔(document)開始與結束、元素(element)開始與結束、文檔(document)結束等地方時通知事件處理函數,由事件處理函數作相應動做,而後繼續一樣的掃描,直至文檔結束。

c.PULL:與 SAX 相似,也是基於事件驅動,咱們能夠調用它的next()方法,來獲取下一個解析事件(就是開始文檔,結束文檔,開始標籤,結束標籤),當處於某個元素時能夠調用XmlPullParser的getAttributte()方法來獲取屬性的值,也可調用它的nextText()獲取本節點的值。


wait()和sleep()的區別

sleep來自Thread類,和wait來自Object類

調用sleep()方法的過程當中,線程不會釋放對象鎖。而 調用 wait 方法線程會釋放對象鎖

sleep睡眠後不出讓系統資源,wait讓出系統資源其餘線程能夠佔用CPU

sleep(milliseconds)須要指定一個睡眠時間,時間一到會自動喚醒


JAVA 中堆和棧的區別,說下java 的內存機制

a.基本數據類型比變量和對象的引用都是在棧分配的

b.堆內存用來存放由new建立的對象和數組

c.類變量(static修飾的變量)程序在一加載的時候就在堆中爲類變量分配內存,堆中的內存地址存放在棧中

d.實例變量:當你使用java關鍵字new的時候,系統在堆中開闢並不必定是連續的空間分配給變量,是根據零散的堆內存地址,經過哈希算法換算爲一長串數字以表徵這個變量在堆中的」物理位置」,實例變量的生命週期–當實例變量的引用丟失後,將被GC(垃圾回收器)列入可回收「名單」中,但並非立刻就釋放堆中內存

e.局部變量: 由聲明在某方法,或某代碼段裏(好比for循環),執行到它的時候在棧中開闢內存,當局部變量一但脫離做用域,內存當即釋放


JAVA多態的實現原理

a.抽象的來說,多態的意思就是同一消息能夠根據發送對象的不一樣而採用多種不一樣的行爲方式。(發送消息就是函數調用)

b.實現的原理是動態綁定,程序調用的方法在運行期才動態綁定,追溯源碼能夠發現,JVM 經過參數的自動轉型來找到合適的辦法。

相關文章
相關標籤/搜索