Java面試題集(86-115)

Java程序員面試題集(86-115)程序員

摘要:下面的內容包括Struts 2和Hibernate的常見面試題,雖然Struts 2在2013年6月曝出高危漏洞後已經顯得江河日下,而Spring MVC的異軍突起更加加速了Struts 2的隕落,但面試中仍然有可能被問及和此框架相關的內容,畢竟Struts 2曾經被阿里巴巴、京東以及政府企業門戶網站普遍採用。另外一方面,Hibernate目前仍然是ORM框架中的中堅力量,MyBatis在此領域也有不容忽視的一席之地,所以瞭解這兩個ORM框架對Java程序員是頗有必要的。第一期發佈的Java面試題集中的150題並未包含Spring MVC和MyBatis的內容,後面會陸續爲你們奉上。面試

 

8六、Struts 2中,Action經過什麼方式得到用戶從頁面輸入的數據,又是經過什麼方式把其自身的數據傳給視圖的?spring

答:Action從頁面獲取數據有三種方式:sql

①經過Action屬性接受參數數據庫

②經過域模型獲取參數編程

③經過模型驅動獲取參數 (ModelDriven<T>)緩存

Action將數據存入值棧(Value Stack)中,視圖能夠經過表達式語言(EL)從值棧中獲取數據。安全

 

8七、簡述Struts 2是如何實現MVC架構模式的。session

答:MVC架構模式要求應用程序的輸入、處理和輸出三者分離,將系統分紅模型(Model)、視圖(View)、控制器(Controller)三個部分,經過控制器實現模型和視圖的解耦合,使得應用程序的開發和維護變得容易,以下圖所示。其中,模型表明了應用程序的數據和處理這些數據的規則,同時還能夠爲視圖提供的查詢保存相關的狀態,一般由JavaBean來實現,模型的代碼寫一次就能夠被多個視圖重用;視圖用來組織模型的內容,它從模型中得到數據,並將數據展示給用戶,在Struts 2中一般由JSP、Freemarker模板等來實現;控制器負責從客戶端接受請求並將其轉換爲某種行爲,行爲完成後再選擇一個視圖來呈現給用戶,控制器自己不須要輸出任何內容,它只是接收請求並決定調用哪一個模型組件去處理請求,StrutsPrepareAndExecuteFilter過濾器是Struts 2中的核心,它和一系列的Action構成了Struts 2中的控制器。多線程

 

圖-1 MVC架構模式圖

8八、闡述Struts 2如何實現用戶輸入驗證。在你作過的項目中使用的是那種驗證方式,爲何選擇這種方式?

答:Struts 2可使用手動驗證和自動驗證框架實現用戶輸入驗證。自動驗證框架是將對輸入的驗證規則放在XML文件中,這種方式比較靈活,能夠在不修改代碼的狀況下修改驗證的規則。

 

8九、闡述Struts 2中的Action如何編寫?Action是否採用了單例?

答:Struts2的Action有三種寫法:

①POJO

②實現Action接口重寫execute()方法

③繼承ActionSupport類

Action沒有像Servlet同樣使用單實例多線程的工做方式,很明顯,每一個Action要接收不一樣用戶的請求參數,這就意味着Action是有狀態的,所以在設計上使用了每一個請求對應一個Action的處理方式。

 

90、Struts 2中的Action並無直接收到用戶的請求,那它爲何能夠處理用戶的請求,又憑什麼知道一個請求到底交給哪一個Action來處理?

答:Struts2的核心過濾器接收到用戶請求後,會對用戶的請求進行簡單的預處理(例如解析、封裝參數),而後經過反射來建立Action實例,並調用Action中指定的方法來處理用戶請求。

要決定請求交給哪個Action來處理有兩種方式:1利用配置文件:能夠在配置文件中經過<action>標籤配置和請求對應的Action類以及要調用的方法;2利用約定:Struts2中可使用約定(convention)插件,例如約定xxx老是對應XxxAction,這是對約定優於配置理念的踐行。

 

9一、你常常用到的Struts 2常量配置有哪些?

答:

①struts.i18n.encoding– 指定默認編碼

②struts.objectFactory/ struts.objectFactory.spring.autoWire – 對象工廠 / Spring的自動裝配方式(名字、類型)

③struts.devMode– 是否使用開發模式

④struts.locale– 指定默認區域,默認值是en_US

⑤struts.i18n.resources– 國際化使用的資源文件

⑥struts.enable.DynamicMethodInvocation– 是否容許動態方法調用

 

