晚上八點多自己在看視頻的時候突然接到杭州來的一個電話,當時覺得很奇怪,突兀,接通之后被告知是杭州網易打來的,沒有簡單的自我介紹,沒有多余的廢話,直接入主題,嚇得我心里怪緊張的,完全沒有准備,但是也沒有辦法,還是得硬上!
1、項目結構。
沒有緩和的時間,面試官直接問我簡歷上某個項目的情況,簡要的說了下算是緩解心情,問了下使用的相關的技術,比如用了spring mvc框架沒 數據庫是用的什么 這些可能就是面試官給的緩和時間吧,但是,我是這樣越緩和越緊張了,悲催。。。
2、用過mybatis沒?因為沒怎么用過,所以面試官就沒怎么問了。。。
3、集合框架hashtable、hashmap、list、list初始化大小、hashmap自動增長
答:一開始是直接問了解常用的集合框架么,這個一聽到肯定說了解咯,於是就讓說說hashtable、hashmap、list的區別,所以就大致展開說了下:
ArrayList和Vector的區別:
共同點:這兩個類都實現了List接口(List接口繼承了Collection接口),他們都是有序集合,即存儲在這兩個集合中的元素的位置都是有順序的,相當於一種動態的數組,我們以后可以按位置索引號取出某個元素,並且其中的數據是允許重復的,這是與HashSet之類的集合的最大不同處,HashSet之類的集合不可以按索引號去檢索其中的元素,也不允許有重復的元素。
接着說ArrayList與Vector的區別,這主要包括兩個方面:.
同步性:Vector是線程安全的,也就是說是它的方法之間是線程同步的,而ArrayList是線程序不安全的,它的方法之間是線程不同步的。如果只有一個線程會訪問到集合,那最好是使用ArrayList,因為它不考慮線程安全,效率會高些;如果有多個線程會訪問到集合,那最好是使用Vector,因為不需要我們自己再去考慮和編寫線程安全的代碼。
注意:這里談到線程安全,同步問題,面試官少不了會多嘴說一句,讓你講講線程安全是咋回事,如果不考慮,你聽到這個問題估計會是一臉懵逼,我當初就是這樣子的!所以這里我補充下線程安全的問題: java中的線程安全就是線程同步的意思,就是當一個程序對一個線程安全的方法或者變量進行訪問的時候,其他的程序不能再對他進行操作了,必須等到這次訪問結束以后才能對這個線程安全的方法進行訪問,否則將會造成錯誤發生;線程安全就是說,如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變量的值也和預期的是一樣的,就是線程安全的。 線程安全問題都是由全局變量及靜態變量引起的,定義在方法內部的局部私有變量是沒有線程安全與否一說的。
備注:對於Vector&ArrayList、Hashtable&HashMap,要記住線程安全的問題,記住Vector與Hashtable是舊的,是java一誕生就提供了的,它們是線程安全的,ArrayList與HashMap是java2時才提供的,它們是線程不安全的。所以,我們講課時先講老的。
數據增長:ArrayList與Vector都有一個初始的容量大小,當存儲進它們里面的元素的個數超過了容量時,就需要增加ArrayList與Vector的存儲空間,每次要增加存儲空間時,不是只增加一個存儲單元,而是增加多個存儲單元,每次增加的存儲單元的個數在內存空間利用與程序效率之間要取得一定的平衡。Vector默認增長為原來兩倍,而ArrayList的增長策略在文檔中沒有明確規定(從源代碼看到的是增長為原來的1.5倍)。ArrayList與Vector都可以設置初始的空間大小,Vector還可以設置增長的空間大小,而ArrayList沒有提供設置增長空間的方法。
總結:即Vector增長原來的一倍,ArrayList增加原來的0.5倍。 PS:因為在上面講區別的時候提到了自動增長的問題,所以面試官順帶問了句,hashmap自動增長為多少,這個問題說實話,自己沒有關注過,平時也沒注意過,所以只能老實的說不知道咯,面后網上查了下,不確定是否正確,有說1.6版本的是增長2倍!
ArrayList,Vector, LinkedList的存儲性能和特性:
ArrayList和Vector都是使用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及數組元素移動等內存操作,所以索引數據快而插入數據慢,Vector由於使用了synchronized方法(線程安全),通常性能上較ArrayList差,而LinkedList使用雙向鏈表實現存儲,按序號索引數據需要進行前向或后向遍歷,但是插入數據時只需要記錄本項的前后項即可,所以插入速度較快。LinkedList也是線程不安全的,LinkedList提供了一些方法,使得LinkedList可以被當作堆棧和隊列來使用。
List和Map的區別:
一個是存儲單列數據的集合,另一個是存儲鍵和值這樣的雙列數據的集合,List中存儲的數據是有順序,並且允許重復;Map中存儲的數據是沒有順序的,其鍵(key)是不能重復的,它的值(value)是可以有重復的,存值采用 put(key,value)。Map中取值:value=m.get(key)(這個面試官常問,雖然不難,但也得注意)
HashMap和Hashtable的區別:
HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因為contains方法容易讓人引起誤解。
一.歷史原因:Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現
二.同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的
三.值:只有HashMap可以讓你將空值作為一個表的條目的key或value,即HashMap允許將null作為一個entry的key或者value,而Hashtable不允許。
PS:最后面試官有問到list初始化大小為多少,也就是說默認是多少,這個其實問的是 List list = new ArrayList() 這里初始化 數組的大小是多少,根據源碼我們知道,默認大小為10.
4、多線程 wait()sleep()
答:聊到多線程,大致先問了多線程的實現方式,這個問題不用多說,很簡單,java提供了兩種方式,一個是繼承Thread類,另一個是實現Runnable接口,由於java不支持多繼承,所以在多繼承的時候,我們得優先選用 實現 Runnable接口,因為我們可以通過實現接口的辦法,間接的實現多繼承!【問了實現方式之后面試官又問了這兩種方法的使用】,其次問到了wait()和sleep()的區別,這兩個方法區別在於:sleep()是Thread類的,而wait()是Object類的,sleep是睡眠,指定時間后線程會繼續執行,不放棄對cpu資源的占用(即不放棄對象鎖),相當於暫停指定t,wait()是等待,需要喚醒,它會釋放對cpu資源的占用(即會放棄對象鎖),調用notify()和notifyAll()喚醒。
5、spring mvc框架結構 spring過濾器、登錄過濾 spring mvc分層 spring注解
答:首先問到的是spring mvc框架,讓我講下其組成及功能,由於當時思路有點凌亂,我主動提出這個問題留到最后講!接下來面試官問了,spring過濾器,就簡單問了下我一般用過濾器做什么,我回答一般處理字符以及編碼,顯然這不是面試官要的結果,於是面試官提示,加入你在做一個登陸注冊系統,怎么用過濾器來驗證是否匹配,我直接脫口而出查數據庫啦,說完后自己都笑了,至於最后要問的是什么這里我好想也忘了,好想提到什么controller 我說是的,然后應該沒答錯了,接下來就問到了spring的注解問題,說自己常用的注解有哪些,這里我大致講了一些,總結摘錄如下:
Spring自帶依賴注入注解
1 @Required:依賴檢查;
2 @Autowired:自動裝配2 自動裝配,用於替代基於XML配置的自動裝配 基於@Autowired的自動裝配,默認是根據類型注入,可以用於構造器、字段、方法注入
3 @Value:注入SpEL表達式 用於注入SpEL表達式,可以放置在字段方法或參數上
@Value(value = "SpEL表達式")
@Value(value = "#{message}")
4 @Qualifier:限定描述符,用於細粒度選擇候選者
@Qualifier限定描述符除了能根據名字進行注入,但能進行更細粒度的控制如何選擇候選者
@Qualifier(value = "限定標識符")
JSR-250注解
1 @Resource:自動裝配,默認根據類型裝配,如果指定name屬性將根據名字裝配,可以使用如下方式來指定
@Resource(name = "標識符")
字段或setter方法
2 @PostConstruct和PreDestroy:通過注解指定初始化和銷毀方法定義
JSR-330注解
1 @Inject:等價於默認的@Autowired,只是沒有required屬性
2 @Named:指定Bean名字,對應於Spring自帶@Qualifier中的缺省的根據Bean名字注入情況
3 @Qualifier:只對應於Spring自帶@Qualifier中的擴展@Qualifier限定描述符注解,即只能擴展使用,沒有value屬性
JPA注解
@PersistenceContext
@PersistenceUnit用於注入EntityManagerFactory和EntityManager
具體這里不詳細展開,大家可以參考一些專門針對注解的文章!
好了,接下來就提到spring mvc的分層了,總結如下:
使用Java spring進行MVC模式開發時,往往將數據模型分為兩部分,即DAO(Data Access Object,數據訪問對象)和Service(業務邏輯模型)。在第2步中,控制器向模型請求數據時,並不是直接向DAO請求數據,而是通過Service向DAO請求數據。這樣做的好處是,可以將業務邏輯與數據庫訪問獨立開,為將來系統更換數據保存介質(如目前系統使用文件系統存儲數據,將來可以更換為使用數據庫存儲,又或者是現在使用了MSSQL存儲數據,將來更換為MySQL等)提供了很大的靈活性。控制器只需要調用Service接口中的方法獲取或是處理數據,Service層對控制器傳入的數據進行業務邏輯處理封裝后,傳給DAO層,由DAO層負責將處理后的數據寫入數據庫中。在Service層使用了抽象工廠模式來實現Service層與DAO層的低耦合,Service層並不知道DAO層是如何實現的,實際上也不需要知道系統使用了哪種數據庫或是文件系統。
action(控制器)、Dao(數據訪問層)、Service(業務邏輯)!view層(視圖 jsp之類的)!
最后就得言歸正傳了,回到spring mvc框架的結構上來,大概是照着下面總結的:
核心容器 核心容器提供 Spring 框架的基本功能。核心容器的主要組件是 BeanFactory,它是工廠模式的實現。BeanFactory 使用控制反轉 (IOC) 模式將應用程序的配置和依賴性規范與實際的應用程序代碼分開。
Spring 上下文 Spring 上下文是一個配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企業服務,例如 JNDI、EJB、電子郵件、國際化、校驗和調度功能。
Spring AOP 通過配置管理特性,Spring AOP 模塊直接將面向方面的編程功能集成到了Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何對象支持 AOP。Spring AOP 模塊為基於 Spring 的應用程序中的對象提供了事務管理服務。通過使用 Spring AOP,不用依賴 EJB 組件,就可以將聲明性事務管理集成到應用程序中。
Spring DAO JDBC DAO 抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不同數據庫供應商拋出的錯誤消息。異常層次結構簡化了錯誤處理,並且極大地降低了需要編寫的異常代碼數量(例如打開和關閉連接)。Spring DAO 的面向 JDBC 的異常遵從通用的 DAO 異常層次結構。
Spring ORM Spring 框架插入了若干個 ORM 框架,從而提供了 ORM 的對象關系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有這些都遵從 Spring 的通用事務和 DAO 異常層次結構。
Spring Web 模塊 Web 上下文模塊建立在應用程序上下文模塊之上,為基於 Web 的應用程序提供了上下文。所以,Spring 框架支持與 Jakarta Struts 的集成。Web 模塊還簡化了處理多部分請求以及將請求參數綁定到域對象的工作。
Spring MVC 框架 MVC 框架是一個全功能的構建 Web 應用程序的 MVC 實現。通過策略接口,MVC 框架變成為高度可配置的,MVC 容納了大量視圖技術,其中包括 JSP、Velocity、Tiles、iText 和 POI。
Spring 框架的功能可以用在任何 J2EE 服務器中,大多數功能也適用於不受管理的環境。Spring 的核心要點是:支持不綁定到特定 J2EE 服務的可重用業務和數據訪問對象。毫無疑問,這樣的對象可以在不同 J2EE 環境 (Web 或 EJB)、獨立應用程序、測試環境之間重用。
PS:題外要知道的:SpringMVC工作流程描述
-
向服務器發送HTTP請求,請求被前端控制器 DispatcherServlet 捕獲。
-
DispatcherServlet 根據 <servlet-name>-servlet.xml 中的配置對請求的URL進行解析,得到請求資源標識符(URI)。 然后根據該URI,調用 HandlerMapping 獲得該Handler配置的所有相關的對象(包括Handler對象以及Handler對象對應的攔截器),最后以 HandlerExecutionChain 對象的形式返回。
-
DispatcherServlet 根據獲得的Handler,選擇一個合適的 HandlerAdapter。(附注:如果成功獲得HandlerAdapter后,此時將開始執行攔截器的preHandler(…)方法)。
-
提取Request中的模型數據,填充Handler入參,開始執行Handler(Controller)。 在填充Handler的入參過程中,根據你的配置,Spring將幫你做一些額外的工作:
HttpMessageConveter: 將請求消息(如Json、xml等數據)轉換成一個對象,將對象轉換為指定的響應信息。 數據轉換:對請求消息進行數據轉換。如String轉換成Integer、Double等。 數據根式化:對請求消息進行數據格式化。 如將字符串轉換成格式化數字或格式化日期等。 數據驗證: 驗證數據的有效性(長度、格式等),驗證結果存儲到BindingResult或Error中。
-
Handler(Controller)執行完成后,向 DispatcherServlet 返回一個 ModelAndView 對象;
-
根據返回的ModelAndView,選擇一個適合的 ViewResolver(必須是已經注冊到Spring容器中的ViewResolver)返回給DispatcherServlet。
-
ViewResolver 結合Model和View,來渲染視圖。
-
視圖負責將渲染結果返回給客戶端。
6、連表查詢方法、笛卡爾積通過什么連接得到 sql對‘a’,‘b’,‘c’,‘d’排序,排成自己指定的順序
答:連表查詢方法,我大致說了三個,引入之前的答案:說句實在話,自從辭職讀研以來很久沒有用過sql語句了,關於這幾個連接光靠記憶的話,完全會是懵逼,幸虧自己還不算蠢,很自然的根據字面理解,我很好的回答了出來,left join就是返回包括左表中所有記錄和右表中聯結字段相等的記錄,好了面試官會問你,那么如果A表中,有甲丙丁3條記錄,B表中有甲乙丙丁4條記錄,那么如果條件都滿足的情況,A left join B 丙記錄是否會被查出,答案是否定的!好了,right join就是和left join 相反的,inner join等值聯結 只返回2表中聯結字段相等的行!講到這里我就戛然而止,可能是面試官覺得我回答的還不夠全面,所以又提醒我那么笛卡爾積怎么實現的,我想了想,突然腦子中冒出了個Cross join,於是脫口而出,交叉連接,然后面試官嗯了下,於是接着往下走問我一般用什么排序,我就回答,order by啦,然后就是提了下 desc 和ASC的含義,一個降序一個升序沒什么好說的,最后話鋒一轉,問我,給我 a b c d 四個字符讓我按照自定義的方式排序怎么實現,比如排序成 b a c d 我實話實說不知道。。。
7、分布式
最后一個問題是問我了解分布式不,我說稍微看了下,不怎么了解,這段時間正打算看看。。。
PS:spring mvc模塊及功能是最后回答的,所以回答完這些,面試官讓我自己提了些問題,隨便問了些,就是后悔沒用問我那幾個沒答出來的題目,本來是要問的,最后竟然忘了!。。。。
2017年2月22日22:44:18總結 by小仇哥