面试题:各大公司Java后端开发面试题总结 已看1 背1 有用 链接有必要看看
ThreadLocal(線程變量副本) ? ? ? --整理
Synchronized實現內存共享,ThreadLocal為每個線程維護一個本地變量。
采用空間換時間,它用于線程間的數據隔離,為每一個使用該變量的線程提供一個副本,每個線程都可以獨立地改變自己的副本,副本之間不共享數據.而不會和其他線程的副本沖突。
ThreadLocal類中維護一個Map,用于存儲每一個線程的變量副本,Map中元素的鍵為線程對 ?象,而值為對應線程的變量副本。
ThreadLocal在Spring中發揮著巨大的作用,在管理Request作用域中的Bean、事務管理、任務調度、AOP等模塊都出現了它的身影。
Spring中絕大部分Bean都可以聲明成Singleton作用域,采用ThreadLocal進行封裝,因此有狀態的Bean就能夠以singleton的方式在多線程中正常工作了。
友情鏈接:深入研究java.lang.ThreadLocal類
Java內存模型:
Java虛擬機規范中將Java運行時數據分為六種。
1.程序計數器:是一個數據結構,用于保存當前正常執行的程序的內存地址。Java虛擬機的多線程就是通過線程輪流切換并分配處理器時間來實現的,為了線程切換后能恢復到正確的位置,每條線程都需要一個獨立的程序計數器,互不影響,該區域為“線程私有”。
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適用場景
友情鏈接:?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反射機制
如何寫一個不可變類?
要創建不可變類,要實現下面幾個步驟:
索引: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個面試問答——終極列表
分享到: 本文由?ImportNew?-?人曉?翻譯自?javacodegeeks。歡迎加入翻譯小組。轉載請見文末要求。這篇文章總結了一些關于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請求的URL無法保存為瀏覽器書簽
- 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中,可見 | 查詢字符串不會顯示在地址欄中,不可見 |
| 方式 | 描述 |
| 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的區別。?
1、HashMap是非線程安全的,HashTable是線程安全的。?
2、HashMap的鍵和值都允許有null值存在,而HashTable則不行。?
3、因為線程安全的問題,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的區別
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. 循環等待?
解決死鎖,第一個是死鎖預防,就是不讓上面的四個條件同時成立。二是,合理分配資源。?
三是使用銀行家算法,如果該進程請求的資源操作系統剩余量可以滿足,那么就分配。
進程間的通信方式
進程與線程的區別和聯系
進程概念
進程是表示資源分配的基本單位,又是調度運行的基本單位。例如,用戶運行自己的程序,系統就創建一個進程,并為它分配資源,包括各種表格、內存空間、磁盤空間、(讀寫)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 總結
程序需要讀取數據的時候,就會建立一個通向數據源的連接,這個數據源可以是文件,內存,或是網絡連接。類似的,當程序需要寫入數據的時候,就會建立一個通向目的地的連接。
是,就使用轉換流,從Stream轉化為Reader、Writer:InputStreamReader,OutputStreamWriter
是就加上Buffered:BufferedInputStream, BufferedOuputStream, BufferedReader,?
輸入:輸入流 InputStream Reader
輸出:輸出流 OutputStream Writer
是:字符流 Reader,Writer
否:字節流 InputStream,OutputStream
- 文件:
讀:FileInputStream,, FileReader,
寫:FileOutputStream,FileWriter- ? ?讀的時候需要判斷是否讀到-1 證明讀完 ? 寫的時候如果是Buffered 需要flush 才能寫入 因為有緩沖區 或者close
JVM(8):JVM知識點總覽-高級Java工程師面試必備
類加載
- 加載,查找并加載類的二進制數據,在Java堆中也創建一個java.lang.Class類的對象
- 連接,連接又包含三塊內容:驗證、準備、初始化。1)驗證,文件格式、元數據、字節碼、符號引用驗證;2)準備,為類的靜態變量分配內存,并將其初始化為默認值;3)解析,把類中的符號引用轉換為直接引用
- 初始化,為類的靜態變量賦予正確的初始值
- 使用,new出對象程序中使用
- 卸載,執行垃圾回收
類初始化時機 ?
、創建類的實例。例如new語句創建實例,或者通過反射、克隆及序列號手段來創建實例。
2、調用類的靜態方法。
3、訪問某個類或接口的靜態變量或者對該靜態變量賦值。
4、調用java API中某些反射方法,比如調用Class.forName("Worker")方法,加入Worker類還沒有被初始化,那么forName()方法就會初始化Worker類,然后返回代表這個Worker類的Class實例。forName()方法是java.lang.Class類的靜態方法。
5、初始化一個類的子類。例如對Sub類的初始化,可看作是它對父類Base類的主動使用,因此會先初始化Base類。
6、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 通過參數的自動轉型來找到合適的辦法。
轉載于:https://www.cnblogs.com/shan1393/p/9017428.html
總結
以上是生活随笔為你收集整理的面试题:各大公司Java后端开发面试题总结 已看1 背1 有用 链接有必要看看的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL查询指定时间的数据
- 下一篇: 简单谈谈setTimeout与setIn