9二、簡述Struts2的異常處理機制。

答:Struts 2提供了聲明式的異常處理機制,能夠在配置文件中加入以下代碼:

<global-exception-mappings>

<exception-mapping exception=」…」 result=」…」/>

</global-exception-mappings>

 

9三、說一下你對約定優於配置(CoC)的理解。

答:約定優於配置(convention over configuration),也稱做按約定編程,是一種軟件設計範式,旨在減小軟件開發人員需作決定的數量,得到簡單的好處而又不失靈活性。CoC本質是說,開發人員僅需規定應用中不符約定的部分。例如,若是模型中有個名爲Sale的類,那麼數據庫中對應的表就會默認命名爲sales。只有在偏離這一約定時,例如將該表命名爲products_sold,才需寫有關這個名字的配置。若是您所用工具的約定與你的期待相符,即可省去配置;反之,你能夠配置來達到你所期待的方式。遵循約定雖然損失了必定的靈活性,不能隨意安排目錄結構,不能隨意進行函數命名,可是卻能減小配置。更重要的是,遵循約定能夠幫助開發人員遵照構建標準,包括各類命名的規範,這對團隊開發是很是有利的。

 

9四、Struts2中如何實現I18N?

答:首先,爲不一樣語言地區編寫不一樣的資源文件;而後在Struts 2配置文件中配置struts.i18n.custom.resources常量;在Action中能夠經過調用getText()方法讀取資源文件獲取國際化資源。

 

9五、簡述攔截器的工做原理以及你在項目中使用過哪些自定義攔截器。

答:Struts 2中定義了攔截器的接口以及默認實現,實現了Interceptor接口或繼承了AbstractInterceptor的類能夠做爲攔截器。接口中的init()方法在攔截器被建立後當即被調用,它在攔截器的生命週期內只被調用一次,能夠在該方法中對相關資源進行必要的初始化。每攔截一個請求,intercept()方法就會被調用一次。destory()方法將在攔截器被銷燬以前被調用, 它在攔截器的生命週期內也只被調用一次。

項目中使用過的有權限攔截器、執行時間攔截器、令牌攔截器等。

 

9六、如何在Struts2中使用Ajax功能?

答:如下是Struts 2中實現Ajax的可選方式:

①JSON plugin+ jQuery

②DOJO plugin

③DWR (DirectWeb Remoting)

 

9七、談一下攔截器和過濾器的區別。

答:攔截器和過濾器均可以用來實現橫切關注功能,其區別主要在於:

①攔截器是基於Java反射機制的,而過濾器是基於接口回調的。

②過濾器依賴於Servlet容器,而攔截器不依賴於Servlet容器。

③攔截器只能對Action請求起做用,而過濾器能夠對全部請求起做用。

④攔截器能夠訪問Action上下文、值棧裏的對象,而過濾器不能。

 

9八、談一下Struts 1和Struts 2的區別。

答:


9九、談一下你的項目選擇Struts 2的理由

答:①Action是POJO,沒有依賴Servlet API,具備良好的可測試性;②強大的攔截器簡化了開發的複雜度;③支持多種表現層技術:JSP、Freemarker等等;④靈活的驗證方式;⑤國際化(I18N)支持;⑥聲明式異常管理;⑦經過JSON插件簡化Ajax;⑧經過Spring插件跟Spring整合。

 

【補充】有人爲選擇和評判Web框架提出了20條標準,包括:開發人員的工做效率(能用1-5天搭建一個CRUD頁面嗎)、開發人員的見解(用起來有意思嗎)、學習曲線(學了一個星期或一個月後能幹活嗎)、項目健康情況(項目陷入絕境了嗎)、開發人員的充足性(能找到經驗豐富的開發人員嗎)、就業趨勢(未來能招到人嗎)、模板化(遵循DRY原則嗎)、組件(自帶日期選擇器之類的控件嗎)、Ajax(是否支持異步調用和局部刷新)、插件或附加項(能加入Facebook集成之類的功能嗎)、擴展性(默認的控制處理的併發用戶數能到500+嗎)、測試支持(可以作測試驅動的開發嗎)、I18N和L10N(有多國語言、地域支持嗎)、校驗(能輕鬆校驗用戶輸入並迅速反饋嗎)、多編程語言支持(可以同時使用多種語言開發嗎)、文檔的質量(常見的用例和問題都在文檔中有體現嗎)、出版的圖書(有沒有行業專家使用了它並分享了本身的使用經驗)、REST支持(能按HTTP協議的設計宗旨使用該協議嗎)、移動支持(是否很容易就能支持Android、iOS和其餘移動智能終端)、風險程度(能不能作大型項目)。很明顯,Java其實算不上最優秀的Web開發語言,可是它卻知足了這20條中的不少,尤爲是充足的開發人員、成熟的解決方案這兩點,並且Java的生態系統是很是良好的,這也是在Java已經顯得江河日下的今天你們仍然一如既往的將其做爲開發語言首選的緣由。

 

100、Struts 2中如何訪問HttpServletRequest、HttpSession和ServletContext三個域對象

答:有兩種方式:

①經過ServletActionContext的方法得到;

②經過ServletRequestAware、SessionAware和ServletContextAware接口注入。

 

10一、Struts 2中的默認包struts-default有什麼做用?

答:它定義了Struts 2內部的衆多攔截器和Result類型,而Struts 2不少核心的功能都是經過這些內置的攔截器實現,如:從請求中把請求參數封裝到action、文件上傳和數據驗證等等都是經過攔截器實現的。在Struts 2的配置文件中,自定義的包繼承了struts-default包就可使用Struts 2爲咱們提供的這些功能。

 

10二、簡述值棧(Value-Stack)的原理和生命週期

答:Value-Stack貫穿整個 Action 的生命週期,保存在request做用域中,因此它和request的生命週期同樣。當Struts 2接受一個請求時,會建立ActionContext、Value-Stack和Action對象,而後把Action存放進Value-Stack,因此Action的實例變量能夠經過OGNL訪問。因爲Action是多實例的,和使用單例的Servlet不一樣,  每一個Action都有一個對應的Value-Stack,Value-Stack存放的數據類型是該Action的實例,以及該Action中的實例變量,Action對象默認保存在棧頂。

 

10三、SessionFactory是線程安全的嗎?Session是線程安全的嗎,兩個線程可以共享同一個Session嗎?

答:SessionFactory對應Hibernate的一個數據存儲的概念,它是線程安全的,能夠被多個線程併發訪問。SessionFactory通常只會在啓動的時候構建。對於應用程序,最好將SessionFactory經過單例的模式進行封裝以便於訪問。Session是一個輕量級非線程安全的對象(線程間不能共享session),它表示與數據庫進行交互的一個工做單元。Session是由SessionFactory建立的,在任務完成以後它會被關閉。Session是持久層服務對外提供的主要接口。Session會延遲獲取數據庫鏈接(也就是在須要的時候纔會獲取)。爲了不建立太多的session,可使用ThreadLocal來取得當前的session,不管你調用多少次getCurrentSession()方法,返回的都是同一個session。

 

10四、Session的load和get方法的區別是什麼?

答:主要有如下三項區別:

① 若是沒有找到符合條件的記錄, get方法返回null,load方法拋出異常

②get方法直接返回實體類對象, load方法返回實體類對象的代理

③ 在Hibernate 3以前,get方法只在一級緩存(內部緩存)中進行數據查找, 若是沒有找到對應的數據則越過二級緩存, 直接發出SQL語句完成數據讀取; load方法則能夠充分利用二級緩存中的現有數據;固然從Hibernate 3開始,get方法再也不是對二級緩存只寫不讀,它也是能夠訪問二級緩存的

簡單的說,對於load()方法Hibernate認爲該數據在數據庫中必定存在能夠放心的使用代理來實現延遲加載,若是沒有數據就拋出異常,而經過get()方法去取的數據能夠不存在。

 

10五、Session的save()、update()、merge()、lock()、saveOrUpdate()和persist()方法有什麼區別?

答:Hibernate的對象有三種狀態:瞬態、持久態和遊離態。遊離狀態的實例能夠經過調用save()、persist()或者saveOrUpdate()方法進行持久化;脫管狀態的實例能夠經過調用 update()、0saveOrUpdate()、lock()或者replicate()進行持久化。save()和persist()將會引起SQL的INSERT語句,而update()或merge()會引起UPDATE語句。save()和update()的區別在於一個是將瞬態對象變成持久態,一個是將遊離態對象變爲持久態。merge方法能夠完成save()和update()方法的功能,它的意圖是將新的狀態合併到已有的持久化對象上或建立新的持久化對象。按照官方文檔的說明:(1)persist()方法把一個瞬態的實例持久化,可是並"不保證"標識符被馬上填入到持久化實例中,標識符的填入可能被推遲到flush的時間;(2) persist"保證",當它在一個事務外部被調用的時候並不觸發一個Insert語句,當須要封裝一個長會話流程的時候,一個persist這樣的函數是須要的。(3)save"不保證"第2條,它要返回標識符,因此它會當即執行Insert語句,無論是否是在事務內部仍是外部。update()方法是把一個已經更改過的脫管狀態的對象變成持久狀態;lock()方法是把一個沒有更改過的脫管狀態的對象變成持久狀態。

 

10六、闡述Session加載實體對象的過程。

答:Session加載實體對象的步驟是:

① Session在調用數據庫查詢功能以前, 首先會在緩存中進行查詢, 在一級緩存中, 經過實體類型和主鍵進行查找, 若是一級緩存查找命中且數據狀態合法, 則直接返回

③ 若是一級緩存沒有命中, 接下來Session會在當前NonExists記錄(至關於一個查詢黑名單, 若是出現重複的無效查詢能夠迅速判斷, 從而提高性能)中進行查找, 若是NonExists中存在一樣的查詢條件,則返回null

③ 對於load方法, 若是一級緩存查詢失敗則查詢二級緩存, 若是二級緩存命中則直接返回

④ 若是以前的查詢都未命中, 則發出SQL語句, 若是查詢未發現對應記錄則將這次查詢添加到Session的NonExists中加以記錄, 並返回null

⑤ 根據映射配置和SQL語句獲得ResultSet,並建立對應的實體對象

⑥ 將對象歸入Session(一級緩存)管理

⑦ 執行攔截器的onLoad方法(若是有對應的攔截器)

⑧將數據對象歸入二級緩存

⑨返回數據對象

 

10七、Query接口的list方法和iterate方法有什麼區別?

答:

1) list方法沒法利用緩存,它對緩存只寫不讀; iterate方法能夠充分利用緩存, 若是目標數據只讀或者讀取頻繁, iterate能夠減小性能開銷

2) list方法不會引發N+1查詢問題, 而iterate方法會引發N+1查詢問題

 

10八、Hibernate如何實現分頁查詢?

答:經過Hibernate實現分頁查詢,開發人員只須要提供HQL語句、查詢起始行數(setFirstresult()方法)和最大查詢行數(setMaxResult()方法),並調用Query接口的list()方法,Hibernate會自動生成分頁查詢的SQL語句。

 

10九、鎖機制有什麼用?簡述Hibernate的悲觀鎖和樂觀鎖機制。

答:有些業務邏輯在執行過程當中每每須要保證數據訪問的排他性,因而須要經過一些機制保證在此過程當中數據被鎖住不會被外界修改,這就是所謂的鎖機制。

Hibernate支持悲觀鎖和樂觀鎖兩種鎖機制。悲觀鎖,顧名思義,它悲觀的認爲在數據處理過程當中必定存在修改數據的併發事務(包括本系統的其餘事務或來自外部系統的事務),因而將處理的數據設置爲鎖定狀態。悲觀鎖必須依賴數據庫自己的鎖機制才能真正保證數據訪問的排他性。樂觀鎖,顧名思義,對併發事務持樂觀態度(認爲對數據的併發操做不多發生),經過更加寬鬆的鎖機制解決悲觀鎖排他的數據訪問對系統性能形成的嚴重影響。最多見的樂觀鎖是經過數據版本標識來實現的,讀取數據時得到數據的版本號,更新數據時將此版本號加1,而後和數據庫表對應記錄的當前版本號進行比較,若是提交的數據版本號大於數據庫中此記錄的當前版本號則更新數據,不然認爲是過時數據。

 

1十、闡述實體對象的三種狀態以及轉換關係。

答:Hibernate中對象有三種狀態:臨時態(transient)、持久態(persistent)和遊狀態(detached),以下圖所示。

 

圖 Hibernate實體狀態轉換圖

 

  • 臨時狀態:當new一個實體對象後,這個對象處於臨時狀態,即這個對象只是一個保存臨時數據的內存區域,若是沒有變量引用這個對象,則會被JVM的垃圾回收機制回收。這個對象所保存的數據與數據庫沒有任何關係,除非經過Session的save或者saveOrUpdate把臨時對象與數據庫關聯,並把數據插入或者更新到數據庫,這個對象才轉換爲持久對象。
  • 持久狀態:持久化對象的實例在數據庫中有對應的記錄,並擁有一個持久化標識。對持久化對象進行delete操做後,數據庫中對應的記錄將被刪除,那麼持久化對象與數據庫記錄再也不存在對應關係,持久化對象變成臨時狀態。持久化對象被修改變動後,不會立刻同步到數據庫,直到數據庫事務提交。
  • 遊離狀態:當Session進行了close、clear或者evict後,持久化對象雖然擁有持久化標識符和與數據庫對應記錄一致的值,可是由於會話已經消失,對象不在持久化管理以內,因此處於遊離狀態(也叫脫管狀態)。遊離狀態的對象與臨時狀態對象是十分類似的,只是它還含有持久化標識。

 

 

1十一、如何理解Hibernate的延遲加載機制。在實際應用中,延遲加載與session關閉的矛盾是如何處理的?

答:延遲加載就是並非在讀取的時候就把數據加載進來,而是等到使用時再加載。Hibernate使用了虛擬代理機制實現延遲加載。返回給用戶的並非實體自己,而是實體對象的代理。代理對象在用戶調用getter方法時就會去數據庫加載數據。但加載數據就須要數據庫鏈接。而當咱們把會話關閉時,數據庫鏈接就同時關閉了。

延遲加載與session關閉的矛盾通常能夠這樣處理:

① 關閉延遲加載特性。這種方式操做起來比較簡單,由於hibernate的延遲加載特性是能夠經過映射文件或者註解進行配置的,但這種解決方案存在明顯的缺陷。首先,出現no session or session was closed就證實了系統中已經存在主外鍵關聯,若是去掉延遲加載的話,則每次查詢的開銷都會變得很大。

②在session關閉以前先獲取須要查詢的數據(Hibernate.initialize()方法)。

③ 使用攔截器(Interceptor)或過濾器(Filter)控制Session。

 

1十二、舉一個多對多關聯的例子,並說明如何實現多對多關聯映射。

答:例如:商品和訂單、學生和課程都是典型的多對多關係。能夠在實體類上經過@ManyToMany註解配置多對多關聯或者經過映射文件中的<set>和<many-to-many>標籤配置多對多關聯,可是一般狀況下,能夠將多對多關聯轉換成兩個多對一關聯來實現多對多關聯映射。

 

11三、談一下你對繼承映射的理解。

答:繼承關係的映射策略有三種:

①每一個繼承結構一張表(table per class hierarchy)

②每一個子類一張表(table per subclass)

③ 每一個具體類一張表(table per concrete class)

第一種方式屬於單表策略,其優勢在於查詢子類對象的時候無需錶鏈接,查詢速度快,適合多態查詢;缺點是可能致使表很大。後兩種方式屬於多表策略,其優勢在於數據存儲緊湊,其缺點是須要進行鏈接查詢,不適合多態查詢。

 

11四、簡述Hibernate常見優化策略。

答:

①制定合理的緩存策略

② 採用合理的Session管理機制

③ 儘可能使用延遲加載特性

④設定合理的批處理參數

⑤ 若是能夠, 選用UUID做爲主鍵生成器

⑥若是能夠, 選用基於version的樂觀鎖替代悲觀鎖

⑦ 在開發過程當中, 開啓hibernate.show_sql選項查看生成的SQL, 從而瞭解底層的情況;開發完成後關閉此選項

⑧ 數據庫自己的優化(合理的索引, 緩存, 數據分區策略等)也會對持久層的性能帶來可觀的提高, 這些須要專業的DBA提供支持

 

11五、談一談Hibernate的一級緩存、二級緩存和查詢緩存。

答:Hibernate的Session提供了一級緩存的功能,默認老是有效的,當應用程序保存持久化實體、修改持久化實體時,Session並不會當即把這種改變提交到數據庫,而是緩存在當前的Session中,除非顯示調用了Session的flush()方法或經過close()方法關閉Session。經過一級緩存,能夠減小程序與數據庫的交互,從而提升數據庫訪問性能。

SessionFactory級別的二級緩存是全局性的,全部的Session能夠共享這個二級緩存。不過二級緩存默認是關閉的,須要顯示開啓並指定須要使用哪一種二級緩存實現類(可使用第三方提供的實現)。一旦開啓了二級緩存並設置了須要使用二級緩存的實體類,SessionFactory就會緩存訪問過的該實體類的每一個對象,除非緩存的數據超出了指定的緩存空間。

一級緩存和二級緩存都是對整個實體進行緩存,不會緩存普通屬性,若是但願對普通屬性進行緩存,可使用查詢緩存。查詢緩存是將HQL或SQL語句以及它們的查詢結果做爲鍵值對進行緩存,對於一樣的查詢能夠直接從緩存中獲取數據。查詢緩存默認也是關閉的,須要顯示開啓。

相關文章
相關標籤/搜索