面試題

2015.3.9

瀋陽中新科技筆試總結:

java相關:

 

1j2ee與j2se區別:

           java2平臺包括標準版(j2se)、企業版(j2ee)、微縮版(j2me)

                    j2ee是在j2se的基礎上添加了一系列的企業級應用編程接口.j2ee包含有很多的技術!其中有你        熟悉的jsp,servlet,jdbc,jme等13中技術!                     

         j2ee主要是用來做B/S結構的應用程序!也就是說是基於瀏覽器和服務器的!

           j2se給我的感覺只需要一個容器就夠了,j2ee支持分佈式組件可以同時存在多個容器

     

2jsp與servlet的區別:

                         

首先你先要弄懂什麼是servlet,servlet是在服務器端執行的java程序,只不過它有專門的一套規則(就是我們平常所說的api);jsp說得簡單點就是用另一套簡單的規則寫的servlet程序,它可以寫java代碼,還可以寫html代碼,JavaScript,css等等……,但是到服務器端首先會被轉成servlet程序然後就按照servlet的執行順序執行了。

3常用的java開發框架:

JSF,Struts,Struts2,Hibernate,Spring,Webwork,Dwr都是很流行的 

最流行的框架現在只有2種
Struts+Spring+Hibernate(SSH)
Struts+Spring+Ibatis(SSI)
以後可能JSF會替代Struts,

4struts框架的好處:

優點:

  1. 這是一個開源軟件,能讓開發人員更深入的瞭解其內部實現機制和原理。

  2. 框架自帶的標籤庫,非常靈活,能極大提高開發人員的工作效率。

  3.頁面導航使系統的導航線路更加清晰。通過框架配置文件,就可以配置系統各個頁面的導航關係,能極大的提高維護的效率和質量。

  4. 提供Exception處理機制,能讓開發人員更好的管理系統異常。

  5. 數據庫鏈接池管理,使得開發人員更加關注業務邏輯的實現,而不必關心與數據庫的鏈接。 

    6,通過採用模型-視圖-控制器(MVC)設計模式,

使用struts可以開發使用 JAVA Servlets和javaServer Pages的高性能、面向事務的WEB應用程           序。

     7,struts提供的模型2體系結構,視圖層-事務處理層-數據模型層,通過明確的應用程序分工使得

     事務邏輯和顯示邏輯彼此相互獨立,視圖層(html,JSP)將用戶所需要的任何數據向事務處理層(servlet)發送請求,
     ,事務處理層將根據請求處理相關事務(包括處理請求,驗證數據等),將用戶所需要的數據提交到數據模型層,
     數據模型層從數據庫取得數據再反饋給事務處理層,由事務處理層傳遞給視圖層顯示數據信息。

     8,struts能很好的與 hibernate、spring整合

缺點:

  1.Taglib標籤庫對於初學者而言,需要花費大量時間去學習,會改變開發成員的開發習慣,無形中增加了開發成本。

  2.Struts 將MVC的控制層一分爲三,雖然能夠更加清晰地分解系統結構,但也增加了複雜度。


4Spring框架的好處:

在SSH框架中使用Spring的好處

在SSH框假中spring充當了管理容器的角色。我們都知道Hibernate用來做持久層,因爲它將JDBC做了一個良好的封裝,程序員在與數據庫進行交互時可以不用書寫大量的SQL語句。Struts是用來做應用層的,他它負責調用業務邏輯serivce層。所以SSH框架的流程大致是:Jsp頁面----Struts------Service(業務邏輯處理類)---Hibernate(左到右) 
struts負責控制Service(業務邏輯處理類),從而控制了Service的生命週期,這樣層與層之間的依賴很強,屬於耦合。這時,使用spring框架就起到了控制Action對象(Strus中的)和Service類的作用,兩者之間的關係就鬆散了,Spring的Ioc機制(控制反轉和依賴注入)正是用在此處。 
Spring的Ioc(控制反轉和依賴注入) 
控制反轉:就是由容器控制程序之間的(依賴)關係,而非傳統實現中,由程序代碼直接操控 
依賴注入:組件之間的依賴關係由容器在運行期決定 ,由容器動態的將某種依賴關係注入到組件之中 。 
從上面我們不難看出:從頭到尾Action僅僅是充當了Service的控制工具,這些具體的業務方法是怎樣實現的,他根本就不會管,也不會問,他只要知道這些業務實現類所提供的方法接口就可以了。而在以往單獨使用Struts框架的時候,所有的業務方法類的生命週期,甚至是一些業務流程都是由Action來控制的。層與層之間耦合性太緊密了,既降低了數據訪問的效率又使業務邏輯看起來很複雜,代碼量也很多。,Spring容器控制所有Action對象和業務邏輯類的生命週期,由於上層不再控制下層的生命週期,層與層之間實現了完全脫耦,使程序運行起來效率更高,維護起來也方便。 
使用Spring的第二個好處(AOP應用): 
事務的處理: 
在以往的JDBCTemplate中事務提交成功,異常處理都是通過Try/Catch 來完成,而在Spring中。Spring容器集成了TransactionTemplate,她封裝了所有對事務處理的功能,包括異常時事務回滾,操作成功時數據提交等複雜業務功能。這都是由Spring容器來管理,大大減少了程序員的代碼量,也對事務有了很好的管理控制。Hibernate中也有對事務的管理,hibernate中事務管理是通過SessionFactory創建和維護Session來完成。而Spring對SessionFactory配置也進行了整合,不需要在通過hibernate.cfg.xml來對SessionaFactory進行設定。這樣的話就可以很好的利用Sping對事務管理強大功能。避免了每次對數據操作都要現獲得Session實例來啓動事務/提交/回滾事務還有繁瑣的Try/Catch操作。這些也就是Spring中的AOP(面向切面編程)機制很好的應用。一方面使開發業務邏輯更清晰、專業分工更加容易進行。另一方面就是應用Spirng AOP隔離降低了程序的耦合性使我們可以在不同的應用中將各個切面結合起來使用大大提高了代碼重用度 
-----------------------------------------------

使用Spring有什麼好處

2010-05-03 21:36:36 來源:WEB開發網 我要評論(0) 關注谷汶鍇的微博
核心提示:Spring Framework(簡稱Spring)是根據Rod Johnson著名的《Expert One-on-One J2EE Design and Development》而開發的J2EE應用程序框架。
1.什麼是Spring Framework?
  Spring Framework(簡稱Spring)是根據Rod Johnson著名的《Expert One-on-One J2EE Design and Development》而開發的J2EE應用程序框架。目前主要根據Rod Johnson和Juergen Hoeller而進行開發的,目前發佈的最新版爲1.1.4。 Spring是J2EE應用程序框架,不過,更嚴格地講它是針對Bean的生命週期進行管理的輕量級容器(Lightweight container),可以單獨利用Spring構築應用程序,也可以和Struts,Webwork,Tapestry等衆多Web應用程序框架組合使用,並且可以與Swing等桌面應用程序API組合。所以Spring並不僅僅只能應用在J2EE中,也可以應用在桌面應用及小應用程序中。針對Spring開發的組件不需要任何外部庫。

2.使用Spring有什麼好處?
(1)Spring能有效地組織你的中間層對象。
(2)Spring能消除在許多工程中常見的對Singleton的過多使用。
(3)Spring能消除各種各樣自定義格式的屬性文件的需要,使配置信息一元化。
(4)Spring能夠幫助我們真正意義上實現針對接口編程。
(5)在Spring應用中的大多數業務對象沒有依賴於Spring。
(6)使用Spring構建的應用程序易於單元測試。
(7)Spring支持JDBC和O/R Mapping產品(Hibernate)
(8)MVC Web框架,提供一種清晰,無侵略性的MVC實現方式。
(9)JNDI抽象層,便於改變實現細節,可以方便地在遠程服務和本地服務間切換。
(10)簡化訪問數據庫時的例外處理。
(11)Spring能使用AOP提供聲明性事務管理,可以不直接操作JTA也能夠對事務進行管理。
(12)提供了JavaMail或其他郵件系統的支持。

3.什麼是輕量(Lightweight)級容器?
Spring的開發者可以避免使用重量級容器開發EJB時的缺點:
(1)帶有侵略性的API。(代碼依賴於EJB)
(2)對容器的依賴。(代碼不能在EJB容器之外工作)
(3)提供固定的一組機能,不具有配置能力。
(4)不同的產品,部署過程不同,不易通用。
(5)啓動時間長。

  針對以上問題,Spring採用了IoC使代碼對Spring的依賴減少,根據Web應用,小應用程序,桌面應用程的不同,對容器的依賴程度也不同。Spring將管理的Bean作爲POJO(Plain Old Java Object)進行控制,通過AOP Interceptor能夠增加其它的功能。
除了Spring以外的輕量級容器還有PicoContainer,(不是輕量級容器)對Bean的生命週期進行管理的還有Apache Avalon Project的Avalon等。

  總結:Spring的核心思想便是IoC和AOP,Spring本身是一個輕量級容器,和EJB容器不同,Spring的組件就是普通的Java Bean,這使得單元測試可以不再依賴容器,編寫更加容易。Spring負責管理所有的Java Bean組件,同樣支持聲明式的事務管理。我們只需要編寫好Java Bean組件,然後將它們"裝配"起來就可以了,組件的初始化和管理均由Spring完成,只需在配置文件中聲明即可。這種方式最大的優點是各組件的耦合極爲鬆散,並且無需我們自己實現Singleton模式。
spring主要的作用?
在SSH框假中spring充當了管理容器的角色。我們都知道Hibernate用來做持久層,因爲它將JDBC做了一個良好的封裝,程序員在與數據庫進行交互時可以不用書寫大量的SQL語句。Struts是用來做應用層的,他它負責調用業務邏輯serivce層。所以SSH框架的流程大致是:Jsp頁面----Struts------Service(業務邏輯處理類)---Hibernate(左到右)struts
負責控制Service(業務邏輯處理類),從而控制了Service的生命週期,這樣層與層之間的依賴和強,屬於耦合。這時,使用spring框架就起到了控制Action對象(Strus中的)和Service類的作用,兩者之間的關係就鬆散了,Spring的Ioc機制(控制反轉和依賴注入)正是用在此處。
     Spring的Ioc(控制反轉和依賴注入)
     控制反轉:就是由容器控制程序之間的(依賴)關係,而非傳統實現中,由程序代碼直接操控。
     依賴注入:組件之間的依賴關係由容器在運行期決定 ,由容器動態的將某種依賴關係注入到組件之中。
     從上面我們不難看出:從頭到尾Action僅僅是充當了Service的控制工具,這些具體的業務方法是怎樣實現的,他根本就不會管,也不會問,他只要知道這些業務實現類所提供的
方法接口就可以了。而在以往單獨使用Struts框架的時候,所有的業務方法類的生命週期,甚至是一些業務流程都是由Action來控制的。層與層之間耦合性太緊密了,既降低了數據訪
問的效率又使業務邏輯看起來很複雜,代碼量也很多。,Spring容器控制所有Action對象和業務邏輯類的生命週期,由與上層不再控制下層的生命週期,層與層之間實現了完全脫耦,使程序運行起來效率更高,維護起來也方便。
     使用Spring的第二個好處(AOP應用):
     事務的處理:
     在以往的JDBCTemplate中事務提交成功,異常處理都是通過Try/Catch 來完成,而在Spring中。Spring容器集成了TransactionTemplate,她封裝了所有對事務處理的功能,包括異常時事務回滾,操作成功時數據提交等複雜業務功能。這都是由Spring容器來管理,大大減少了程序員的代碼量,也對事務有了很好的管理控制。Hibernate中也有對事務的管理,hibernate中事務管理是通過SessionFactory創建和維護Session來完成。而Spring對SessionFactory配置也進行了整合,不需要在通過hibernate.cfg.xml來對SessionaFactory進行設定。這樣的話就可以很好的利用Sping對事務管理強大功能。避免了每次對數據操作都要現獲得Session實例來啓動事務/提交/回滾事務還有繁瑣的Try/Catch操作。這些也就是Spring中的AOP(面向切面編程)機制很好的應用。一方面使開發業務邏輯更清晰、專業分工更加容易進行。另一方面就是應用Spirng  AOP隔離降低了程序的耦合性使我們可以在不同的應用中將各個切面結合起來使用大大提高了代碼重用度

當模塊化到一定地步了,spring就有很大的做了,這個時候基本上新的業務就是配置spring就可以搞定了,基本上不需要寫代碼了。反過來如果基本上沒有模塊化,就非常累,一邊寫代碼一邊還要去寫配置。最簡單的就是如果你把做菜的每個步驟都分清楚了,洗菜,配料,切菜,燒火,整個流程每一個細節都實現了,那麼要回鍋肉就寫一個回鍋肉的配置,要青椒肉絲就寫一個青椒肉絲的配置,當然這個是建立在你流程中每一個節點(模塊)都全部實現了,想切菜,你要有切絲,切片,切塊等諸多實現模式,這個時候你用spring的配置優勢纔會體現。

如果是那種典型單一炒菜方式,爲一道菜而炒菜,spring反而會多此一舉。spring就是依賴注入的一個解決方案,依賴注入我覺得主要是面向接口的,想要達到的效果就跟U盤是的,插到電腦上就能用,拔掉就不性用。減小了耦合度


 




1.如何過簡歷關?

我先講解幾個軟件求職相關的真實故事,以幫助大家瞭解大多數軟件開發企業是如何賽選簡歷和錄用新員工的。

1.傳智播客學員A是大四在讀的應屆畢業生,他自信技術學得很不錯,實質上確實也達到用人單位的標準,他不願意編寫兩年工作經驗的虛假簡歷,希望憑藉自己的真實情況去面對求職,投遞了很多份簡歷,都沒有迴應;而他周圍的很多相似背景的學員因爲使用了假簡歷,都很快找到了薪水4.5k/月左右的工作,最後萬不得已,他修改了自己的簡歷,增加了一些水分,以兩年工作經驗的身份去投遞簡歷,結果就很快找到了滿意的工作。

2.一個穿着和氣質給人的印象都很不錯的女生諮詢時,問:“如果在傳智播客學完了,能找到工作嗎?”,我問了她一些基本情況後,得知她是鄭州航空工業管理學院本科畢業,並且畢業時間已經有兩年,談話中感覺很有工作經驗,英語也不錯,所以,我斬釘截鐵地告訴她:“她學完後絕對能找到一份滿意的工作”,並說出了一些原因:(1)她本身的談吐氣質就決定了她找工作沒問題,應聘工作除了要求有那些必需的技能外,關鍵一點還要看這個人的性格和素養,按她的條件,如果她要找軟件開發方面的工作,只需要把技術補上就可以了,這一點在傳智播客學習是很容易補上的;(2)要想找到好工作,除了掌握必需的技術外,通常都需要編寫兩年工作經驗的簡歷,她的畢業是證確實兩年前的,編造兩年軟件開發的工作經驗更容易,至少不用專門去做假的畢業證了。她聽完後,很贊同我的觀念,說她現在就在一家軟件公司做人力資源,負責挑選應聘者的簡歷,按領導的吩咐:“凡是工作經驗低於兩年的簡歷直接刪除到垃圾桶”,可見,如果你的簡歷首先到達了類似這個女生的人力資源之手,即使你的技術再厲害,如果你的工作經驗一欄上寫得低於了兩年,那簡歷就永無露臉之日了,何談後來的筆試和麪試呢? 

3.與傳智播客同一樓的一個軟件開發單位,因爲項目經理讀過傳智播客老師們的書籍和看過傳智播客的視頻,所以他們公司想到了從傳智播客學員中招聘開發人員,提出薪水在2800元左後,我們公司老師對他們誰,2800元,我們學員肯定不會去!他們公司說對於沒有實際經驗的新手開出2800元的薪水已經很不錯了,我們老師說,傳智播客學員通過簡歷包裝都能找到平均4500元的工資,樓下公司說假簡歷他們一聊就能聊出來,沒工作經驗的人是騙不住他們的,我們的老師當時就無語了,…,因爲就在前幾天,我們就有一個學員成功潛伏進了他們公司,並且工資是4500元,但我們老師不能當他們的面來說這事,就讓他們一直矇在鼓裏還很自信吧!大餅的故事

4.前面談到簡歷上的工作經驗很重要,可是大多數要找工作的同學往往是沒有工作經驗的,所以,只能在簡歷上加點水分。但是,只要你將簡歷上寫成了兩年以上的工作經驗,是不是一定就能得到筆試和麪試的機會呢?寫兩年工作經驗只是有效簡歷的開始,離簡歷被用人單位相中還有一段差距。一個好的畢業學校、優秀的英語水平、中共黨員的政治面貌、某省或直轄市的優秀畢業生、奧林匹克競賽獲幾等獎等榮耀都會給用人單位一個很好的印象,如果你有這些榮耀,一定要在簡歷的基本信息部分寫清楚。但是,很多人是沒有這些榮耀的,那麼只能平平淡淡列出自己的一些基本信息,這也沒有很大的關係,頂多就是自己的簡歷不能脫穎而出,但是,對於軟件工程師崗位來說,學歷一欄怎麼着也不能寫爲高中,起碼也要寫個大專或以上,畢業院校編個二線城市的不知名的小學院,如果你不願意去做假證,等到別人面試你時,再說“閒棄以前上的學校不好,因爲對編程太感興趣,就輟學了!”

 

1.你們會帶着我們做完整個完整的項目嗎?

答:小的項目會,大的項目則不可能,

1.衆所周知,隨便拿出一箇中等大小的項目,也需要好多個熟練的開發人員開發好多個月才能勉強做得差不多,培訓期間沒有這麼多時間,並且你還要先學會了很多技術後才能開始做項目。

 2.一個項目中的很多東西都是重複性的工作量的累積,技術方面都大同小異。做一個項目就好比蓋一座樓房,只要告訴你整個樓房的整體結構,然後帶着你蓋上一間兩間房子,其他剩下的幾百間房子,老師想繼續蓋給你看,或者讓你自己蓋剩下的房間,你肯定也不願意吧。以後有的是練手的機會,拿着人家發給你的工資,你再去做這些重複性的工作也不遲,豈不是更好!

 

2.業務重要?還是編碼實戰更重要?

答:

1.對軟件企業來說,兩者都很重要,有的項目是業務爲重心,有的則是以技術作爲核心;以業務爲重心的項目與做鞋差不多,沒有多大技術含量和壁壘,只有積累了一定的經驗,誰都可以做,利潤很薄,例如大多數管理系統,靠的是人海戰術和時間糾纏;以技術爲核心的項目則很有技術壁壘,不是誰都能做的,利潤率很高,例如,360殺毒軟件、baiduqq,迅雷下載,大型bbs項目和淘寶這樣的電子商務網站。

  2.對程序員來說,編碼實戰更重要,業務則不算什麼!程序員和軟件公司的工作就是要把用戶的需求和業務變成代碼,即爲人作嫁,一開始,需求和業務都在用戶那裏,用戶最懂業務,你不用瞭解業務,你的任務就是了解用戶的業務後編寫代碼,在開始做項目前,用戶會把業務告訴給你的。一個軟件公司從來都不是隻做自己熟悉業務的項目,而是來了業務不熟悉的項目機會,肯定也會衝上去做,軟件公司通常都是在做自己以前沒做過的項目,即做以前不瞭解業務的項目,只有項目做完了才完全熟悉了業務,這才叫做項目,否則就成了賣產品了,所以,軟件工程裏說的需求調研和理解業務的過程,也是在從側面說明,程序員是在接到項目之後纔開始瞭解其業務的,而在此之前,對業務可以是完全不懂的。

 

3.是培訓內容和信息量大好?還是培訓內容少而精的好?

答:內容和信息量大培訓課程體系,對大多人來說是更合適的。程序員做的工作總是在變化的,沒有一成不變的工作,爲了適應這種變化,你的知識面必須很廣泛。如果你學的知識內容很少,即使你把這些內容練的滾瓜爛熟了,除非你出去找的一份工作正好就是你以前練習的那些東西,這時候會讓人感覺你比誰都厲害,但這種千載難逢的好事怎麼就被你碰上了呢?軟件開發畢竟不同於刷盤子,不是在重複幹一件事情。軟件開發的工作總是要面臨不同的需求和問題,如果培訓課程的內容和信息量很大,即使由於時間關係,你暫時沒有完全消化和熟練這麼多內容,但是,你在工作中不管遇到什麼新問題,都有那麼一點點印象,知道大概的解決辦法和思路,你就可以慢慢地通過查閱資料和最終解決這個問題,軟件開發的工作本來就是這麼一種現狀,如果你學的知識量很少,一旦遇到了新問題,你完全就沒有了思路,完全無從下手,這是何等痛苦,只有灰溜溜走人的份了吧。

 

4. 我們培養的不是IT蟻族和IT民工

先看看IT蟻族和IT民工的悲慘命運吧!

http://news.csdn.net/a/20100316/217473.html  ()

http://topic.csdn.net/u/20100317/16/2dba32e3-90f4-40b5-b1fd-0bf3709297c6.html?97395

搜素 程序員的悲哀,還有更多辛酸的故事,但是,我並不同情他們,我只是說他們自己無能!程序員這個職業能創造出許多年輕的富翁,不靠父母不靠天,還有那個職業這麼有機會和誘惑呢。不過,程序員毀壞身體是真,可是,不讓你做程序員,你去打遊戲,聊QQ不也照樣壞身體嗎?

java不只是有SSH這套,我們不培養IT蟻族,如果你不想厭煩軟件開發,那就不能只學ssh,這個沒有太多技術含量的單一熟練工種。

 

別的培訓機構培養的是技術單一的熟練技工,傳智播客培養的是具有很強學習和解決問題能力的技術高手和未來技術經理。很多工廠說,清華畢業的學生剛進工廠時的動手操作不如技校畢業的學生熟練,但過一段時間後,清華學生則能解決工廠生成過程出現中的各種新問題和弊端,甚至能提出創新和發明,後勁十足,因爲清華培養的就不是一個單一工種的熟練工人,而是知識全面和具有創新能力的高級工程師。別的機構和傳智播客培養出來的學生差別好比如此。

 

 

說明,爲了節省大家的時間和提高學習效率,一些過時知識點和被筆試概率極低的題目不再被收錄和分析。

回答問題的思路:先正面敘述一些基本的核心知識,然後描述一些特殊的東西,最後再來一些錦上添花的東西。要注意有些不是錦上添花,而是畫蛇添足的東西,不要隨便寫上。把答題像寫書一樣寫。我要回答一個新技術的問題大概思路和步驟是:我們想幹什麼,怎麼幹,乾的過程中遇到了什麼問題,現在用什麼方式來解決。其實我們講課也是這樣一個思路。

例如,講ajax時,我們希望不改變原來的整個網頁,而只是改變網頁中的局部內容,例如,用戶名校驗,級聯下拉列表,下拉樹狀菜單。用傳統方式,就是瀏覽器自己直接向服務器發請求,服務器返回新頁面會蓋掉老頁面,這樣就不流暢了。

對本面試寶典中的題目有信心嗎?本來有信心的,結果聽你講完後,就沒信心了!我非常理解。因爲他覺得我的太深,他想記住我的些東西,可是記不住,所以沒信心了。我又問:聽懂了嗎?他說聽懂了。你到現在只要把你的理解儘量清晰地、有條理地表達出來,就很棒了。

 

這套面試題主要目的是幫助那些還沒有java軟件開發實際工作經驗,而正在努力尋找java軟件開發工作的朋友在筆試時更好地贏得筆試和麪試。由於這套面試題涉及的範圍很泛,很廣,很雜,大家不可能一天兩天就看完和學完這套面試寶典,即使你已經學過了有關的技術,那麼至少也需要一個月的時間才能消化和掌握這套面試寶典,所以,大家應該早作準備,從拿到這套面試寶典之日起,就要堅持在每天閒暇之餘學習其中幾道題目,日積月累,等到出去面試時,一切都水到渠成,面試時就自然會遊刃有餘了。

 

答題時,先答是什麼,再答有什麼作用和要注意什麼(這部分最重要,展現自己的心得)

 

答案的段落分別,層次分明,條理清晰都非常重要,從這些表面的東西也可以看出一個人的習慣、辦事風格、條理等。

要講你做出答案的思路過程,或者說你記住答案的思想都寫下來。把答題想着是辯論賽。答題就是給別人講道理、擺事實。答題不侷限於什麼格式和形式,就是要將自己的學識展現出來!

別因爲人家題目本來就模棱兩可,你就心裏膽怯和沒底氣了,不敢回答了。你要大膽地指出對方題目很模糊和你的觀點,不要把面試官想得有多高,其實他和你就是差不多的,你想想,如果他把你招進去了,你們以後就是同事了,可不是差不多的嗎?

關於就業薪水,如果你是應屆生,那不能要高工資,好比大餅的故事,沒有文憑還想拿高工資,就去中關村缺什麼補什麼吧!少數人基礎確實很好,在校期間確實又做過一些項目,那仍然是可以要到相對高的工資的。

 

公司招聘程序員更看重的要用到的編碼技術、而不是那些業務不太相關的所謂項目經歷:

1.公司想招什麼樣的人2.公司面試會問什麼,.3.簡歷怎麼寫4怎樣達到簡歷上的標準(培訓中心教項目的目的)

 

對於一些公司接到了一些項目,想招聘一些初中級的程序員過來幫助寫代碼,完成這個項目,你更看重的是他的專業技術功底,還是以前做過幾個項目的經歷呢?我們先排除掉那些編碼技術功底好,又正好做過相似項目的情況,實際上,這種魚和熊掌兼得的情況並不常見。其實公司很清楚,只要招聘進來的人技術真的很明白,那他什麼項目都可以做出來,公司招人不是讓你去重複做你以前的項目,而是做一個新項目,業務方面,你只要進了項目團隊,自然就能掌握。所以,大多數招聘單位在招聘那些編碼級別的程序員時也沒指望能招聘到做過類似項目的人,也不會刻意去找做過類似項目的人,用人單位也不是想把你招進,然後把你以前做過的項目重做一遍,所以,用人單位更看重招進來的人對要用到的編碼技術的功底到底怎樣,技術紮實不紮實,項目則只要跟着開發團隊走,自然就沒問題。除非是一些非常專業的行業,要招聘特別高級的開發人員和系統分析師,招聘單位才特別注重他的項目經驗和行業經驗,要去找到行業高手,公司才關心項目和與你聊項目的細節,這樣的人通常都不是通過常規招聘渠道去招聘進來的,而是通過各種手段挖過來的,這情況不再我今天要討論的範圍中。

技術學得明白不明白,人家幾個問題就把你的深淺問出來了,只要問一些具體的技術點,就很容易看出你是真懂還是假懂,很容看出你的技術深度和實力,所以,技術是來不得半點虛假的,必須紮紮實實。

由於項目的種類繁多,涉及到現實生活中的各行各業,什麼五花八門的業務都有,例如,酒店房間預定管理,公司車輛調度管理,學校課程教室管理,超市進銷存管理,知識內容管理,等等……成千上萬等等,但是,不管是什麼項目,採用的無非都是我們學習的那些目前流行和常用的技術。技術好、經驗豐富,則項目做出來的效率高些,程序更穩定和更容易維護些;技術差點,碰碰磕磕最後也能把項目做出來,無非是做的週期長點、返工的次數多點,程序代碼寫得差些,用的技術笨拙點。如果一個人不是完完全全做過某個項目,他是不太關心該項目的業務的,對其中的一些具體細節更是一竅不知,(如果我招你來做圖書管理,你項目經歷說你做過汽車調度,那我能問你汽車調度具體怎麼回事嗎?不會,所以,你很容易矇混過去的)而一個程序員的整個職業生涯中能實實在在和完完整整做出來的項目沒幾個,更別說在多個不同行業的項目了,有的程序員更是一輩子都只是在做某一個行業的項目,結果他就成了這個行業的專家(專門幹一件事的傢伙)。所以,技術面試官通常沒正好親身經歷過你簡歷寫的那些項目,他不可能去問你寫的那些項目的具體細節,而是隻能泛泛地問你這個項目是多少人做的,做了多長時間,開發的過程,你在做項目的過程中有什麼心得和收穫,用的什麼技術等面上的問題,所以,簡歷上的項目經歷可以含有很多水分,很容易作假,技術面試官也無法在項目上甄別你的真僞。

簡歷該怎麼寫:精通那些技術,有一些什麼項目經歷

教項目是爲了鞏固和靈活整合運用技術,增強學習的趣味性,熟悉做項目的流程,或得一些專業課程中無法獲得的特有項目經驗,增強自己面試的信心。講的項目應該真實可靠才有價值,否則,表面上是項目,實際上還是知識點的整合,對鞏固技術點和增強學習的趣味性,但無法獲得實際的項目經驗。(項目主要是增加你經驗的可信度,獲得更多面試機會,真正能不能找到工作,找到好工作,主要看你鍵盤上的功夫了),好的面試官幾下就能面出你是否真有工作經驗,他們問技術以外的公司的人和事,並且問開始、過程、結果,看你怎麼編。

建議大家儘量開自己的blog,堅持每天寫技術blog。在簡歷上寫上自己的blog地址,可以多轉載一些技術文章。

1. Java基礎部分

基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語法,集合的語法,io 的語法,虛擬機方面的語法,其他。有些題來自網上搜集整理,有些題來自傳智播客學員面試後的反饋,說真的,少數一些網上的面試題,我真懷疑其是否還有存在價值!

1、一個".java"源文件中是否可以包括多個類(不是內部類)?有什麼限制? 

可以有多個類,但只能有一個public的類,並且public的類名必須與文件名相一致。

2Java有沒有goto? 

java中的保留字,現在沒有在java中使用。

 

3、說說&&&的區別。 

&&&都可以用作邏輯與的運算符,表示邏輯與(and),當運算符兩邊的表達式的結果都爲true時,整個運算結果才爲true,否則,只要有一方爲false,則結果爲false

&&還具有短路的功能,即如果第一個表達式爲false,則不再計算第二個表達式,例如,對於if(str != null && !str.equals(“”))表達式,當strnull時,後面的表達式不會執行,所以不會出現NullPointerException如果將&&改爲&,則會拋出NullPointerException異常。If(x==33 & ++y>0) y會增長,If(x==33 && ++y>0)不會增長

&還可以用作位運算符,當&操作符兩邊的表達式不是boolean類型時,&表示按位與操作,我們通常使用0x0f來與一個整數進行&運算,來獲取該整數的最低4bit位,例如,0x31 & 0x0f的結果爲0x01。 

 

備註:這道題先說兩者的共同點,再說出&&&的特殊之處,並列舉一些經典的例子來表明自己理解透徹深入、實際經驗豐富。 

 

4、在JAVA中如何跳出當前的多重嵌套循環? 

Java中,要想跳出多重循環,可以在外面的循環語句前定義一個標號,然後在裏層循環體的代碼中使用帶有標號的break 語句,即可跳出外層循環。例如,

ok:

for(int i=0;i<10;i++)

{

for(int j=0;j<10;j++)

{

System.out.println(“i=” + i + “,j=” + j);

if(j == 5) break ok;

}

另外,我個人通常並不使用標號這種方式,而是讓外層的循環條件表達式的結果可以受到裏層循環體代碼的控制,例如,要在二維數組中查找到某個數字。

int arr[][] = {{1,2,3},{4,5,6,7},{9}};

boolean found = false;

for(int i=0;i<arr.length && !found;i++)

{

for(int j=0;j<arr[i].length;j++)

{

System.out.println(“i=” + i + “,j=” + j);

if(arr[i][j]  == 5) 

{

found = true;

break;

}

}

 

 

5switch語句能否作用在byte上,能否作用在long上,能否作用在String

switchexpr1)中,expr1只能是一個整數表達式或者枚舉常量(更大字體),整數表達式可以是int基本類型或Integer包裝類型,由於,byte,short,char都可以隱含轉換爲int,所以,這些類型以及這些類型的包裝類型也是可以的。顯然,longString類型都不符合switch的語法規定,並且不能被隱式轉換成int類型,所以,它們不能作用於swtich語句中。 

6short s1 = 1; s1 = s1 + 1;有什麼錯? short s1 = 1; s1 += 1;有什麼錯

對於short s1 = 1; s1 = s1 + 1; 由於s1+1運算時會自動提升表達式的類型,所以結果是int型,再賦值給short類型s1時,編譯器將報告需要強制轉換類型的錯誤。

對於short s1 = 1; s1 += 1;由於 += java語言規定的運算符,java編譯器會對它進行特殊處理,因此可以正確編譯。 

7char型變量中能不能存貯一箇中文漢字?爲什麼

char型變量是用來存儲Unicode編碼的字符的,unicode編碼字符集中包含了漢字,所以,char型變量中當然可以存儲漢字啦。不過,如果某個特殊的漢字沒有被包含在unicode編碼字符集中,那麼,這個char型變量中就不能存儲這個特殊漢字。補充說明:unicode編碼佔用兩個字節,所以,char類型的變量也是佔用兩個字節。

備註:後面一部分回答雖然不是在正面回答題目,但是,爲了展現自己的學識和表現自己對問題理解的透徹深入,可以回答一些相關的知識,做到知無不言,言無不盡。 

8、用最有效率的方法算出2乘以8等於幾

2 << 3,

因爲將一個數左移n位,就相當於乘以了2n次方,那麼,一個數乘以8只要將其左移3位即可,而位運算cpu直接支持的,效率最高,所以,2乘以8等於幾的最效率的方法是2 << 3。

9、請設計一個一百億的計算器

首先要明白這道題目的考查點是什麼,一是大家首先要對計算機原理的底層細節要清楚、要知道加減法的位運算原理和知道計算機中的算術運算會發生越界的情況,二是要具備一定的面向對象的設計思想。

首先,計算機中用固定數量的幾個字節來存儲的數值,所以計算機中能夠表示的數值是有一定的範圍的,爲了便於講解和理解,我們先以byte 類型的整數爲例,它用1個字節進行存儲,表示的最大數值範圍爲-128+127-1在內存中對應的二進制數據爲11111111,如果兩個-1相加,不考慮Java運算時的類型提升,運算後會產生進位,二進制結果爲1,11111110,由於進位後超過了byte類型的存儲空間,所以進位部分被捨棄,即最終的結果爲11111110,也就是-2,這正好利用溢位的方式實現了負數的運算。-128在內存中對應的二進制數據爲10000000,如果兩個-128相加,不考慮Java運算時的類型提升,運算後會產生進位,二進制結果爲1,00000000,由於進位後超過了byte類型的存儲空間,所以進位部分被捨棄,即最終的結果爲00000000,也就是0,這樣的結果顯然不是我們期望的,這說明計算機中的算術運算是會發生越界情況的,兩個數值的運算結果不能超過計算機中的該類型的數值範圍。由於Java中涉及表達式運算時的類型自動提升,我們無法用byte類型來做演示這種問題和現象的實驗,大家可以用下面一個使用整數做實驗的例子程序體驗一下:

int a = Integer.MAX_VALUE;

int b = Integer.MAX_VALUE;

int sum = a + b;

System.out.println(“a=”+a+”,b=”+b+”,sum=”+sum);

 

先不考慮long類型,由於int的正數範圍爲231次方,表示的最大數值約等於2*1000*1000*1000,也就是20億的大小,所以,要實現一個一百億的計算器,我們得自己設計一個類可以用於表示很大的整數,並且提供了與另外一個整數進行加減乘除的功能,大概功能如下:

()這個類內部有兩個成員變量,一個表示符號,另一個用字節數組表示數值的二進制數

()有一個構造方法,把一個包含有多位數值的字符串轉換到內部的符號和字節數組中

()提供加減乘除的功能

public class BigInteger

{

int sign;

byte[] val;

public Biginteger(String val)

{

sign = ;

val = ;

}

public BigInteger add(BigInteger other)

{

}

public BigInteger subtract(BigInteger other)

{

}

public BigInteger multiply(BigInteger other)

{

}

public BigInteger divide(BigInteger other)

{

}

 

}

備註:要想寫出這個類的完整代碼,是非常複雜的,如果有興趣的話,可以參看jdk中自帶的java.math.BigInteger類的源碼。面試的人也知道誰都不可能在短時間內寫出這個類的完整代碼的,他要的是你是否有這方面的概念和意識,他最重要的還是考查你的能力,所以,你不要因爲自己無法寫出完整的最終結果就放棄答這道題,你要做的就是你比別人寫得多,證明你比別人強,你有這方面的思想意識就可以了,畢竟別人可能連題目的意思都看不懂,什麼都沒寫,你要敢於答這道題,即使只答了一部分,那也與那些什麼都不懂的人區別出來,拉開了距離,算是矮子中的高個,機會當然就屬於你了。另外,答案中的框架代碼也很重要,體現了一些面向對象設計的功底,特別是其中的方法命名很專業,用的英文單詞很精準,這也是能力、經驗、專業性、英語水平等多個方面的體現,會給人留下很好的印象,在編程能力和其他方面條件差不多的情況下,英語好除了可以使你獲得更多機會外,薪水可以高出一千元。 

 

10、使用final關鍵字修飾一個變量時,是引用不能變,還是引用的對象不能變? 

使用final關鍵字修飾一個變量時,是指引用變量不能變,引用變量所指向的對象中的內容還是可以改變的。例如,對於如下語句:

 final StringBuffer a=new StringBuffer("immutable");
執行如下語句將報告編譯期錯誤:

a=new StringBuffer("");
但是,執行如下語句則可以通過編譯:

a.append(" broken!"); 

 

有人在定義方法的參數時,可能想採用如下形式來阻止方法內部修改傳進來的參數對象:

public void method(final  StringBuffer  param)

{

實際上,這是辦不到的,在該方法內部仍然可以增加如下代碼來修改參數對象:

param.append("a");

11"=="equals方法究竟有什麼區別?

(單獨把一個東西說清楚,然後再說清楚另一個,這樣,它們的區別自然就出來了,混在一起說,則很難說清楚)

==操作符專門用來比較兩個變量的值是否相等,也就是用於比較變量所對應的內存中所存儲的數值是否相同,要比較兩個基本類型的數據或兩個引用變量是否相等,只能用==操作符。

如果一個變量指向的數據是對象類型的,那麼,這時候涉及了兩塊內存,對象本身佔用一塊內存(堆內存),變量也佔用一塊內存,例如Objet obj = new Object();變量obj是一個內存,new Object()是另一個內存,此時,變量obj所對應的內存中存儲的數值就是對象佔用的那塊內存的首地址。對於指向對象類型的變量,如果要比較兩個變量是否指向同一個對象,即要看這兩個變量所對應的內存中的數值是否相等,這時候就需要用==操作符進行比較。

equals方法是用於比較兩個獨立對象的內容是否相同,就好比去比較兩個人的長相是否相同,它比較的兩個對象是獨立的。例如,對於下面的代碼:

String a=new String("foo");

String b=new String("foo");

兩條new語句創建了兩個對象,然後用a,b這兩個變量分別指向了其中一個對象,這是兩個不同的對象,它們的首地址是不同的,即ab中存儲的數值是不相同的,所以,表達式a==b將返回false,而這兩個對象中的內容是相同的,所以,表達式a.equals(b)將返回true

在實際開發中,我們經常要比較傳遞進行來的字符串內容是否等,例如,String input = …;input.equals(“quit”),許多人稍不注意就使用==進行比較了,這是錯誤的,隨便從網上找幾個項目實戰的教學視頻看看,裏面就有大量這樣的錯誤。記住,字符串的比較基本上都是使用equals方法。

如果一個類沒有自己定義equals方法,那麼它將繼承Object類的equals方法,Object類的equals方法的實現代碼如下:

boolean equals(Object o){

return this==o;

}

這說明,如果一個類沒有自己定義equals方法,它默認的equals方法(從Object 類繼承的)就是使用==操作符,也是在比較兩個變量指向的對象是否是同一對象,這時候使用equals和使用==會得到同樣的結果,如果比較的是兩個獨立的對象則總返回false。如果你編寫的類希望能夠比較該類創建的兩個實例對象的內容是否相同,那麼你必須覆蓋equals方法,由你自己寫代碼來決定在什麼情況即可認爲兩個對象的內容是相同的。

12、靜態變量和實例變量的區別? 

在語法定義上的區別:靜態變量前要加static關鍵字,而實例變量前則不加。

在程序運行時的區別:實例變量屬於某個對象的屬性,必須創建了實例對象,其中的實例變量纔會被分配空間,才能使用這個實例變量。靜態變量不屬於某個實例對象,而是屬於類,所以也稱爲類變量,只要程序加載了類的字節碼,不用創建任何實例對象,靜態變量就會被分配空間,靜態變量就可以被使用了。總之,實例變量必須創建對象後纔可以通過這個對象來使用,靜態變量則可以直接使用類名來引用。

例如,對於下面的程序,無論創建多少個實例對象,永遠都只分配了一個staticVar變量,並且每創建一個實例對象,這個staticVar就會加1;但是,每創建一個實例對象,就會分配一個instanceVar,即可能分配多個instanceVar,並且每個instanceVar的值都只自加了1次。

public class VariantTest

{

public static int staticVar = 0; 

public int instanceVar = 0; 

public VariantTest()

{

staticVar++;

instanceVar++;

System.out.println(“staticVar=” + staticVar + ”,instanceVar=” + instanceVar);

}

}

備註:這個解答除了說清楚兩者的區別外,最後還用一個具體的應用例子來說明兩者的差異,體現了自己有很好的解說問題和設計案例的能力,思維敏捷,超過一般程序員,有寫作能力!

13、是否可以從一個static方法內部發出對非static方法的調用? 

不可以。因爲非static方法是要與對象關聯在一起的,必須創建一個對象後,纔可以在該對象上進行方法調用,而static方法調用時不需要創建對象,可以直接調用。也就是說,當一個static方法被調用時,可能還沒有創建任何實例對象,如果從一個static方法中發出對非static方法的調用,那個非static方法是關聯到哪個對象上的呢?這個邏輯無法成立,所以,一個static方法內部發出對非static方法的調用。

14Integerint的區別

intjava提供的8種原始數據類型之一。Java爲每個原始類型提供了封裝類,Integerjavaint提供的封裝類。int的默認值爲0,而Integer的默認值爲null,即Integer可以區分出未賦值和值爲0的區別,int則無法表達出未賦值的情況,例如,要想表達出沒有參加考試和考試成績爲0的區別,則只能使用Integer。在JSP開發中,Integer的默認爲null,所以用el表達式在文本框中顯示時,值爲空白字符串,而int默認的默認值爲0,所以用el表達式在文本框中顯示時,結果爲0,所以,int不適合作爲web層的表單數據的類型。

Hibernate中,如果將OID定義爲Integer類型,那麼Hibernate就可以根據其值是否爲null而判斷一個對象是否是臨時的,如果將OID定義爲了int類型,還需要在hbm映射文件中設置其unsaved-value屬性爲0

另外,Integer提供了多個與整數相關的操作方法,例如,將一個字符串轉換成整數,Integer中還定義了表示整數的最大值和最小值的常量。

 

15Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

Math類中提供了三個與取整有關的方法:ceilfloorround,這些方法的作用與它們的英文名稱的含義相對應,例如,ceil的英文意義是天花板,該方法就表示向上取整,Math.ceil(11.3)的結果爲12,Math.ceil(-11.3)的結果是-11floor的英文意義是地板,該方法就表示向下取整,Math.ceil(11.6)的結果爲11,Math.ceil(-11.6)的結果是-12;最難掌握的是round方法,它表示“四捨五入”,算法爲Math.floor(x+0.5),即將原來的數字加上0.5後再向下取整,所以,Math.round(11.5)的結果爲12Math.round(-11.5)的結果爲-11

 

15、下面的代碼有什麼不妥之處?

1. if(username.equals(“zxx”){}

2. int  x = 1;

return x==1?true:false;

 

1、請說出作用域publicprivateprotected,以及不寫時的區別

這四個作用域的可見範圍如下表所示。

說明:如果在修飾的元素上面沒有寫任何訪問修飾符,則表示friendly

 

作用域    當前類 同一package 子孫類 其他package 

public    √     √          √       √ 

protected  √     √          √      × 

friendly   √     √          ×      × 

private    √     ×          ×      × 

備註:只要記住了有4種訪問權限,4個訪問範圍,然後將全選和範圍在水平和垂直方向上分別按排從小到大或從大到小的順序排列,就很容易畫出上面的圖了。

2OverloadOverride的區別。Overloaded的方法是否可以改變返回值的類型

Overload是重載的意思,Override是覆蓋的意思,也就是重寫。

重載Overload表示同一個類中可以有多個名稱相同的方法,但這些方法的參數列表各不相同(即參數個數或類型不同)。

重寫Override表示子類中的方法可以與父類中的某個方法的名稱和參數完全相同,通過子類創建的實例對象調用這個方法時,將調用子類中的定義方法,這相當於把父類中定義的那個完全相同的方法給覆蓋了,這也是面向對象編程的多態性的一種表現。子類覆蓋父類的方法時,只能比父類拋出更少的異常,或者是拋出父類拋出的異常的子異常,因爲子類可以解決父類的一些問題,不能比父類有更多的問題。子類方法的訪問權限只能比父類的更大,不能更小。如果父類的方法是private類型,那麼,子類則不存在覆蓋的限制,相當於子類中增加了一個全新的方法。

至於Overloaded的方法是否可以改變返回值的類型這個問題,要看你倒底想問什麼呢?這個題目很模糊。如果幾個Overloaded的方法的參數列表不一樣,它們的返回者類型當然也可以不一樣。但我估計你想問的問題是:如果兩個方法的參數列表完全一樣,是否可以讓它們的返回值不同來實現重載Overload。這是不行的,我們可以用反證法來說明這個問題,因爲我們有時候調用一個方法時也可以不定義返回結果變量,即不要關心其返回結果,例如,我們調用map.remove(key)方法時,雖然remove方法有返回值,但是我們通常都不會定義接收返回結果的變量,這時候假設該類中有兩個名稱和參數列表完全相同的方法,僅僅是返回類型不同,java就無法確定編程者倒底是想調用哪個方法了,因爲它無法通過返回結果類型來判斷。 

 

override可以翻譯爲覆蓋,從字面就可以知道,它是覆蓋了一個方法並且對其重寫,以求達到不同的作用。對我們來說最熟悉的覆蓋就是對接口方法的實現,在接口中一般只是對方法進行了聲明,而我們在實現時,就需要實現接口聲明的所有方法。除了這個典型的用法以外,我們在繼承中也可能會在子類覆蓋父類中的方法。在覆蓋要注意以下的幾點:

1、覆蓋的方法的標誌必須要和被覆蓋的方法的標誌完全匹配,才能達到覆蓋的效果;

2、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;

3、覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類;

4、被覆蓋的方法不能爲private,否則在其子類中只是新定義了一個方法,並沒有對其進行覆蓋。

overload對我們來說可能比較熟悉,可以翻譯爲重載,它是指我們可以定義一些名稱相同的方法,通過定義不同的輸入參數來區分這些方法,然後再調用時,VM就會根據不同的參數樣式,來選擇合適的方法執行。在使用重載要注意以下的幾點:

1、在使用重載時只能通過不同的參數樣式。例如,不同的參數類型,不同的參數個數,不同的參數順序(當然,同一方法內的幾個參數類型必須不一樣,例如可以是fun(int,float),但是不能爲fun(int,int));

2、不能通過訪問權限、返回類型、拋出的異常進行重載;

3、方法的異常類型和數目不會對重載造成影響;

4、對於繼承來說,如果某一方法在父類中是訪問權限是priavte,那麼就不能在子類對其進行重載,如果定義的話,也只是定義了一個新方法,而不會達到重載的效果。

 

3421號班同學貢獻的一些題

朱wenchao,女:3500,21歲

搞了多個重載方法,參數分別是int ,char,和double,然後將double x = 2,傳遞進去,會選擇哪個方法?

說說對javaee中的session的理解,你是怎麼用session的?cvs/svn下載

jdk中哪些類是不能繼承的:System,String,StringBuffer等。

在eclipse中調試時,怎樣查看一個變量的值。

 

陳yong, 4000

判斷身份證:要麼是15位,要麼是18位,最後一位可以爲字母,並寫程序提出其中的年月日。

一個房子裏有椅子,椅子有腿和背,房子與椅子是什麼關係,椅子與腿和背是什麼關係?

如果房子有多個椅子,就是聚合關係,否則是一種關聯關係,當然,聚合是一種特殊的關聯。椅子與腿和背時組合關係。

說說has ais a的區別。

工廠模式的類圖

4515號班同學貢獻的一些題?

1. 線程如何同步和通訊。 同學回答說synchronized方法或代碼塊!面試官似乎不太滿意!

 只有多個synchronized代碼塊使用的是同一個監視器對象,這些synchronized代碼塊之間才具有線程互斥的效果,假如a代碼塊用obj1作爲監視器對象,假如b代碼塊用obj2作爲監視器對象,那麼,兩個併發的線程可以同時分別進入這兩個代碼塊中。 …這裏還可以分析一下同步的原理。

   對於同步方法的分析,所用的同步監視器對象是this

   接着對於靜態同步方法的分析,所用的同步監視器對象是該類的Class對象

接着對如何實現代碼塊與方法的同步進行分析。

2.ClassLoader如何加載class 

    jvm裏有多個類加載,每個類加載可以負責加載特定位置的類,例如,bootstrap類加載負責加載jre/lib/rt.jar中的類, 我們平時用的jdk中的類都位於rt.jar中。extclassloader負責加載jar/lib/ext/*.jar中的類,appclassloader負責classpath指定的目錄或jar中的類。除了bootstrap之外,其他的類加載器本身也都是java類,它們的父類是ClassLoader

3.Servlet的生命週期

Servlet生命週期分爲三個階段:

  1,初始化階段  調用init()方法

  2,響應客戶請求階段  調用service()方法

  3,終止階段  調用destroy()方法

 

4.抽象類的作用

5.ArrayList如何實現插入的數據按自定義的方式有序存放

class MyBean implements Comparable{

public int compareTo(Object obj){

if(! obj instanceof MyBean)

throw new ClassCastException() //具體異常的名稱,我要查jdk文檔。

MyBean other = (MyBean) obj;

return age > other.age?1:age== other.age?0:-1;

}

}

 

 

class MyTreeSet {

 

private ArrayList  datas = new ArrayList();

public void add(Object obj){

for(int i=0;i<datas.size();i++){

if(obj.compareTo(datas.get(i) != 1){

datas.add(i,obj);

}

}

}

}

 

6.分層設計的好處;把各個功能按調用流程進行了模塊化,模塊化帶來的好處就是可以隨意組合,舉例說明:如果要註冊一個用戶,流程爲顯示界面並通過界面接收用戶的輸入,接着進行業務邏輯處理,在處理業務邏輯又訪問數據庫,如果我們將這些步驟全部按流水帳的方式放在一個方法中編寫,這也是可以的,但這其中的壞處就是,當界面要修改時,由於代碼全在一個方法內,可能會碰壞業務邏輯和數據庫訪問的碼,同樣,當修改業務邏輯或數據庫訪問的代碼時,也會碰壞其他部分的代碼。分層就是要把界面部分、業務邏輯部分、數據庫訪問部分的代碼放在各自獨立的方法或類中編寫,這樣就不會出現牽一髮而動全身的問題了。這樣分層後,還可以方便切換各層,譬如原來的界面是Swing,現在要改成BS界面,如果最初是按分層設計的,這時候不需要涉及業務和數據訪問的代碼,只需編寫一條web界面就可以了。

   下面的僅供參考,不建議照搬照套,一定要改成自己的語言,發現內心的感受:

  分層的好處:

1,實現了軟件之間的解耦;

2.便於進行分工

3.便於維護

4,提高軟件組件的重用

5.便於替換某種產品,比如持久層用的是hibernate,需要更換產品用toplink,就不用該其他業務代碼,直接把配置一改。

6.便於產品功能的擴展。

7。便於適用用戶需求的不斷變化

 

7.序列化接口的id有什麼用?

   對象經常要通過IO進行傳送,讓你寫程序傳遞對象,你會怎麼做?把對象的狀態數據用某種格式寫入到硬盤,Person->“zxx,male,28,30000”àPerson,既然大家都要這麼幹,並且沒有個統一的幹法,於是,sun公司就提出一種統一的解決方案,它會把對象變成某個格式進行輸入和輸出,這種格式對程序員來說是透明(transparent)的,但是,我們的某個類要想能被sun的這種方案處理,必須實現Serializable接口。

   ObjectOutputStream.writeObject(obj);

   Object obj = ObjectInputStream.readObject();

   假設兩年前我保存了某個類的一個對象,這兩年來,我修改該類,刪除了某個屬性和增加了另外一個屬性,兩年後,我又去讀取那個保存的對象,或有什麼結果?未知!sun的jdk就會蒙了。爲此,一個解決辦法就是在類中增加版本後,每一次類的屬性修改,都應該把版本號升級一下,這樣,在讀取時,比較存儲對象時的版本號與當前類的版本號,如果不一致,則直接報版本號不同的錯!

 

8.StringBufferStringBuilder的區別

  因爲 StringBuilder sbuilder = ;是線程不安全的,運行效率高,如果一個字符串變量是在方法裏面定義,這種情況只可能有一個線程訪問它,不存在不安全的因素了,則用StringBuilder。如果要在類裏面定義成員變量,並且這個類的實例對象會在多線程環境下使用,那麼最好用StringBuffer

9.hashCode方法的作用?說

10.webservice問得很多

11.設計出計算任意正整數的階層。

 

4.oracle數據庫中需要查詢出前8條記錄的sql語句怎麼寫?

 

 

5.什麼是SOA,談談你的SOA的理解。service orientied architecture

6.如何實現線程間的通訊。

 

新題目:編程:1.編寫一個函數將一個十六進制數的字符串參數轉換成整數返回。

String str = “13abf”;

int len = str.length;

int sum = 0;

for(int i=0;i<len;i++){

char c = str.charAt(len-1-i);

int n = Character.digit(c,16);

sum += n * (1<<(4*i));

}

      

     其實,也可以用Integer.parseInt(str,16),但面試官很可能是想考我們的編碼基本功。

 

編程2

   :銀行貸款的還款方式中最常用的是一種叫“等額本息”,還款法,即借款人在約定還款期限內的每一期(月)歸還的金額(產生的利息+部分本金)都是相等的,現有一筆總額爲T元的N年期住房貸款,年利率爲R,要求算出每一期的還款的本金和利息總額,請寫出解決思路和任意一種編程語言實現的主要代碼。

思路:既然是按月還款,那我就要將N年按月來計算,即要還N*12個月,這樣就可以求出每月要還的本金。由於每月要還的那部分本金所欠的時間不同,所以,它們所產生的利息是不同的,該部分本金的利息爲:部分本金額*所欠月數*月利率。應該是這麼個算法,如果利息還計利息,如果月還款不按年利率來算,老百姓算不明白的。

int monthMoney = T/N/12;

float monthRate = R/12;

int totalMonth = N * 12;

float totalRate = 0;

for(int i=1;i<=totalMonth;i++){

totalRate += monthMoney * monthRate * i;

}

int result = monthMoney + totalRate/N/12;

 

幾道題:

1. ****SpringDI是什麼(學員注:除了IOCAOP這些概念,還不太清楚DI的概念)

2. *任意數字序列“123456”之類,輸出它們所有的排列組合

3. *****什麼是AOP(學員注:會用,但感覺說不清楚)

我注:由上面這些題,可以看出,思想很重要,只有琢磨思想和原理的人才能很好地回答這些問題!

2題的答案:

String str = “xafdvs”;

char[] arr1 = str.toCharArray();

char[] arr2 = Arrays.copyOf(arr1,arr1.length);

for(int i=0;i<arr1.length-1;i++)

{

for(int j = i+1;j<arr2.length;j++){

syso: arr1[i] + “,” + arr2[j];

}

}

3題的答案:

1.概念介紹:所謂AOP,即Aspect orientied program,就是面向方面的編程,

2.解釋什麼是方面:貫穿到系統的各個模塊中的系統一個功能就是一個方面,

比如,記錄日誌,統一異常處理,事務處理,全限檢查,這些功能都是軟件系統

的一個面,而不是一點,在各個模塊中都要出現。

3.什麼是面向方面編程:把系統的一個方面的功能封裝成對象的形式來處理

4.怎麼進行面向方面編程:把功能模塊對應的對象作爲切面嵌入到原來的各個系統模塊中,

採用代理技術,代理會調用目標,同時把切面功能的代碼(對象)加入進來,所以,

spring配置代理對象時只要要配兩個屬性,分別表示目標和切面對象(Advisor)。

3、構造器Constructor是否可被override? 

構造器Constructor不能被繼承,因此不能重寫Override,但可以被重載Overload。 

4、接口是否可繼承接口抽象類是否可實現(implements)接口抽象類是否可繼承具體類(concrete class)? 抽象類中是否可以有靜態的main方法?

接口可以繼承接口。抽象類可以實現(implements)接口,抽象類是否可繼承具體類。抽象類中可以有靜態的main方法。

備註:只要明白了接口和抽象類的本質和作用,這些問題都很好回答,你想想,如果你是java語言的設計者,你是否會提供這樣的支持,如果不提供的話,有什麼理由嗎?如果你沒有道理不提供,那答案就是肯定的了。

 只有記住抽象類與普通類的唯一區別就是不能創建實例對象和允許有abstract方法。

 

5、寫clone()方法時,通常都有一行代碼,是什麼? 

clone 有缺省行爲,super.clone();因爲首先要把父類中的成員複製到位,然後纔是複製自己的成員。 

6、面向對象的特徵有哪些方面

計算機軟件系統是現實生活中的業務在計算機中的映射,而現實生活中的業務其實就是一個個對象協作的過程。面向對象編程就是按現實業務一樣的方式將程序代碼按一個個對象進行組織和編寫,讓計算機系統能夠識別和理解用對象方式組織和編寫的程序代碼,這樣就可以把現實生活中的業務對象映射到計算機系統中。

面向對象的編程語言有封裝、繼承 、抽象、多態等4個主要的特徵。

1封裝:

封裝是保證軟件部件具有優良的模塊性的基礎,封裝的目標就是要實現軟件部件的“高內聚、低耦合”,防止程序相互依賴性而帶來的變動影響。在面向對象的編程語言中,對象是封裝的最基本單位,面向對象的封裝比傳統語言的封裝更爲清晰、更爲有力。面向對象的封裝就是把描述一個對象的屬性和行爲的代碼封裝在一個“模塊”中,也就是一個類中,屬性用變量定義,行爲用方法進行定義,方法可以直接訪問同一個對象中的屬性。通常情況下,只要記住讓變量和訪問這個變量的方法放在一起,將一個類中的成員變量全部定義成私有的,只有這個類自己的方法纔可以訪問到這些成員變量,這就基本上實現對象的封裝,就很容易找出要分配到這個類上的方法了,就基本上算是會面向對象的編程了。把握一個原則:把對同一事物進行操作的方法和相關的方法放在同一個類中,把方法和它操作的數據放在同一個類中。

例如,人要在黑板上畫圓,這一共涉及三個對象:人、黑板、圓,畫圓的方法要分配給哪個對象呢?由於畫圓需要使用到圓心和半徑,圓心和半徑顯然是圓的屬性,如果將它們在類中定義成了私有的成員變量,那麼,畫圓的方法必須分配給圓,它才能訪問到圓心和半徑這兩個屬性,人以後只是調用圓的畫圓方法、表示給圓發給消息而已,畫圓這個方法不應該分配在人這個對象上,這就是面向對象的封裝性,即將對象封裝成一個高度自治和相對封閉的個體,對象狀態(屬性)由這個對象自己的行爲(方法)來讀取和改變。一個更便於理解的例子就是,司機將火車剎住了,剎車的動作是分配給司機,還是分配給火車,顯然,應該分配給火車,因爲司機自身是不可能有那麼大的力氣將一個火車給停下來的,只有火車自己才能完成這一動作,火車需要調用內部的離合器和剎車片等多個器件協作才能完成剎車這個動作,司機剎車的過程只是給火車發了一個消息,通知火車要執行剎車動作而已。

 

抽象:

抽象就是找出一些事物的相似和共性之處,然後將這些事物歸爲一個類,這個類只考慮這些事物的相似和共性之處,並且會忽略與當前主題和目標無關的那些方面,將注意力集中在與當前目標有關的方面。例如,看到一隻螞蟻和大象,你能夠想象出它們的相同之處,那就是抽象。抽象包括行爲抽象和狀態抽象兩個方面。例如,定義一個Person類,如下:

class Person

{

String name;

int age;

}

人本來是很複雜的事物,有很多方面,但因爲當前系統只需要瞭解人的姓名和年齡,所以上面定義的類中只包含姓名和年齡這兩個屬性,這就是一種抽像,使用抽象可以避免考慮一些與目標無關的細節。我對抽象的理解就是不要用顯微鏡去看一個事物的所有方面,這樣涉及的內容就太多了,而是要善於劃分問題的邊界,當前系統需要什麼,就只考慮什麼。

 

繼承:

在定義和實現一個類的時候,可以在一個已經存在的類的基礎之上來進行,把這個已經存在的類所定義的內容作爲自己的內容,並可以加入若干新的內容,或修改原來的方法使之更適合特殊的需要,這就是繼承。繼承是子類自動共享父類數據和方法的機制,這是類之間的一種關係,提高了軟件的可重用性和可擴展性。

 

多態:

多態是指程序中定義的引用變量所指向的具體類型和通過該引用變量發出的方法調用在編程時並不確定,而是在程序運行期間才確定,即一個引用變量倒底會指向哪個類的實例對象,該引用變量發出的方法調用到底是哪個類中實現的方法,必須在由程序運行期間才能決定。因爲在程序運行時才確定具體的類,這樣,不用修改源程序代碼,就可以讓引用變量綁定到各種不同的類實現上,從而導致該引用調用的具體方法隨之改變,即不修改程序代碼就可以改變程序運行時所綁定的具體代碼,讓程序可以選擇多個運行狀態,這就是多態性。多態性增強了軟件的靈活性和擴展性。例如,下面代碼中的UserDao是一個接口,它定義引用變量userDao指向的實例對象由daofactory.getDao()在執行的時候返回,有時候指向的是UserJdbcDao這個實現,有時候指向的是UserHibernateDao這個實現,這樣,不用修改源代碼,就可以改變userDao指向的具體類實現,從而導致userDao.insertUser()方法調用的具體代碼也隨之改變,即有時候調用的是UserJdbcDaoinsertUser方法,有時候調用的是UserHibernateDaoinsertUser方法:

UserDao userDao = daofactory.getDao();  

userDao.insertUser(user);

 

比喻:人吃飯,你看到的是左手,還是右手?

7java中實現多態的機制是什麼? 

靠的是父類或接口定義的引用變量可以指向子類或具體實現類的實例對象,而程序調用的方法在運行期才動態綁定,就是引用變量所指向的具體實例對象的方法,也就是內存里正在運行的那個對象的方法,而不是引用變量的類型中定義的方法。 

8abstract classinterface有什麼區別

含有abstract修飾符的class即爲抽象類,abstract 類不能創建的實例對象。含有abstract方法的類必須定義爲abstract classabstract class類中的方法不必是抽象的。abstract class類中定義抽象方法必須在具體(Concrete)子類中實現,所以,不能有抽象構造方法或抽象靜態方法。如果的子類沒有實現抽象父類中的所有抽象方法,那麼子類也必須定義爲abstract類型。

接口(interface)可以說成是抽象類的一種特例,接口中的所有方法都必須是抽象的。接口中的方法定義默認爲public abstract類型,接口中的成員變量類型默認爲public static final

下面比較一下兩者的語法區別:

1.抽象類可以有構造方法,接口中不能有構造方法。

2.抽象類中可以有普通成員變量,接口中沒有普通成員變量

3.抽象類中可以包含非抽象的普通方法,接口中的所有方法必須都是抽象的,不能有非抽象的普通方法。

4. 抽象類中的抽象方法的訪問類型可以是publicprotected和(默認類型,雖然

eclipse下不報錯,但應該也不行),但接口中的抽象方法只能是public類型的,並且默認即爲public abstract類型。

5. 抽象類中可以包含靜態方法,接口中不能包含靜態方法

6. 抽象類和接口中都可以包含靜態成員變量,抽象類中的靜態成員變量的訪問類型可以任意,但接口中定義的變量只能是public static final類型,並且默認即爲public static final類型。

7. 一個類可以實現多個接口,但只能繼承一個抽象類。

下面接着再說說兩者在應用上的區別:

接口更多的是在系統架構設計方法發揮作用,主要用於定義模塊之間的通信契約。而抽象類在代碼實現方面發揮作用,可以實現代碼的重用,例如,模板方法設計模式是抽象類的一個典型應用,假設某個項目的所有Servlet類都要用相同的方式進行權限判斷、記錄訪問日誌和處理異常,那麼就可以定義一個抽象的基類,讓所有的Servlet都繼承這個抽象基類,在抽象基類的service方法中完成權限判斷、記錄訪問日誌和處理異常的代碼,在各個子類中只是完成各自的業務邏輯代碼,僞代碼如下:

public abstract class BaseServlet extends HttpServlet

{

public final void service(HttpServletRequest request, HttpServletResponse response) throws IOExcetion,ServletException

{

記錄訪問日誌

進行權限判斷

if(具有權限)

{

try

{

doService(request,response);

}

catch(Excetpion e)

{

記錄異常信息

}

}

protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws IOExcetion,ServletException;  

//注意訪問權限定義成protected,顯得既專業,又嚴謹,因爲它是專門給子類用的

}

 

public class MyServlet1 extends BaseServlet

{

protected void doService(HttpServletRequest request, HttpServletResponse response) throws IOExcetion,ServletException

{

Servlet只處理的具體業務邏輯代碼

 

}

父類方法中間的某段代碼不確定,留給子類幹,就用模板方法設計模式。

備註:這道題的思路是先從總體解釋抽象類和接口的基本概念,然後再比較兩者的語法細節,最後再說兩者的應用區別。比較兩者語法細節區別的條理是:先從一個類中的構造方法、普通成員變量和方法(包括抽象方法),靜態變量和方法,繼承性等6個方面逐一去比較回答,接着從第三者繼承的角度的回答,特別是最後用了一個典型的例子來展現自己深厚的技術功底。

9abstractmethod是否可同時是static,是否可同時是native,是否可同時是synchronized? 

abstractmethod 不可以是static的,因爲抽象的方法是要被子類實現的,而static與子類扯不上關係!

native方法表示該方法要用另外一種依賴平臺的編程語言實現的,不存在着被子類實現的問題,所以,它也不能是抽象的,不能與abstract混用。例如,FileOutputSteam類要硬件打交道,底層的實現用的是操作系統相關的api實現,例如,在windowsc語言實現的,所以,查看jdk 的源代碼,可以發現FileOutputStreamopen方法的定義如下:

private native void open(String name) throws FileNotFoundException;

如果我們要用java調用別人寫的c語言函數,我們是無法直接調用的,我們需要按照java的要求寫一個c語言的函數,又我們的這個c語言函數去調用別人的c語言函數。由於我們的c語言函數是按java的要求來寫的,我們這個c語言函數就可以與java對接上,java那邊的對接方式就是定義出與我們這個c函數相對應的方法,java中對應的方法不需要寫具體的代碼,但需要在前面聲明native

關於synchronizedabstract合用的問題,我覺得也不行,因爲在我幾年的學習和開發中,從來沒見到過這種情況,並且我覺得synchronized應該是作用在一個具體的方法上纔有意義。而且,方法上的synchronized同步所使用的同步鎖對象是this,而抽象方法上無法確定this是什麼。 

10、什麼是內部類?Static Nested Class 和 Inner Class的不同。

內部類就是在一個類的內部定義的類,內部類中不能定義靜態成員(靜態成員不是對象的特性,只是爲了找一個容身之處,所以需要放到一個類中而已,這麼一點小事,你還要把它放到類內部的一個類中,過分了啊!提供內部類,不是爲讓你幹這種事情,無聊,不讓你幹。我想可能是既然靜態成員類似c語言的全局變量,而內部類通常是用於創建內部對象用的,所以,把“全局變量”放在內部類中就是毫無意義的事情,既然是毫無意義的事情,就應該被禁止),內部類可以直接訪問外部類中的成員變量,內部類可以定義在外部類的方法外面,也可以定義在外部類的方法體中,如下所示:

public class Outer

{

int out_x  = 0;

public void method()
{

Inner1 inner1 = new Inner1();

public class Inner2   //在方法體內部定義的內部類

{

public method()

{

out_x = 3;

}

}

Inner2 inner2 = new Inner2();

}

 

public class Inner1   //在方法體外面定義的內部類

{

}

}

在方法體外面定義的內部類的訪問類型可以是public,protecte,默認的,private4種類型,這就好像類中定義的成員變量有4種訪問類型一樣,它們決定這個內部類的定義對其他類是否可見;對於這種情況,我們也可以在外面創建內部類的實例對象,創建內部類的實例對象時,一定要先創建外部類的實例對象,然後用這個外部類的實例對象去創建內部類的實例對象,代碼如下:

Outer outer = new Outer();

Outer.Inner1 inner1 = outer.new Innner1();

 

在方法內部定義的內部類前面不能有訪問類型修飾符,就好像方法中定義的局部變量一樣,但這種內部類的前面可以使用finalabstract修飾符。這種內部類對其他類是不可見的其他類無法引用這種內部類,但是這種內部類創建的實例對象可以傳遞給其他類訪問。這種內部類必須是先定義,後使用,即內部類的定義代碼必須出現在使用該類之前,這與方法中的局部變量必須先定義後使用的道理也是一樣的。這種內部類可以訪問方法體中的局部變量,但是,該局部變量前必須加final修飾符。

對於這些細節,只要在eclipse寫代碼試試,根據開發工具提示的各類錯誤信息就可以馬上瞭解到。

 

在方法體內部還可以採用如下語法來創建一種匿名內部類,即定義某一接口或類的子類的同時,還創建了該子類的實例對象,無需爲該子類定義名稱:

public class Outer

{

public void start()

{

new Thread(

new Runable(){

public void run(){};

}

).start();

}

}

 

最後,在方法外部定義的內部類前面可以加上static關鍵字,從而成爲Static Nested Class,它不再具有內部類的特性,所有,從狹義上講,它不是內部類。Static Nested Class與普通類在運行時的行爲和功能上沒有什麼區別,只是在編程引用時的語法上有一些差別,它可以定義成publicprotected、默認的、private等多種類型,而普通類只能定義成public和默認的這兩種類型。在外面引用Static Nested Class類的名稱爲“外部類名.內部類名”。在外面不需要創建外部類的實例對象,就可以直接創建Static Nested Class,例如,假設Inner是定義在Outer類中的Static Nested Class,那麼可以使用如下語句創建Inner類:

Outer.Inner inner = new Outer.Inner();

由於static Nested Class不依賴於外部類的實例對象,所以,static Nested Class能訪問外部類的非static成員變量。當在外部類中訪問Static Nested Class時,可以直接使用Static Nested Class的名字,而不需要加上外部類的名字了,在Static Nested Class中也可以直接引用外部類的static的成員變量,不需要加上外部類的名字。

在靜態方法中定義的內部類也是Static Nested Class,這時候不能在類前面加static關鍵字,靜態方法中的Static Nested Class與普通方法中的內部類的應用方式很相似,它除了可以直接訪問外部類中的static的成員變量,還可以訪問靜態方法中的局部變量,但是,該局部變量前必須加final修飾符。

 

備註:首先根據你的印象說出你對內部類的總體方面的特點:例如,在兩個地方可以定義,可以訪問外部類的成員變量,不能定義靜態成員,這是大的特點。然後再說一些細節方面的知識,例如,幾種定義方式的語法區別,靜態內部類,以及匿名內部類。

11、內部類可以引用它的包含類的成員嗎?有沒有什麼限制? 

完全可以。如果不是靜態內部類,那沒有什麼限制! 

如果你把靜態嵌套類當作內部類的一種特例,那在這種情況下不可以訪問外部類的普通成員變量,而只能訪問外部類中的靜態成員,例如,下面的代碼:

class Outer

{

static int x;

static class Inner

{

void test()

{

syso(x);

}

}

}

 

答題時,也要能察言觀色,揣摩提問者的心思,顯然人家希望你說的是靜態內部類不能訪問外部類的成員,但你一上來就頂牛,這不好,要先順着人家,讓人家滿意,然後再說特殊情況,讓人家吃驚。

 

12Anonymous Inner Class (匿名內部類是否可以extends(繼承)其它類,是否可以implements(實現)interface(接口)? 

可以繼承其他類或實現其他接口。不僅是可以,而是必須!

13super.getClass()方法調用

下面程序的輸出結果是多少?

import java.util.Date;

public  class Test extends Date{

public static void main(String[] args) {

new Test().test();

}

public void test(){

System.out.println(super.getClass().getName());

}

}

 

很奇怪,結果是Test

這屬於腦筋急轉彎的題目,在一個qq羣有個網友正好問過這個問題,我覺得挺有趣,就研究了一下,沒想到今天還被你面到了,哈哈。

test方法中,直接調用getClass().getName()方法,返回的是Test類名

由於getClass()Object類中定義成了final,子類不能覆蓋該方法,所以,在

test方法中調用getClass().getName()方法,其實就是在調用從父類繼承的getClass()方法,等效於調用super.getClass().getName()方法,所以,super.getClass().getName()方法返回的也應該是Test

如果想得到父類的名稱,應該用如下代碼:

getClass().getSuperClass().getName();

 

 

2String是最基本的數據類型嗎

基本數據類型包括byteintcharlongfloatdoublebooleanshort。 

java.lang.String類是final類型的,因此不可以繼承這個類、不能修改這個類。爲了提高效率節省空間,我們應該用StringBuffer類 

 

111String s = "Hello";s = s + " world!";這兩行代碼執行後,原始的String對象中的內容到底變了沒有?


沒有。因爲String被設計成不可變(immutable)類,所以它的所有對象都是不可變對象。在這段代碼中,s原先指向一個String對象,內容是 "Hello",然後我們對s進行了+操作,那麼s所指向的那個對象是否發生了改變呢?答案是沒有。這時,s不指向原來那個對象了,而指向了另一個 String對象,內容爲"Hello world!",原來那個對象還存在於內存之中,只是s這個引用變量不再指向它了。
通過上面的說明,我們很容易導出另一個結論,如果經常對字符串進行各種各樣的修改,或者說,不可預見的修改,那麼使用String來代表字符串的話會引起很大的內存開銷。因爲 String對象建立之後不能再改變,所以對於每一個不同的字符串,都需要一個String對象來表示。這時,應該考慮使用StringBuffer類,它允許修改,而不是每個不同的字符串都要生成一個新的對象。並且,這兩種類的對象轉換十分容易。
同時,我們還可以知道,如果要使用內容相同的字符串,不必每次都new一個String。例如我們要在構造器中對一個名叫sString引用變量進行初始化,把它設置爲初始值,應當這樣做:
public class Demo {
private String s;
...
public Demo {
s = "Initial Value";
}
...
}
而非
s = new String("Initial Value");
後者每次都會調用構造器,生成新對象,性能低下且內存開銷大,並且沒有意義,因爲String對象不可改變,所以對於內容相同的字符串,只要一個String對象來表示就可以了。也就說,多次調用上面的構造器創建多個對象,他們的String類型屬性s都指向同一個對象。
上面的結論還基於這樣一個事實:對於字符串常量,如果內容相同,Java認爲它們代表同一個String對象。而用關鍵字new調用構造器,總是會創建一個新的對象,無論內容是否相同。
至於爲什麼要把String類設計成不可變類,是它的用途決定的。其實不只String,很多Java標準類庫中的類都是不可變的。在開發一個系統的時候,我們有時候也需要設計不可變類,來傳遞一組相關的值,這也是面向對象思想的體現。不可變類有一些優點,比如因爲它的對象是隻讀的,所以多線程併發訪問也不會有任何問題。當然也有一些缺點,比如每個不同的狀態都要一個對象來代表,可能會造成性能上的問題。所以Java標準類庫還提供了一個可變版本,即 StringBuffer

41、是否可以繼承String

String類是final類故不可以繼承。 

 

27String s = new String("xyz");創建了幾個String Object? 二者之間有什麼區別?

兩個或一個,”xyz”對應一個對象,這個對象放在字符串常量緩衝區,常量”xyz”不管出現多少遍,都是緩衝區中的那一個。New String每寫一遍,就創建一個新的對象,它一句那個常量”xyz”對象的內容來創建出一個新String對象。如果以前就用過’xyz’,這句代表就不會創建”xyz”自己了,直接從緩衝區拿。

5String 和StringBuffer的區別

JAVA平臺提供了兩個類:StringStringBuffer,它們可以儲存和操作字符串,即包含多個字符的字符數據。這個String類提供了數值不可改變的字符串。而這個StringBuffer類提供的字符串進行修改。當你知道字符數據要改變的時候你就可以使用StringBuffer。典型地,你可以使用StringBuffers來動態構造字符數據。另外,String實現了equals方法,new String(“abc”).equals(new String(“abc”)的結果爲true,StringBuffer沒有實現equals方法,所以,new StringBuffer(“abc”).equals(new StringBuffer(“abc”)的結果爲false

 

接着要舉一個具體的例子來說明,我們要把1100的所有數字拼起來,組成一個串。

StringBuffer sbf = new StringBuffer();  

for(int i=0;i<100;i++)

{

sbf.append(i);

}

上面的代碼效率很高,因爲只創建了一個StringBuffer對象,而下面的代碼效率很低,因爲創建了101個對象。

String str = new String();  

for(int i=0;i<100;i++)

{

str = str + i;

}

在講兩者區別時,應把循環的次數搞成10000,然後用endTime-beginTime來比較兩者執行的時間差異,最後還要講講StringBuilderStringBuffer的區別。

 

String覆蓋了equals方法和hashCode方法,而StringBuffer沒有覆蓋equals方法和hashCode方法,所以,將StringBuffer對象存儲進Java集合類中時會出現問題。

3如何把一段逗號分割的字符串轉換成一個數組?

如果不查jdk api,我很難寫出來!我可以說說我的思路:

1. 用正則表達式,代碼大概爲:String [] result = orgStr.split(“,”);

2. 用 StingTokenizer ,代碼爲:StringTokenizer  tokener = StringTokenizer(orgStr,”,”);

String [] result = new String[tokener .countTokens()];

Int i=0;

while(tokener.hasNext(){result[i++]=toker.nextToken();}

 

38、數組有沒有length()這個方法? String有沒有length()這個方法? 

數組沒有length()這個方法,有length的屬性。String有有length()這個方法。

39、下面這條語句一共創建了多少個對象:String s="a"+"b"+"c"+"d";

答:對於如下代碼:

String s1 = "a";

String s2 = s1 + "b";

String s3 = "a" + "b";

System.out.println(s2 == "ab");

System.out.println(s3 == "ab");

第一條語句打印的結果爲false,第二條語句打印的結果爲true,這說明javac編譯可以對字符串常量直接相加的表達式進行優化,不必要等到運行期去進行加法運算處理,而是在編譯時去掉其中的加號,直接將其編譯成一個這些常量相連的結果。

題目中的第一行代碼被編譯器在編譯時優化後,相當於直接定義了一個”abcd”的字符串,所以,上面的代碼應該只創建了一個String對象。寫如下兩行代碼,

String s = "a" + "b" + "c" + "d";

System.out.println(s == "abcd");

最終打印的結果應該爲true。 

 

 

43try {}裏有一個return語句,那麼緊跟在這個try後的finally {}裏的code會不會被執行,什麼時候被執行,在return前還是後

也許你的答案是在return之前,但往更細地說,我的答案是在return中間執行,請看下面程序代碼的運行結果: 

public  class Test {

 

/**

 * @param args add by zxx ,Dec 9, 2008

 */

public static void main(String[] args) {

// TODO Auto-generated method stub

System.out.println(new Test().test());;

}

 

static int test()

{

int x = 1;

try

{

return x;

}

finally

{

++x;

}

}

}

 

---------執行結果 ---------

1

 

運行結果是1,爲什麼呢?主函數調用子函數並得到結果的過程,好比主函數準備一個空罐子,當子函數要返回結果時,先把結果放在罐子裏,然後再將程序邏輯返回到主函數。所謂返回,就是子函數說,我不運行了,你主函數繼續運行吧,這沒什麼結果可言,結果是在說這話之前放進罐子裏的。

7、下面的程序代碼輸出的結果是多少?

public class  smallT

{

public static void  main(String args[])

{

smallT t  = new  smallT();

int  b  =  t.get();

System.out.println(b);

}

public int  get()

{

try

{

return 1 ;

}

finally

{

return 2 ;

}

}

}

 

返回的結果是2

我可以通過下面一個例子程序來幫助我解釋這個答案,從下面例子的運行結果中可以發現,try中的return語句調用的函數先於finally中調用的函數執行,也就是說return語句先執行,finally語句後執行,所以,返回的結果是2Return並不是讓函數馬上返回,而是return語句執行後,將把返回結果放置進函數棧中,此時函數並不是馬上返回,它要執行finally語句後才真正開始返回。

在講解答案時可以用下面的程序來幫助分析:

public  class Test {

 

/**

 * @param args add by zxx ,Dec 9, 2008

 */

public static void main(String[] args) {

// TODO Auto-generated method stub

System.out.println(new Test().test());;

}

 

int test()

{

try

{

return func1();

}

finally

{

return func2();

}

}

int func1()

{

System.out.println("func1");

return 1;

}

int func2()

{

System.out.println("func2");

return 2;

}

}

-----------執行結果-----------------

 

func1

func2

2

 

結論:finally中的代碼比return break語句後執行

 

12final, finally, finalize的區別。 

 final 用於聲明屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承。 

內部類要訪問局部變量,局部變量必須定義成final類型,例如,一段代碼……

 

finally是異常處理語句結構的一部分,表示總是執行。

 

 

finalizeObject類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法,可以覆蓋此方法提供垃圾收集時的其他資源回收,例如關閉文件等。JVM不保證此方法總被調用

 

5、運行時異常與一般異常有何異同? 

異常表示程序運行過程中可能出現的非正常狀態,運行時異常表示虛擬機的通常操作中可能遇到的異常,是一種常見運行錯誤。java編譯器要求方法必須聲明拋出可能發生的非運行時異常,但是並不要求必須聲明拋出未被捕獲的運行時異常。

15errorexception有什麼區別

error 表示恢復不是不可能但很困難的情況下的一種嚴重問題。比如說內存溢出。不可能指望程序能處理這樣的情況。 exception 表示一種設計或實現問題。也就是說,它表示如果程序運行正常,從不會發生的情況。 

 

50Java中的異常處理機制的簡單原理和應用。 

異常是指java程序運行時(非編譯)所發生的非正常情況或錯誤,與現實生活中的事件很相似,現實生活中的事件可以包含事件發生的時間、地點、人物、情節等信息,可以用一個對象來表示,Java使用面向對象的方式來處理異常,它把程序中發生的每個異常也都分別封裝到一個對象來表示的,該對象中包含有異常的信息。

Java對異常進行了分類,不同類型的異常分別用不同的Java類表示,所有異常的根類爲java.lang.ThrowableThrowable下面又派生了兩個子類:ErrorExceptionError 表示應用程序本身無法克服和恢復的一種嚴重問題,程序只有死的份了,例如,說內存溢出和線程死鎖等系統問題。Exception表示程序還能夠克服和恢復的問題,其中又分爲系統異常和普通異常,系統異常是軟件本身缺陷所導致的問題,也就是軟件開發人員考慮不周所導致的問題,軟件使用者無法克服和恢復這種問題,但在這種問題下還可以讓軟件系統繼續運行或者讓軟件死掉,例如,數組腳本越界(ArrayIndexOutOfBoundsException),空指針異常(NullPointerException)、類轉換異常(ClassCastException);普通異常是運行環境的變化或異常所導致的問題,是用戶能夠克服的問題,例如,網絡斷線,硬盤空間不夠,發生這樣的異常後,程序不應該死掉。

java爲系統異常和普通異常提供了不同的解決方案,編譯器強制普通異常必須try..catch處理或用throws聲明繼續拋給上層調用方法處理,所以普通異常也稱爲checked異常,而系統異常可以處理也可以不處理,所以,編譯器不強制用try..catch處理或用throws聲明,所以系統異常也稱爲unchecked異常。

 

提示答題者:就按照三個級別去思考:虛擬機必須宕機的錯誤,程序可以死掉也可以不死掉的錯誤,程序不應該死掉的錯誤;

 

 

33、請寫出你最常見到的5runtime exception。 

這道題主要考你的代碼量到底多大,如果你長期寫代碼的,應該經常都看到過一些系統方面的異常,你不一定真要回答出5個具體的系統異常,但你要能夠說出什麼是系統異常,以及幾個系統異常就可以了,當然,這些異常完全用其英文名稱來寫是最好的,如果實在寫不出,那就用中文吧,有總比沒有強! 

所謂系統異常,就是…..,它們都是RuntimeException的子類,在jdk doc中查RuntimeException類,就可以看到其所有的子類列表,也就是看到了所有的系統異常。我比較有印象的系統異常有:NullPointerExceptionArrayIndexOutOfBoundsExceptionClassCastException。

96JAVA語言如何進行異常處理,關鍵字:throws,throw,try,catch,finally分別代表什麼意義?在try塊中可以拋出異常嗎? 

 

99java中有幾種方法可以實現一個線程?用什麼關鍵字修飾同步方法? stop()suspend()方法爲何不推薦使用? 

 

java5以前,有如下兩種:

第一種:

new Thread(){}.start();這表示調用Thread子類對象的run方法,new Thread(){}表示一個Thread的匿名子類的實例對象,子類加上run方法後的代碼如下:

new Thread(){

public void run(){

}

}.start();

 

第二種:

new Thread(new Runnable(){}).start();這表示調用Thread對象接受的Runnable對象的run方法,new Runnable(){}表示一個Runnable的匿名子類的實例對象,runnable的子類加上run方法後的代碼如下:

new Thread(new Runnable(){

public void run(){

}

}

).start();

java5開始,還有如下一些線程池創建多線程的方式:

ExecutorService pool = Executors.newFixedThreadPool(3)

for(int i=0;i<10;i++)

{

 pool.execute(new Runable(){public void run(){}});

}

Executors.newCachedThreadPool().execute(new Runable(){public void run(){}});

Executors.newSingleThreadExecutor().execute(new Runable(){public void run(){}});

 

 

 

有兩種實現方法,分別使用new Thread()new Thread(runnable)形式,第一種直接調用threadrun方法,所以,我們往往使用Thread子類,即new SubThread()。第二種調用runnablerun方法。

 

有兩種實現方法,分別是繼承Thread類與實現Runnable接口 

synchronized關鍵字修飾同步方法 

反對使用stop(),是因爲它不安全。它會解除由線程獲取的所有鎖定,而且如果對象處於一種不連貫狀態,那麼其他線程能在那種狀態下檢查和修改它們。結果很難檢查出真正的問題所在。suspend()方法容易發生死鎖。調用suspend()的時候,目標線程會停下來,但卻仍然持有在這之前獲得的鎖定。此時,其他任何線程都不能訪問鎖定的資源,除非被"掛起"的線程恢復運行。對任何線程來說,如果它們想恢復目標線程,同時又試圖使用任何一個鎖定的資源,就會造成死鎖。所以不應該使用suspend(),而應在自己的Thread類中置入一個標誌,指出線程應該活動還是掛起。若標誌指出線程應該掛起,便用wait()命其進入等待狀態。若標誌指出線程應當恢復,則用一個notify()重新啓動線程。 

13sleep() 和 wait() 有什麼區別

     (網上的答案:sleep是線程類(Thread)的方法,導致此線程暫停執行指定時間,給執行機會給其他線程,但是監控狀態依然保持,到時後會自動恢復。調用sleep不會釋放對象鎖。 waitObject類的方法,對此對象調用wait方法導致本線程放棄對象鎖,進入等待此對象的等待鎖定池,只有針對此對象發出notify方法(或notifyAll)後本線程才進入對象鎖定池準備獲得對象鎖進入運行狀態。) 

 

sleep就是正在執行的線程主動讓出cpucpu去執行其他線程,在sleep指定的時間過後,cpu纔會回到這個線程上繼續往下執行,如果當前線程進入了同步鎖,sleep方法並不會釋放鎖,即使當前線程使用sleep方法讓出了cpu,但其他被同步鎖擋住了的線程也無法得到執行。wait是指在一個已經進入了同步鎖的線程內,讓自己暫時讓出同步鎖,以便其他正在等待此鎖的線程可以得到同步鎖並運行,只有其他線程調用了notify方法(notify並不釋放鎖,只是告訴調用過wait方法的線程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因爲鎖還在別人手裏,別人還沒釋放。如果notify方法後面的代碼還有很多,需要這些代碼執行完後纔會釋放鎖,可以在notfiy方法後增加一個等待和一些代碼,看看效果),調用wait方法的線程就會解除wait狀態和程序可以再次得到鎖後繼續向下運行。對於wait的講解一定要配合例子代碼來說明,才顯得自己真明白。

package com.huawei.interview;

 

public class MultiThread {

 

/**

 * @param args

 */

public static void main(String[] args) {

// TODO Auto-generated method stub

new Thread(new Thread1()).start();

try {

Thread.sleep(10);

catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

new Thread(new Thread2()).start();

}

private static class Thread1 implements Runnable

{

 

@Override

public void run() {

// TODO Auto-generated method stub

//由於這裏的Thread1和下面的Thread2內部run方法要用同一對象作爲監視器,我們這裏不能用this,因爲在Thread2裏面的this和這個Thread1this不是同一個對象。我們用MultiThread.class這個字節碼對象,當前虛擬機裏引用這個變量時,指向的都是同一個對象。

synchronized (MultiThread.class) {

 

System.out.println("enter thread1...");

System.out.println("thread1 is waiting");

try {

//釋放鎖有兩種方式,第一種方式是程序自然離開監視器的範圍,也就是離開了synchronized關鍵字管轄的代碼範圍,另一種方式就是在synchronized關鍵字管轄的代碼內部調用監視器對象的wait方法。這裏,使用wait方法釋放鎖。

MultiThread.class.wait();

catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println("thread1 is going on...");

System.out.println("thread1 is being over!");

}

}

}

private static class Thread2 implements Runnable

{

 

@Override

public void run() {

// TODO Auto-generated method stub

synchronized (MultiThread.class) {

System.out.println("enter thread2...");

System.out.println("thread2 notify other thread can release wait status..");

//由於notify方法並不釋放鎖, 即使thread2調用下面的sleep方法休息了10毫秒,但thread1仍然不會執行,因爲thread2沒有釋放鎖,所以Thread1無法得不到鎖。

 

MultiThread.class.notify();

System.out.println("thread2 is sleeping ten millisecond...");

try {

Thread.sleep(10);

catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println("thread2 is going on...");

System.out.println("thread2 is being over!");

}

}

}

 

}

 

 

16、同步和異步有何異同,在什麼情況下分別使用他們?舉例說明。 

如果數據將在線程間共享。例如正在寫的數據以後可能被另一個線程讀到,或者正在讀的數據可能已經被另一個線程寫過了,那麼這些數據就是共享數據,必須進行同步存取。 

當應用程序在對象上調用了一個需要花費很長時間來執行的方法,並且不希望讓程序等待方法的返回時,就應該使用異步編程,在很多情況下采用異步途徑往往更有效率。 

 

17. 下面兩個方法同步嗎?(自己發明)

class Test

{

synchronized static void sayHello3()

{

}

synchronized void getX(){}

}

56、多線程有幾種實現方法?同步有幾種實現方法

多線程有兩種實現方法,分別是繼承Thread類與實現Runnable接口 

同步的實現方面有兩種,分別是synchronized,waitnotify 

wait():使一個線程處於等待狀態,並且釋放所持有的對象的lock。 

sleep():使一個正在運行的線程處於睡眠狀態,是一個靜態方法,調用此方法要捕捉InterruptedException異常。 

notify():喚醒一個處於等待狀態的線程,注意的是在調用此方法的時候,並不能確切的喚醒某一個等待狀態的線程,而是由JVM確定喚醒哪個線程,而且不是按優先級。 

Allnotity():喚醒所有處入等待狀態的線程,注意並不是給所有喚醒線程一個對象的鎖,而是讓它們競爭。

 

 

30、啓動一個線程是用run()還是start()? . 

啓動一個線程是調用start()方法,使線程就緒狀態,以後可以被調度爲運行狀態,一個線程必須關聯一些具體的執行代碼,run()方法是該線程所關聯的執行代碼。 

 

47、當一個線程進入一個對象的一個synchronized方法後,其它線程是否可進入此對象的其它方法

分幾種情況:

     1.其他方法前是否加了synchronized關鍵字,如果沒加,則能。

     2.如果這個方法內部調用了wait,則可以進入其他synchronized方法。

     3.如果其他個方法都加了synchronized關鍵字,並且內部沒有調用wait,則不能。

4.如果其他方法是static,它用的同步鎖是當前類的字節碼,與非靜態的方法不能同步,因爲非靜態的方法用的是this

 

58、線程的基本概念、線程的基本狀態以及狀態之間的關係 

 

一個程序中可以有多條執行線索同時執行,一個線程就是程序中的一條執行線索,每個線程上都關聯有要執行的代碼,即可以有多段程序代碼同時運行,每個程序至少都有一個線程,即main方法執行的那個線程。如果只是一個cpu,它怎麼能夠同時執行多段程序呢?這是從宏觀上來看的,cpu一會執行a線索,一會執行b線索,切換時間很快,給人的感覺是a,b在同時執行,好比大家在同一個辦公室上網,只有一條鏈接到外部網線,其實,這條網線一會爲a傳數據,一會爲b傳數據,由於切換時間很短暫,所以,大家感覺都在同時上網。 

 

  狀態:就緒,運行,synchronize阻塞,waitsleep掛起,結束。wait必須在synchronized內部調用。

  調用線程的start方法後線程進入就緒狀態,線程調度系統將就緒狀態的線程轉爲運行狀態,遇到synchronized語句時,由運行狀態轉爲阻塞,當synchronized獲得鎖後,由阻塞轉爲運行,在這種情況可以調用wait方法轉爲掛起狀態,當線程關聯的代碼執行完後,線程變爲結束狀態。 

 

71、簡述synchronizedjava.util.concurrent.locks.Lock的異同 ? 

主要相同點:Lock能完成synchronized所實現的所有功能 

主要不同點:Lock有比synchronized更精確的線程語義和更好的性能。synchronized會自動釋放鎖,而Lock一定要求程序員手工釋放,並且必須在finally從句中釋放。Lock還有更強大的功能,例如,它的tryLock方法可以非阻塞方式去拿鎖。 

舉例說明(對下面的題用lock進行了改寫):

package com.huawei.interview;

 

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

 

public class ThreadTest {

 

/**

 * @param args

 */

private int j;

private Lock lock = new ReentrantLock();

public static void main(String[] args) {

// TODO Auto-generated method stub

ThreadTest tt = new ThreadTest();

for(int i=0;i<2;i++)

{

new Thread(tt.new Adder()).start();

new Thread(tt.new Subtractor()).start();

}

}

 

private class Subtractor implements Runnable

{

 

@Override

public void run() {

// TODO Auto-generated method stub

while(true)

{

/*synchronized (ThreadTest.this) {

System.out.println("j--=" + j--);

//這裏拋異常了,鎖能釋放嗎?

}*/

lock.lock();

try

{

System.out.println("j--=" + j--);

}finally

{

lock.unlock();

}

}

}

}

private class Adder implements Runnable

{

 

@Override

public void run() {

// TODO Auto-generated method stub

while(true)

{

/*synchronized (ThreadTest.this) {

System.out.println("j++=" + j++);

}*/

lock.lock();

try

{

System.out.println("j++=" + j++);

}finally

{

lock.unlock();

}

}

}

}

}

28、設計4個線程,其中兩個線程每次對j增加1,另外兩個線程對j每次減少1。寫出程序。 

以下程序使用內部類實現線程,對j增減的時候沒有考慮順序問題。 

public class ThreadTest1 

private int j; 

public static void main(String args[]){ 

   ThreadTest1 tt=new ThreadTest1(); 

   Inc inc=tt.new Inc(); 

   Dec dec=tt.new Dec(); 

   for(int i=0;i<2;i++){ 

       Thread t=new Thread(inc); 

       t.start(); 

   t=new Thread(dec); 

       t.start(); 

       } 

   } 

private synchronized void inc(){ 

   j++; 

   System.out.println(Thread.currentThread().getName()+"-inc:"+j); 

   } 

private synchronized void dec(){ 

   j--; 

   System.out.println(Thread.currentThread().getName()+"-dec:"+j); 

   } 

class Inc implements Runnable{ 

   public void run(){ 

       for(int i=0;i<100;i++){ 

       inc(); 

       } 

   } 

class Dec implements Runnable{ 

   public void run(){ 

       for(int i=0;i<100;i++){ 

       dec(); 

       } 

   } 

 

----------隨手再寫的一個-------------

class A

{

JManger j =new JManager();

main()

{

new A().call();

}

 

void call

{

for(int i=0;i<2;i++)

{

new Thread(

new Runnable(){ public void run(){while(true){j.accumulate()}}}

).start();

new Thread(new Runnable(){ public void run(){while(true){j.sub()}}}).start();

}

}

}

 

class JManager

{

private j = 0;

public synchronized void subtract()

{

j--

}

public synchronized void accumulate()

{

j++;

}

}

 

28、子線程循環10次,接着主線程循環100,接着又回到子線程循環10次,接着再回到主線程又循環100,如此循環50次,請寫出程序。 

 

最終的程序代碼如下:

public class ThreadTest {

 

/**

 * @param args

 */

public static void main(String[] args) {

// TODO Auto-generated method stub

new ThreadTest().init();

 

}

 

public void init()

{

final Business business = new Business();

new Thread(

new Runnable()

{

 

public void run() {

for(int i=0;i<50;i++)

{

business.SubThread(i);

}

}

}

).start();

for(int i=0;i<50;i++)

{

business.MainThread(i);

}

}

private class Business

{

boolean bShouldSub = true;//這裏相當於定義了控制該誰執行的一個信號燈

public synchronized void MainThread(int i)

{

if(bShouldSub)

try {

this.wait();

catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

for(int j=0;j<5;j++)

{

System.out.println(Thread.currentThread().getName() + ":i=" + i +",j=" + j);

}

bShouldSub = true;

this.notify();

}

public synchronized void SubThread(int i)

{

if(!bShouldSub)

try {

this.wait();

catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

for(int j=0;j<10;j++)

{

System.out.println(Thread.currentThread().getName() + ":i=" + i +",j=" + j);

}

bShouldSub = false;

this.notify();

}

}

}

 

備註:不可能一上來就寫出上面的完整代碼,最初寫出來的代碼如下,問題在於兩個線程的代碼要參照同一個變量,即這兩個線程的代碼要共享數據,所以,把這兩個線程的執行代碼搬到同一個類中去:

 

package com.huawei.interview.lym;

 

public class ThreadTest {

private static boolean bShouldMain = false;

public static void main(String[] args) {

// TODO Auto-generated method stub

/*new Thread(){

public void run()

{

for(int i=0;i<50;i++)

{

for(int j=0;j<10;j++)

{

System.out.println("i=" + i + ",j=" + j);

}

}

}

}.start();*/

//final String str = new String("");

 

new Thread(

new Runnable()

{

public void run()

{

for(int i=0;i<50;i++)

{

synchronized (ThreadTest.class) {

if(bShouldMain)

{

try {

ThreadTest.class.wait();} 

catch (InterruptedException e) {

e.printStackTrace();

}

}

for(int j=0;j<10;j++)

{

System.out.println(

Thread.currentThread().getName() + 

"i=" + i + ",j=" + j);

}

bShouldMain = true;

ThreadTest.class.notify();

}

}

}

}

).start();

for(int i=0;i<50;i++)

{

synchronized (ThreadTest.class) {

if(!bShouldMain)

{

try {

ThreadTest.class.wait();} 

catch (InterruptedException e) {

e.printStackTrace();

}

}

for(int j=0;j<5;j++)

{

System.out.println(

Thread.currentThread().getName() + 

"i=" + i + ",j=" + j);

}

bShouldMain = false;

ThreadTest.class.notify();

}

}

}

 

}

下面使用jdk5中的併發庫來實現的:

import java.util.concurrent.Executors;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

import java.util.concurrent.locks.Condition;

 

public class ThreadTest

{

private static Lock lock = new ReentrantLock();

private static Condition subThreadCondition = lock.newCondition();

private static boolean bBhouldSubThread = false;

public static void main(String [] args)

{

ExecutorService threadPool = Executors.newFixedThreadPool(3);

threadPool.execute(new Runnable(){

public void run()

{

for(int i=0;i<50;i++)

{

lock.lock();

try

{

if(!bBhouldSubThread)

subThreadCondition.await();

for(int j=0;j<10;j++)

{

System.out.println(Thread.currentThread().getName() + ",j=" + j);

}

bBhouldSubThread = false;

subThreadCondition.signal();

}catch(Exception e)

{

}

finally

{

lock.unlock();

}

}

}

});

threadPool.shutdown();

for(int i=0;i<50;i++)

{

lock.lock();

try

{

if(bBhouldSubThread)

subThreadCondition.await();

for(int j=0;j<10;j++)

{

System.out.println(Thread.currentThread().getName() + ",j=" + j);

}

bBhouldSubThread = true;

subThreadCondition.signal();

}catch(Exception e)

{

}

finally

{

lock.unlock();

}

}

}

}

 

 

3、介紹Collection框架的結構

答:隨意發揮題,天南海北誰便談,只要讓別覺得你知識淵博,理解透徹即可。

 

3Collection框架中實現比較要實現什麼接口

comparable/comparator

3ArrayListVector的區別

答:

這兩個類都實現了List接口(List接口繼承了Collection接口),他們都是有序集合,即存儲在這兩個集合中的元素的位置都是有順序的,相當於一種動態的數組,我們以後可以按位置索引號取出某個元素,,並且其中的數據是允許重複的,這是HashSet之類的集合的最大不同處,HashSet之類的集合不可以按索引號去檢索其中的元素,也不允許有重複的元素(本來題目問的與hashset沒有任何關係,但爲了說清楚ArrayListVector的功能,我們使用對比方式,更有利於說明問題)。

 

接着才說ArrayListVector的區別,這主要包括兩個方面:. 
1同步性:

Vector是線程安全的,也就是說是它的方法之間是線程同步的,而ArrayList是線程序不安全的,它的方法之間是線程不同步的。如果只有一個線程會訪問到集合,那最好是使用ArrayList,因爲它不考慮線程安全,效率會高些;如果有多個線程會訪問到集合,那最好是使用Vector,因爲不需要我們自己再去考慮和編寫線程安全的代碼。

 

備註:對於Vector&ArrayListHashtable&HashMap,要記住線程安全的問題,記住VectorHashtable是舊的,是java一誕生就提供了的,它們是線程安全的,ArrayListHashMapjava2時才提供的,它們是線程不安全的。所以,我們講課時先講老的。
2數據增長:

ArrayListVector都有一個初始的容量大小,當存儲進它們裏面的元素的個數超過了容量時,就需要增加ArrayListVector的存儲空間,每次要增加存儲空間時,不是隻增加一個存儲單元,而是增加多個存儲單元,每次增加的存儲單元的個數在內存空間利用與程序效率之間要取得一定的平衡。Vector默認增長爲原來兩倍,而ArrayList增長策略在文檔中沒有明確規定(從源代碼看到的是增長爲原來的1.5倍)。ArrayListVector都可以設置初始的空間大小,Vector還可以設置增長的空間大小,而ArrayList沒有提供設置增長空間的方法。

    總結:即Vector增長原來的一倍,ArrayList增加原來的0.5倍。

4HashMapHashtable的區別

(條理上還需要整理,也是先說相同點,再說不同點)

HashMapHashtable的輕量級實現(非線程安全的實現),他們都完成了Map接口,主要區別在於HashMap允許空(null)鍵值(key,由於非線程安全,在只有一個線程訪問的情況下,效率要高於Hashtable。 

HashMap允許將null作爲一個entrykey或者value,而Hashtable不允許。 

HashMapHashtablecontains方法去掉了,改成containsvaluecontainsKey。因爲contains方法容易讓人引起誤解。 

Hashtable繼承自Dictionary類,而HashMapJava1.2引進的Map interface的一個實現。 

最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多個線程訪問Hashtable時,不需要自己爲它的方法實現同步,而HashMap 就必須爲之提供外同步。 

HashtableHashMap採用的hash/rehash算法都大概一樣,所以性能不會有很大的差異。

 

HashMapHashTable主要從三方面來說。 
.歷史原因:Hashtable是基於陳舊的Dictionary類的,HashMapJava 1.2引進的Map接口的一個實現 
.同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的 
.值:只有HashMap可以讓你將空值作爲一個表的條目的keyvalue 

5List 和 Map 區別?

一個是存儲單列數據的集合,另一個是存儲鍵和值這樣的雙列數據的集合,List中存儲的數據是有順序,並且允許重複;Map中存儲的數據是沒有順序的,其鍵是不能重複的,它的值是可以有重複的。

35List, Set, Map是否繼承自Collection接口

   ListSet是,Map不是 

 

109ListMapSet三個接口,存取元素時,各有什麼特點? 

這樣的題屬於隨意發揮題:這樣的題比較考水平,兩個方面的水平:一是要真正明白這些內容,二是要有較強的總結和表述能力。如果你明白,但表述不清楚,在別人那裏則等同於不明白。

 

首先,ListSet具有相似性,它們都是單列元素的集合,所以,它們有一個功共同的父接口,叫CollectionSet裏面不允許有重複的元素,所謂重複,即不能有兩個相等(注意,不是僅僅是相同)的對象 ,即假設Set集合中有了一個A對象,現在我要向Set集合再存入一個B對象,但B對象與A對象equals相等,則B對象存儲不進去,所以,Set集合的add方法有一個boolean的返回值,當集合中沒有某個元素,此時add方法可成功加入該元素時,則返回true,當集合含有與某個元素equals相等的元素時,此時add方法無法加入該元素,返回結果爲falseSet取元素時,沒法說取第幾個,只能以Iterator接口取得所有的元素,再逐一遍歷各個元素。

List表示有先後順序的集合, 注意,不是那種按年齡、按大小、按價格之類的排序。當我們多次調用add(Obj e)方法時,每次加入的對象就像火車站買票有排隊順序一樣,按先來後到的順序排序。有時候,也可以插隊,即調用add(int index,Obj e)方法,就可以指定當前對象在集合中的存放位置。一個對象可以被反覆存儲進List中,每調用一次add方法,這個對象就被插入進集合中一次,其實,並不是把這個對象本身存儲進了集合中,而是在集合中用一個索引變量指向這個對象,當這個對象被add多次時,即相當於集合中有多個索引指向了這個對象,如圖x所示。List除了可以以Iterator接口取得所有的元素,再逐一遍歷各個元素之外,還可以調用get(index i)來明確說明取第幾個。

MapListSet不同,它是雙列的集合,其中有put方法,定義如下:put(obj key,obj value),每次存儲時,要存儲一對key/value,不能存儲重複的key,這個重複的規則也是按equals比較相等。取則可以根據key獲得相應的value,即get(Object key)返回值爲key 所對應的value。另外,也可以獲得所有的key的結合,還可以獲得所有的value的結合,還可以獲得keyvalue組合成的Map.Entry對象的集合。

 

List 以特定次序來持有元素,可有重複元素。Set 無法擁有重複元素,內部排序。Map 保存key-value值,value可多值。

 

 

HashSet按照hashcode值的某種運算方式進行存儲,而不是直接按hashCode值的大小進行存儲。例如,"abc" ---> 78"def" ---> 62"xyz" ---> 65hashSet中的存儲順序不是62,65,78,這些問題感謝以前一個叫崔健的學員提出,最後通過查看源代碼給他解釋清楚,看本次培訓學員當中有多少能看懂源碼。LinkedHashSet按插入的順序存儲,那被存儲對象的hashcode方法還有什麼作用呢?學員想想!hashset集合比較兩個對象是否相等,首先看hashcode方法是否相等,然後看equals方法是否相等。new 兩個Student插入到HashSet中,看HashSetsize,實現hashcodeequals方法後再看size

 

同一個對象可以在Vector中加入多次。往集合裏面加元素,相當於集合裏用一根繩子連接到了目標對象。往HashSet中卻加不了多次的。 

 

7、說出ArrayList,Vector, LinkedList的存儲性能和特性 

ArrayListVector都是使用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及數組元素移動等內存操作,所以索引數據快而插入數據慢,Vector由於使用了synchronized方法(線程安全),通常性能上較ArrayList差,而LinkedList使用雙向鏈表實現存儲,按序號索引數據需要進行前向或後向遍歷,但是插入數據時只需要記錄本項的前後項即可,所以插入速度較快。

 

LinkedList也是線程不安全的,LinkedList提供了一些方法,使得LinkedList可以被當作堆棧和隊列來使用。

4、去掉一個Vector集合中重複的元素 

Vector newVector = new Vector();

For (int i=0;i<vector.size();i++)

{

Object obj = vector.get(i);

if(!newVector.contains(obj);

newVector.add(obj);

}

還有一種簡單的方式,HashSet set = new HashSet(vector); 

9Collection 和 Collections的區別。 

  Collection是集合類的上級接口,繼承與他的接口主要有Set List. 

Collections是針對集合類的一個幫助類,他提供一系列靜態方法實現對各種集合的搜索、排序、線程安全化等操作。 

39Set裏的元素是不能重複的,那麼用什麼方法來區分重複與否呢是用==還是equals()? 它們有何區別

Set裏的元素是不能重複的,元素重複與否是使用equals()方法進行判斷的。 

   equals()==方法決定引用值是否指向同一對象equals()在類中被覆蓋,爲的是當兩個分離的對象的內容和類型相配的話,返回真值。

 

53、你所知道的集合類都有哪些?主要方法? 

最常用的集合類是 List 和 Map。 List 的具體實現包括 ArrayList 和 Vector,它們是可變大小的列表,比較適合構建、存儲和操作任何類型對象的元素列表。 List 適用於按數值索引訪問元素的情形。 

Map 提供了一個更通用的元素存儲方法。 Map 集合類用於存儲元素對(稱作""""),其中每個鍵映射到一個值。 

 

ArrayList/VectoràList

                    àCollection

HashSet/TreeSetàSet

 

PropetiesàHashTable

àMap

Treemap/HashMap

 

我記的不是方法名,而是思想,我知道它們都有增刪改查的方法,但這些方法的具體名稱,我記得不是很清楚,對於set,大概的方法是add,remove, contains;對於map,大概的方法就是put,removecontains等,因爲,我只要在eclispe下按點操作符,很自然的這些方法就出來了。我記住的一些思想就是List類會有get(int index)這樣的方法,因爲它可以按順序取元素,而set類中沒有get(int index)這樣的方法。Listset都可以迭代出所有元素,迭代時先要得到一個iterator對象,所以,setlist類都有一個iterator方法,用於返回那個iterator對象。map可以返回三個集合,一個是返回所有的key的集合,另外一個返回的是所有value的集合,再一個返回的keyvalue組合成的EntrySet對象的集合,map也有get方法,參數是key,返回值是key對應的value。 

 

45、兩個對象值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對不對

對。

如果對象要保存在HashSetHashMap中,它們的equals相等,那麼,它們的hashcode值就必須相等。

如果不是要保存在HashSetHashMap,則與hashcode沒有什麼關係了,這時候hashcode不等是可以的,例如arrayList存儲的對象就不用實現hashcode,當然,我們沒有理由不實現,通常都會去實現的。

46TreeSet裏面放對象,如果同時放入了父類和子類的實例對象,那比較時使用的是父類的compareTo方法,還是使用的子類的compareTo方法,還是拋異常! 

(應該是沒有針對問題的確切的答案,當前的add方法放入的是哪個對象,就調用哪個對象的compareTo方法,至於這個compareTo方法怎麼做,就看當前這個對象的類中是如何編寫這個方法的)

實驗代碼:

public class Parent implements Comparable {

private int age = 0;

public Parent(int age){

this.age = age;

}

public int compareTo(Object o) {

// TODO Auto-generated method stub

System.out.println("method of parent");

Parent o1 = (Parent)o;

return age>o1.age?1:age<o1.age?-1:0;

}

 

}

 

public class Child extends Parent {

 

public Child(){

super(3);

}

public int compareTo(Object o) {

 

// TODO Auto-generated method stub

System.out.println("method of child");

//Child o1 = (Child)o;

return 1;

 

}

}

 

public class TreeSetTest {

 

/**

 * @param args

 */

public static void main(String[] args) {

// TODO Auto-generated method stub

TreeSet set = new TreeSet();

set.add(new Parent(3));

set.add(new Child());

set.add(new Parent(4));

System.out.println(set.size());

}

 

}

 

 

112、說出一些常用的類,包,接口,請各舉5個 

要讓人家感覺你對java ee開發很熟,所以,不能僅僅只列core java中的那些東西,要多列你在做ssh項目中涉及的那些東西。就寫你最近寫的那些程序中涉及的那些類。

 

常用的類:BufferedReader  BufferedWriter  FileReader  FileWirter  String  Integer 

java.util.DateSystemClassList,HashMap

 

常用的包:java.lang   java.io  java.util  java.sql ,javax.servlet,org.apache.strtuts.action,org.hibernate

常用的接口:Remote  List  Map  Document  NodeList ,Servlet,HttpServletRequest,HttpServletResponse,Transaction(Hibernate)Session(Hibernate),HttpSession

100java中有幾種類型的流?JDK爲每種類型的流提供了一些抽象類以供繼承,請說出他們分別是哪些類? 

字節流,字符流。字節流繼承於InputStream OutputStream,字符流繼承於InputStreamReader OutputStreamWriter。在java.io包中還有許多其他的流,主要是爲了提高性能和使用方便。 

102、字節流與字符流的區別

要把一片二進制數據數據逐一輸出到某個設備中,或者從某個設備中逐一讀取一片二進制數據,不管輸入輸出設備是什麼,我們要用統一的方式來完成這些操作,用一種抽象的方式進行描述,這個抽象描述方式起名爲IO流,對應的抽象類爲OutputStreamInputStream ,不同的實現類就代表不同的輸入和輸出設備,它們都是針對字節進行操作的。

在應用中,經常要完全是字符的一段文本輸出去或讀進來,用字節流可以嗎?計算機中的一切最終都是二進制的字節形式存在。對於“中國”這些字符,首先要得到其對應的字節,然後將字節寫入到輸出流。讀取時,首先讀到的是字節,可是我們要把它顯示爲字符,我們需要將字節轉換成字符。由於這樣的需求很廣泛,人家專門提供了字符流的包裝類。

  底層設備永遠只接受字節數據,有時候要寫字符串到底層設備,需要將字符串轉成字節再進行寫入。字符流是字節流的包裝,字符流則是直接接受字符串,它內部將串轉成字節,再寫入底層設備,這爲我們向IO設別寫入或讀取字符串提供了一點點方便。

  字符向字節轉換時,要注意編碼的問題,因爲字符串轉成字節數組,

  其實是轉成該字符的某種編碼的字節形式,讀取也是反之的道理。

 

講解字節流與字符流關係的代碼案例:

import java.io.BufferedReader;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.InputStreamReader;

import java.io.PrintWriter;

 

public class IOTest {

public static void main(String[] args) throws Exception {

String str = "中國人";

/*FileOutputStream fos  = new FileOutputStream("1.txt");

fos.write(str.getBytes("UTF-8"));

fos.close();*/

/*FileWriter fw = new FileWriter("1.txt");

fw.write(str);

fw.close();*/

PrintWriter pw = new PrintWriter("1.txt","utf-8");

pw.write(str);

pw.close();

/*FileReader fr = new FileReader("1.txt");

char[] buf = new char[1024];

int len = fr.read(buf);

String myStr = new String(buf,0,len);

System.out.println(myStr);*/

/*FileInputStream fr = new FileInputStream("1.txt");

byte[] buf = new byte[1024];

int len = fr.read(buf);

String myStr = new String(buf,0,len,"UTF-8");

System.out.println(myStr);*/

BufferedReader br = new BufferedReader(

new InputStreamReader(

new FileInputStream("1.txt"),"UTF-8"

)

);

String myStr = br.readLine();

br.close();

System.out.println(myStr);

}

 

}

105、什麼是java序列化,如何實現java序列化?或者請解釋Serializable接口的作用。 

 

我們有時候將一個java對象變成字節流的形式傳出去或者從一個字節流中恢復成一個java對象,例如,要將java對象存儲到硬盤或者傳送給網絡上的其他計算機,這個過程我們可以自己寫代碼去把一個java對象變成某個格式的字節流再傳輸,但是,jre本身就提供了這種支持,我們可以調用OutputStream的writeObject方法來做,如果要讓java 幫我們做,要被傳輸的對象必須實現serializable接口,這樣,javac編譯時就會進行特殊處理,編譯的類纔可以被writeObject方法操作,這就是所謂的序列化。需要被序列化的類必須實現Serializable接口,該接口是一個mini接口,其中沒有需要實現的方法,implements Serializable只是爲了標註該對象是可被序列化的。 

 

 

例如,在web開發中,如果對象被保存在了Session中,tomcat在重啓時要把Session對象序列化到硬盤,這個對象就必須實現Serializable接口。如果對象要經過分佈式系統進行網絡傳輸或通過rmi等遠程調用,這就需要在網絡上傳輸對象,被傳輸的對象就必須實現Serializable接口。

 

54、描述一下JVM加載class文件的原理機制

JVM中類的裝載是由ClassLoader和它的子類來實現的,Java ClassLoader 是一個重要的Java運行時系統組件。它負責在運行時查找和裝入類文件的類。 

 

18heapstack有什麼區別。 

java的內存分爲兩類,一類是棧內存,一類是堆內存。棧內存是指程序進入一個方法時,會爲這個方法單獨分配一塊私屬存儲空間,用於存儲這個方法內部的局部變量,當這個方法結束時,分配給這個方法的棧會釋放,這個棧中的變量也將隨之釋放。

堆是與棧作用不同的內存,一般用於存放不放在當前方法棧中的那些數據,例如,使用new創建的對象都放在堆裏,所以,它不會隨方法的結束而消失。方法中的局部變量使用final修飾後,放在堆中,而不是棧中。 

 

24GC是什麼爲什麼要有GC?    

GC是垃圾收集的意思(Gabage Collection,內存處理是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會導致程序或系統的不穩定甚至崩潰,Java提供的GC功能可以自動監測對象是否超過作用域從而達到自動回收內存的目的,Java語言沒有提供釋放已分配內存的顯示操作方法。

 

51、垃圾回收的優點和原理。並考慮2種回收機制。 

Java語言中一個顯著的特點就是引入了垃圾回收機制,使c++程序員最頭疼的內存管理的問題迎刃而解,它使得Java程序員在編寫程序的時候不再需要考慮內存管理。由於有個垃圾回收機制,Java中的對象不再有"作用域"的概念,只有對象的引用纔有"作用域"。垃圾回收可以有效的防止內存泄露,有效的使用可以使用的內存。垃圾回收器通常是作爲一個單獨的低級別的線程運行,不可預知的情況下對內存堆中已經死亡的或者長時間沒有使用的對象進行清楚和回收,程序員不能實時的調用垃圾回收器對某個對象或所有對象進行垃圾回收。回收機制有分代複製垃圾回收和標記垃圾回收,增量垃圾回收。

 

103、垃圾回收器的基本原理是什麼?垃圾回收器可以馬上回收內存嗎?有什麼辦法主動通知虛擬機進行垃圾回收? 

對於GC來說,當程序員創建對象時,GC就開始監控這個對象的地址、大小以及使用情況。通常,GC採用有向圖的方式記錄和管理堆(heap)中的所有對象。通過這種方式確定哪些對象是"可達的",哪些對象是"不可達的"。當GC確定一些對象爲"不可達"時,GC就有責任回收這些內存空間。可以。程序員可以手動執行System.gc(),通知GC運行,但是Java語言規範並不保證GC一定會執行。 

 

 

23、什麼時候用assert。 

assertion(斷言)在軟件開發中是一種常用的調試方式,很多開發語言中都支持這種機制。在實現中,assertion就是在程序中的一條語句,它對一個boolean表達式進行檢查,一個正確程序必須保證這個boolean表達式的值爲true;如果該值爲false,說明程序已經處於不正確的狀態下,assert將給出警告或退出。一般來說,assertion用於保證程序最基本、關鍵的正確性。assertion檢查通常在開發和測試時開啓。爲了提高性能,在軟件發佈後,assertion檢查通常是關閉的。 

package com.huawei.interview;

 

public class AssertTest {

 

/**

 * @param args

 */

public static void main(String[] args) {

// TODO Auto-generated method stub

int i = 0;

for(i=0;i<5;i++)

{

System.out.println(i);

}

//假設程序不小心多了一句--i;

--i;

assert i==5;

}

 

}

 

101java中會存在內存泄漏嗎,請簡單描述。 

所謂內存泄露就是指一個不再被程序使用的對象或變量一直被佔據在內存中。java中有垃圾回收機制,它可以保證一對象不再被引用的時候,即對象編程了孤兒的時候,對象將自動被垃圾回收器從內存中清除掉。由於Java 使用有向圖的方式進行垃圾回收管理,可以消除引用循環的問題,例如有兩個對象,相互引用,只要它們和根進程不可達的,那麼GC也是可以回收它們的,例如下面的代碼可以看到這種情況的內存回收:

package com.huawei.interview;

 

import java.io.IOException;

 

public class GarbageTest {

 

/**

 * @param args

 * @throws IOException 

 */

public static void main(String[] args) throws IOException {

// TODO Auto-generated method stub

try {

gcTest();

catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println("has exited gcTest!");

System.in.read();

System.in.read();

System.out.println("out begin gc!");

for(int i=0;i<100;i++)

{

System.gc();

System.in.read();

System.in.read();

}

}

 

private static void gcTest() throws IOException {

System.in.read();

System.in.read();

Person p1 = new Person();

System.in.read();

System.in.read();

Person p2 = new Person();

p1.setMate(p2);

p2.setMate(p1);

System.out.println("before exit gctest!");

System.in.read();

System.in.read();

System.gc();

System.out.println("exit gctest!");

}

 

private static class Person

{

byte[] data = new byte[20000000];

Person mate = null;

public void setMate(Person other)

{

mate = other;

}

}

}

 

java中的內存泄露的情況:長生命週期的對象持有短生命週期對象的引用就很可能發生內存泄露,儘管短生命週期對象已經不再需要,但是因爲長生命週期對象持有它的引用而導致不能被回收,這就是java中內存泄露的發生場景,通俗地說,就是程序員可能創建了一個對象,以後一直不再使用這個對象,這個對象卻一直被引用,即這個對象無用但是卻無法被垃圾回收器回收的,這就是java中可能出現內存泄露的情況,例如,緩存系統,我們加載了一個對象放在緩存中(例如放在一個全局map對象中),然後一直不再使用它,這個對象一直被緩存引用,但卻不再被使用。

檢查java中的內存泄露,一定要讓程序將各種分支情況都完整執行到程序結束,然後看某個對象是否被使用過,如果沒有,則才能判定這個對象屬於內存泄露。

 

如果一個外部類的實例對象的方法返回了一個內部類的實例對象,這個內部類對象被長期引用了,即使那個外部類實例對象不再被使用,但由於內部類持久外部類的實例對象,這個外部類對象將不會被垃圾回收,這也會造成內存泄露。

 

下面內容來自於網上(主要特點就是清空堆棧中的某個元素,並不是徹底把它從數組中拿掉,而是把存儲的總數減少,本人寫得可以比這個好,在拿掉某個元素時,順便也讓它從數組中消失,將那個元素所在的位置的值設置爲null即可):

我實在想不到比那個堆棧更經典的例子了,以致於我還要引用別人的例子,下面的例子不是我想到的,是書上看到的,當然如果沒有在書上看到,可能過一段時間我自己也想的到,可是那時我說是我自己想到的也沒有人相信的。

    public class Stack {
    private Object[] elements=new Object[10];
    private int size = 0;
    public void push(Object e){
    ensureCapacity();
    elements[size++] = e;
    }
    public Object pop(){
    if( size == 0)

    throw new EmptyStackException();
    return elements[--size];
    }
    private void ensureCapacity(){
    if(elements.length == size){
    Object[] oldElements = elements;
    elements = new Object[2 * elements.length+1];
    System.arraycopy(oldElements,0, elements, 0, size);
    }
    }
    }
    上面的原理應該很簡單,假如堆棧加了10個元素,然後全部彈出來,雖然堆棧是空的,沒有我們要的東西,但是這是個對象是無法回收的,這個才符合了內存泄露的兩個條件:無用,無法回收。

    但是就是存在這樣的東西也不一定會導致什麼樣的後果,如果這個堆棧用的比較少,也就浪費了幾個K內存而已,反正我們的內存都上G了,哪裏會有什麼影響,再說這個東西很快就會被回收的,有什麼關係。下面看兩個例子。

    例子1
    public class Bad{
    public static Stack s=Stack();
    static{
    s.push(new Object());
    s.pop(); //這裏有一個對象發生內存泄露
    s.push(new Object()); //上面的對象可以被回收了,等於是自愈了
    }
    }
    因爲是static,就一直存在到程序退出,但是我們也可以看到它有自愈功能,就是說如果你的Stack最多有100個對象,那麼最多也就只有100個對象無法被回收其實這個應該很容易理解,Stack內部持有100個引用,最壞的情況就是他們都是無用的,因爲我們一旦放新的進取,以前的引用自然消失!

 

內存泄露的另外一種情況:當一個對象被存儲進HashSet集合中以後,就不能修改這個對象中的那些參與計算哈希值的字段了,否則,對象修改後的哈希值與最初存儲進HashSet集合中時的哈希值就不同了,在這種情況下,即使在contains方法使用該對象的當前引用作爲的參數去HashSet集合中檢索對象,也將返回找不到對象的結果,這也會導致無法從HashSet集合中單獨刪除當前對象,造成內存泄露。

 

 

 

8、能不能自己寫個類,也叫java.lang.String

 

可以,但在應用的時候,需要用自己的類加載器去加載,否則,系統的類加載器永遠只是去加載jre.jar包中的那個java.lang.String。由於在tomcatweb應用程序中,都是由webapp自己的類加載器先自己加載WEB-INF/classess目錄中的類,然後才委託上級的類加載器加載,如果我們在tomcatweb應用程序中寫一個java.lang.String,這時候Servlet程序加載的就是我們自己寫的java.lang.String,但是這麼幹就會出很多潛在的問題,原來所有用了java.lang.String類的都將出現問題。

 

雖然java提供了endorsed技術,可以覆蓋jdk中的某些類,具體做法是….。但是,能夠被覆蓋的類是有限制範圍,反正不包括java.lang這樣的包中的類。

 

(下面的例如主要是便於大家學習理解只用,不要作爲答案的一部分,否則,人家懷疑是題目泄露了)例如,運行下面的程序:

package java.lang;

 

public class String {

 

/**

 * @param args

 */

public static void main(String[] args) {

// TODO Auto-generated method stub

System.out.println("string");

}

 

}

報告的錯誤如下:

java.lang.NoSuchMethodError: main

Exception in thread "main"

這是因爲加載了jre自帶的java.lang.String,而該類中沒有main方法。

 

2. Java代碼查錯

1.
abstract class Name {
   private String name;
   public abstract boolean isStupidName(String name) {}
}
大俠們,這有何錯誤?
答案錯。abstract method必須以分號結尾,且不帶花括號。
2.
public class Something {
   void doSomething () {
       private String s = "";
       int l = s.length();
   }
}
有錯嗎?
答案錯。局部變量前不能放置任何訪問修飾符 (privatepublic,和protected)final可以用來修飾局部變量
(final如同abstractstrictfp,都是非訪問修飾符,strictfp只能修飾classmethod而非variable)
3.
abstract class Something {
   private abstract String doSomething ();
}
這好像沒什麼錯吧?
答案錯。abstractmethods不能以private修飾。abstractmethods就是讓子類implement(實現)具體細節的,怎麼可以用privateabstract
method封鎖起來呢? (同理,abstract method前不能加final)
4.
public class Something {
   public int addOne(final int x) {
       return ++x;
   }
}
這個比較明顯。
答案錯。int x被修飾成final,意味着x不能在addOne method中被修改。
5.
public class Something {
   public static void main(String[] args) {
       Other o = new Other();
       new Something().addOne(o);
   }
   public void addOne(final Other o) {
       o.i++;
   }
}
class Other {
   public int i;
}
和上面的很相似,都是關於final的問題,這有錯嗎?
答案正確。在addOne method中,參數o被修飾成final。如果在addOne method裏我們修改了oreference
(比如: o = new Other();),那麼如同上例這題也是錯的。但這裏修改的是omember vairable
(成員變量),而oreference並沒有改變。
6.
class Something {
    int i;
    public void doSomething() {
        System.out.println("i = " + i);
    }

有什麼錯呢看不出來啊。
答案正確。輸出的是"i = 0"int i屬於instant variable (實例變量,或叫成員變量)instant variabledefault valueintdefault value0
7.
class Something {
    final int i;
    public void doSomething() {
        System.out.println("i = " + i);
    }
}
和上面一題只有一個地方不同,就是多了一個final。這難道就錯了嗎?
答案錯。final int i是個finalinstant variable (實例變量,或叫成員變量)finalinstant variable沒有default value,必須在constructor (構造器)結束之前被賦予一個明確的值。可以修改爲"final int i = 0;"
8.
public class Something {
     public static void main(String[] args) {
        Something s = new Something();
        System.out.println("s.doSomething() returns " + doSomething());
    }
    public String doSomething() {
        return "Do something ...";
    }
}
 看上去很完美。
答案錯。看上去在maincall doSomething沒有什麼問題,畢竟兩個methods都在同一個class裏。但仔細看,mainstatic的。static method不能直接call non-static methods。可改成"System.out.println("s.doSomething() returns " + s.doSomething());"。同理,static method不能訪問non-static instant variable
9.
此處,Something類的文件名叫OtherThing.java
class Something {
    private static void main(String[] something_to_do) {        
        System.out.println("Do something ...");
    }
}
 這個好像很明顯。
答案正確。從來沒有人說過JavaClass名字必須和其文件名相同。但public class的名字必須和文件名相同。
10
interface  A{
   int x = 0;
}
class B{
   int x =1;
}
class C extends B implements A {
   public void pX(){
      System.out.println(x);
   }
   public static void main(String[] args) {
      new C().pX();
   }
}
答案:錯誤。在編譯時會發生錯誤(錯誤描述不同的JVM有不同的信息,意思就是未明確的x調用,兩個x都匹配(就象在同時import java.utiljava.sql兩個包時直接聲明Date一樣)。對於父類的變量,可以用super.x來明確,而接口的屬性默認隱含爲 public static final.所以可以通過A.x來明確。
11.
interface Playable {
    void play();
}
interface Bounceable {
    void play();
}
interface Rollable extends Playable, Bounceable {
    Ball ball = new Ball("PingPang");
}
class Ball implements Rollable {
    private String name;
    public String getName() {
        return name;
    }
    public Ball(String name) {
        this.name = name;        
    }
   public void play() {
        ball = new Ball("Football");
        System.out.println(ball.getName());
    }
}
這個錯誤不容易發現。
答案錯。"interface Rollable extends Playable, Bounceable"沒有問題。interface可繼承多個interfaces,所以這裏沒錯。問題出在interface Rollable裏的"Ball ball = new Ball("PingPang");"。任何在interface裏聲明的interface variable (接口變量,也可稱成員變量),默認爲public static final。也就是說"Ball ball = new Ball("PingPang");"實際上是"public static final Ball ball = new Ball("PingPang");"。在Ball類的Play()方法中,"ball = new Ball("Football");"改變了ballreference,而這裏的ball來自Rollable interfaceRollable interface裏的ballpublic static final的,finalobject是不能被改變reference的。因此編譯器將在"ball = new Ball("Football");"這裏顯示有錯。

2. 算法與編程

1、編寫一個程序,將a.txt文件中的單詞與b.txt文件中的單詞交替合併到c.txt文件中,a.txt文件中的單詞用回車符分隔,b.txt文件中用回車或空格進行分隔。

答:

package cn.itcast;

 

import java.io.File;

import java.io.FileReader;

import java.io.FileWriter;

 

public class MainClass{

public static void main(String[] args) throws Exception{

FileManager a = new FileManager("a.txt",new char[]{'\n'});

FileManager b = new FileManager("b.txt",new char[]{'\n',' '});

FileWriter c = new FileWriter("c.txt");

String aWord = null;

String bWord = null;

while((aWord = a.nextWord()) !=null ){

c.write(aWord + "\n");

bWord = b.nextWord();

if(bWord != null)

c.write(bWord + "\n");

}

while((bWord = b.nextWord()) != null){

c.write(bWord + "\n");

}

c.close();

}

}

 

 

class FileManager{

 

String[] words = null;

int pos = 0;

public FileManager(String filename,char[] seperators) throws Exception{

File f = new File(filename);

FileReader reader = new FileReader(f);

char[] buf = new char[(int)f.length()];

int len = reader.read(buf);

String results = new String(buf,0,len);

String regex = null;

if(seperators.length >1 ){

regex = "" + seperators[0] + "|" + seperators[1];

}else{

regex = "" + seperators[0];

}

words = results.split(regex);

}

public String nextWord(){

if(pos == words.length)

return null;

return words[pos++];

}

 

}

 

1、編寫一個程序,將d:\java目錄下的所有.java文件複製到d:\jad目錄下,並將原來文件的擴展名從.java改爲.jad

大家正在做上面這道題,網上遲到的朋友也請做做這道題,找工作必須能編寫這些簡單問題的代碼!

答:listFiles方法接受一個FileFilter對象,這個FileFilter對象就是過慮的策略對象,不同的人提供不同的FileFilter實現,即提供了不同的過濾策略。

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.FilenameFilter;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

 

public class Jad2Java {

 

public static void main(String[] args) throws Exception {

File srcDir = new File("java");

if(!(srcDir.exists() && srcDir.isDirectory()))

throw new Exception("目錄不存在");

File[] files = srcDir.listFiles(

new FilenameFilter(){

 

public boolean accept(File dir, String name) {

return name.endsWith(".java");

}

}

);

System.out.println(files.length);

File destDir = new File("jad");

if(!destDir.exists()) destDir.mkdir();

for(File f :files){

FileInputStream  fis = new FileInputStream(f);

String destFileName = f.getName().replaceAll("\\.java$", ".jad");

FileOutputStream fos = new FileOutputStream(new File(destDir,destFileName));

copy(fis,fos);

fis.close();

fos.close();

}

}

private static void copy(InputStream ips,OutputStream ops) throws Exception{

int len = 0;

byte[] buf = new byte[1024];

while((len = ips.read(buf)) != -1){

ops.write(buf,0,len);

}

 

}

}

 

由本題總結的思想及策略模式的解析:

1.

class jad2java{

1. 得到某個目錄下的所有的java文件集合

1.1 得到目錄 File srcDir = new File("d:\\java");

1.2 得到目錄下的所有java文件:File[] files = srcDir.listFiles(new MyFileFilter());

1.3 只想得到.java的文件: class MyFileFilter implememyts FileFilter{

public boolean accept(File pathname){

return pathname.getName().endsWith(".java")

}

}

2.將每個文件複製到另外一個目錄,並改擴展名

2.1 得到目標目錄,如果目標目錄不存在,則創建之

2.2 根據源文件名得到目標文件名,注意要用正則表達式,注意.的轉義。

2.3 根據表示目錄的File和目標文件名的字符串,得到表示目標文件的File

//要在硬盤中準確地創建出一個文件,需要知道文件名和文件的目錄。 

2.4 將源文件的流拷貝成目標文件流,拷貝方法獨立成爲一個方法,方法的參數採用抽象流的形式。

//方法接受的參數類型儘量面向父類,越抽象越好,這樣適應面更寬廣。

}

 

分析listFiles方法內部的策略模式實現原理

File[] listFiles(FileFilter filter){

File[] files = listFiles();

//Arraylist acceptedFilesList = new ArrayList();

File[] acceptedFiles = new File[files.length];

int pos = 0;

for(File file: files){

boolean accepted = filter.accept(file);

if(accepted){

//acceptedFilesList.add(file);

acceptedFiles[pos++] = file;

}

}

Arrays.copyOf(acceptedFiles,pos);

//return (File[])accpetedFilesList.toArray();

}

1、編寫一個截取字符串的函數,輸入爲一個字符串和字節數,輸出爲按字節截取的字符串,但要保證漢字不被截取半個,如“我ABC”,4,應該截取“我AB”,輸入“我ABCDEF”,6,應該輸出“我ABC”,而不是“我ABC+漢的半個”。

答:

首先要了解中文字符有多種編碼及各種編碼的特徵。

    假設n爲要截取的字節數。

public static void main(String[] args) throws Exception{

String str = "a愛中華abc我愛傳智def';

String str = "ABC";

int num = trimGBK(str.getBytes("GBK"),5);

System.out.println(str.substring(0,num) );

}

public static int  trimGBK(byte[] buf,int n){

int num = 0;

boolean bChineseFirstHalf = false;

for(int i=0;i<n;i++)

{

if(buf[i]<0 && !bChineseFirstHalf){

bChineseFirstHalf = true;

}else{

num++;

bChineseFirstHalf = false;

}

}

return num;

}

1、有一個字符串,其中包含中文字符、英文字符和數字字符,請統計和打印出各個字符的個數。

答:哈哈,其實包含中文字符、英文字符、數字字符原來是出題者放的煙霧彈。

String content = “中國aadf111bbb菲的zz薩菲”;

HashMap map = new HashMap();

for(int i=0;i<content.length;i++)

{

char c = content.charAt(i);

Integer num = map.get(c);

if(num == null)

num = 1;

else

num = num + 1;

map.put(c,num);

for(Map.EntrySet entry : map)

{

system.out.println(entry.getkey() + “:” + entry.getValue());

}

估計是當初面試的那個學員表述不清楚,問題很可能是:

如果一串字符如"aaaabbc中國1512"要分別統計英文字符的數量,中文字符的數量,和數字字符的數量,假設字符中沒有中文字符、英文字符、數字字符之外的其他特殊字符。

int engishCount;

int chineseCount;

int digitCount;

for(int i=0;i<str.length;i++)

{

char ch = str.charAt(i);

if(ch>=’0’ && ch<=’9’)

{

digitCount++

}

else if((ch>=’a’ && ch<=’z’) || (ch>=’A’ && ch<=’Z’))

{

engishCount++;

}

else

{

chineseCount++;

}

}

System.out.println(……………);

 

1、說明生活中遇到的二叉樹,用java實現二叉樹

這是組合設計模式。

我有很多個(假設10萬個)數據要保存起來,以後還需要從保存的這些數據中檢索是否存在某個數據,(我想說出二叉樹的好處,該怎麼說呢?那就是說別人的缺點),假如存在數組中,那麼,碰巧要找的數字位於99999那個地方,那查找的速度將很慢,因爲要從第1個依次往後取,取出來後進行比較。平衡二叉樹(構建平衡二叉樹需要先排序,我們這裏就不作考慮了)可以很好地解決這個問題,但二叉樹的遍歷(前序,中序,後序)效率要比數組低很多,原理如下圖:

 

代碼如下:

package com.huawei.interview;

 

public class Node {

public int value;

public Node left;

public Node right;

public void store(int value)

{

if(value<this.value)

{

if(left == null)

{

left = new Node();

left.value=value;

}

else

{

left.store(value);

}

}

else if(value>this.value)

{

if(right == null)

{

right = new Node();

right.value=value;

}

else

{

right.store(value);

}

}

}

public boolean find(int value)

{

System.out.println("happen " + this.value);

if(value == this.value)

{

return true;

}

else if(value>this.value)

{

if(right == nullreturn false;

return right.find(value);

}else

{

if(left == nullreturn false;

return left.find(value);

}

 

}

public  void preList()

{

System.out.print(this.value + ",");

if(left!=nullleft.preList();

if(right!=nullright.preList();

}

public void middleList()

{

if(left!=nullleft.preList();

System.out.print(this.value + ",");

if(right!=nullright.preList();

}

public void afterList()

{

if(left!=nullleft.preList();

if(right!=nullright.preList();

System.out.print(this.value + ",");

}

public static void main(String [] args)

{

int [] data = new int[20];

for(int i=0;i<data.length;i++)

{

data[i] = (int)(Math.random()*100) + 1;

System.out.print(data[i] + ",");

}

System.out.println();

Node root = new Node();

root.value = data[0];

for(int i=1;i<data.length;i++)

{

root.store(data[i]);

}

root.find(data[19]);

root.preList();

System.out.println();

root.middleList();

System.out.println();

root.afterList();

}

}

-----------------又一次臨場寫的代碼---------------------------

import java.util.Arrays;

import java.util.Iterator;

 

public class Node {

private Node left;

private Node right;

private int value;

//private int num;

public Node(int value){

this.value = value;

}

public void add(int value){

if(value > this.value)

{

if(right != null)

right.add(value);

else

{

Node node = new Node(value);

right = node;

}

}

else{

if(left != null)

left.add(value);

else

{

Node node = new Node(value);

left = node;

}

}

}

public boolean find(int value){

if(value == this.value) return true;

else if(value > this.value){

if(right == null) return false;

else return right.find(value);

}else{

if(left == null) return false;

else return left.find(value);

}

 

}

public void display(){

System.out.println(value);

if(left != null) left.display();

if(right != null) right.display();

}

/*public Iterator iterator(){

}*/

public static void main(String[] args){

int[] values = new int[8];

for(int i=0;i<8;i++){

int num = (int)(Math.random() * 15);

//System.out.println(num);

//if(Arrays.binarySearch(values, num)<0)

if(!contains(values,num))

values[i] = num;

else

i--;

}

System.out.println(Arrays.toString(values));

Node root  = new Node(values[0]);

for(int i=1;i<values.length;i++){

root.add(values[i]);

}

System.out.println(root.find(13));

root.display();

}

public static boolean contains(int [] arr, int value){

int i = 0;

for(;i<arr.length;i++){

if(arr[i] == value) return true;

}

return false;

}

}

1、從類似如下的文本文件中讀取出所有的姓名,並打印出重複的姓名和重複的次數,並按重複次數排序:

1,張三,28

2,李四,35

3,張三,28

4,王五,35

5,張三,28

6,李四,35

7,趙六,28

8,田七,35

 

程序代碼如下(答題要博得用人單位的喜歡,包名用該公司,面試前就提前查好該公司的網址,如果查不到,現場問也是可以的。還要加上實現思路的註釋):

package com.huawei.interview;

 

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.util.Comparator;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.TreeSet;

 

 

public class GetNameTest {

 

/**

 * @param args

 */

public static void main(String[] args) {

// TODO Auto-generated method stub

//InputStream ips = GetNameTest.class.getResourceAsStream("/com/huawei/interview/info.txt");

//用上一行註釋的代碼和下一行的代碼都可以,因爲info.txtGetNameTest類在同一包下面,所以,可以用下面的相對路徑形式

Map results = new HashMap();

InputStream ips = GetNameTest.class.getResourceAsStream("info.txt");

BufferedReader in = new BufferedReader(new InputStreamReader(ips));

String line = null;

try {

while((line=in.readLine())!=null)

{

dealLine(line,results);

}

sortResults(results);

catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

static class User

{

public  String name;

public Integer value;

public User(String name,Integer value)

{

this.name = name;

this.value = value;

}

 

@Override

public boolean equals(Object obj) {

// TODO Auto-generated method stub

//下面的代碼沒有執行,說明往treeset中增加數據時,不會使用到equals方法。

boolean result = super.equals(obj);

System.out.println(result);

return result;

}

}

private static void sortResults(Map results) {

// TODO Auto-generated method stub

TreeSet sortedResults = new TreeSet(

new Comparator(){

public int compare(Object o1, Object o2) {

// TODO Auto-generated method stub

User user1 = (User)o1;

User user2 = (User)o2;

/*如果compareTo返回結果0,則認爲兩個對象相等,新的對象不會增加到集合中去

 * 所以,不能直接用下面的代碼,否則,那些個數相同的其他姓名就打印不出來。

 * */

//return user1.value-user2.value;

//return user1.value<user2.value?-1:user1.value==user2.value?0:1;

if(user1.value<user2.value)

{

return -1;

}else if(user1.value>user2.value)

{

return 1;

}else

{

return user1.name.compareTo(user2.name);

}

}

}

);

Iterator iterator = results.keySet().iterator();

while(iterator.hasNext())

{

String name = (String)iterator.next();

Integer value = (Integer)results.get(name);

if(value > 1)

{

sortedResults.add(new User(name,value));

}

}

printResults(sortedResults);

}

private static void printResults(TreeSet sortedResults) 

{

Iterator iterator  = sortedResults.iterator();

while(iterator.hasNext())

{

User user = (User)iterator.next();

System.out.println(user.name + ":" + user.value);

}

}

public static void dealLine(String line,Map map)

{

if(!"".equals(line.trim()))

{

String [] results = line.split(",");

if(results.length == 3)

{

String name = results[1];

Integer value = (Integer)map.get(name);

if(value == null) value = 0;

map.put(name,value + 1);

}

}

}

 

}

48、寫一個Singleton出來。

第一種:飽漢模式

public class SingleTon {

private SingleTon(){

}

 

//實例化放在靜態代碼塊裏可提高程序的執行效率,但也可能更佔用空間

private final static SingleTon instance = new SingleTon();

public static SingleTon getInstance(){

return instance;

}

}

 

第二種:飢漢模式

public class SingleTon {

private SingleTon(){}

private static instance = null;//new SingleTon();

public static synchronized SingleTon getInstance(){

if(instance == null)

instance = new SingleTon();

return instance;

}

}

 

第三種:用枚舉

public enum SingleTon{

ONE;

}

 

第三:更實際的應用(在什麼情況用單例)

public class SequenceGenerator{

//下面是該類自身的業務功能代碼

private int count = 0;

 

public synchronized int getSequence(){

++count;

}

//下面是把該類變成單例的代碼

private SequenceGenerator(){}

private final static instance = new SequenceGenerator();

public static SingleTon getInstance(){

return instance;

}

}

 

第四:

public class MemoryDao

{

    private HashMap map = new HashMap();

    

    public void add(Student stu1){ 

     map.put(SequenceGenerator.getInstance().getSequence(),stu1);

    }

   

   //MemoryDao變成單例 

  }

 

 

 

 

 

 

Singleton模式主要作用是保證在Java應用程序中,一個類Class只有一個實例存在。 

一般Singleton模式通常有幾種種形式

第一種形式定義一個類,它的構造函數爲private的,它有一個staticprivate的該類變量,在類初始化時實例話,通過一個publicgetInstance方法獲取對它的引用,繼而調用其中的方法。 

public class Singleton { 

private Singleton(){} 

      //在自己內部定義自己一個實例,是不是很奇怪? 

      //注意這是private 只供內部調用 

      private static Singleton instance = new Singleton(); 

      //這裏提供了一個供外部訪問本class的靜態方法,可以直接訪問   

      public static Singleton getInstance() { 

        return instance;    

      

   } 

   第二種形式

public class Singleton { 

  private static Singleton instance = null; 

  public static synchronized Singleton getInstance() { 

  //這個方法比上面有所改進,不用每次都進行生成對象,只是第一次      

  //使用時生成實例,提高了效率! 

  if (instance==null) 

    instancenew Singleton(); 

return instance; 

其他形式

定義一個類,它的構造函數爲private的,所有方法爲static的。 

一般認爲第一種形式要更加安全些 

7、遞歸算法題1

一個整數,大於0,不用循環和本地變量,按照n,2n,4n,8n的順序遞增,當值大於5000時,把值按照指定順序輸出來。
例:n=1237
則輸出爲:
1237,
2474,
4948,
9896,
9896,
4948,
2474,
1237,

提示:寫程序時,先致謝按遞增方式的代碼,寫好遞增的以後,再增加考慮遞減部分。

public static void doubleNum(int n)

{

System.out.println(n);

if(n<=5000)

doubleNum(n*2);

System.out.println(n);

}

 

 

7、遞歸算法題2

第1個人10,第2個比第1個人大2歲,依次遞推,請用遞歸方式計算出第8個人多大?

package cn.itcast;

 

import java.util.Date;

 

public class A1 {

 

public static void main(String [] args)

{

System.out.println(computeAge(8));

}

public static int computeAge(int n)

{

if(n==1) return 10;

return computeAge(n-1) + 2;

}

}

 

public static void toBinary(int n,StringBuffer result)

{

 

if(n/2 != 0)

toBinary(n/2,result);

result.append(n%2);

}

94、排序都有哪幾種方法?請列舉。用JAVA實現一個快速排序。 

 本人只研究過冒泡排序、選擇排序和快速排序,下面是快速排序的代碼:

public class QuickSort {
/**
快速排序
* @param strDate
* @param left
* @param right
*/
public void quickSort(String[] strDate,int left,int right){
String middle,tempDate;
int i,j;
i=left;
j=right;
middle=strDate[(i+j)/2];
do{
while(strDate[i].compareTo(middle)<0&& i<right)
i++; //找出左邊比中間值大的數
while(strDate[j].compareTo(middle)>0&& j>left)
j--; //找出右邊比中間值小的數
if(i<=j){ //將左邊大的數和右邊小的數進行替換 
tempDate=strDate[i];
strDate[i]=strDate[j];
strDate[j]=tempDate;
i++;
j--;
}
}while(i<=j); //當兩者交錯時停止

if(i<right){
quickSort(strDate,i,right);//
}
if(j>left){
quickSort(strDate,left,j);
}
}
/**
  * @param args
  */
public static void main(String[] args){
String[] strVoid=new String[]{"11","66","22","0","55","22","0","32"};
QuickSort sort=new QuickSort();
sort.quickSort(strVoid,0,strVoid.length-1);
for(int i=0;i<strVoid.length;i++){
System.out.println(strVoid[i]+" ");
}
}


}

7、有數組a[n],用java代碼將數組元素順序顛倒

//用下面的也可以

//for(int i=0,int j=a.length-1;i<j;i++,j--) 是否等效於 for(int i=0;i<a.length/2;i++)呢?

 

import java.util.Arrays;

 

public class SwapDemo{

 

public static void main(String[] args){

int [] a = new int[]{

(int)(Math.random() * 1000),

(int)(Math.random() * 1000),

(int)(Math.random() * 1000),

(int)(Math.random() * 1000),

(int)(Math.random() * 1000)

};

System.out.println(a);

System.out.println(Arrays.toString(a));

swap(a);

System.out.println(Arrays.toString(a));

}

public static void swap(int a[]){

int len = a.length;

for(int i=0;i<len/2;i++){

int tmp = a[i];

a[i] = a[len-1-i];

a[len-1-i] = tmp;

}

}

}

2.金額轉換,阿拉伯數字的金額轉換成中國傳統的形式如:(¥1011)->(一千零一拾一元整)輸出。

去零的代碼:

return sb.reverse().toString().replaceAll("零[拾佰仟]","零").replaceAll("零+萬","萬").replaceAll("零+元","元").replaceAll("零+","零");

 

public class RenMingBi {

 

/**

 * @param args add by zxx ,Nov 29, 2008

 */

private static final char[] data = new char[]{

'','','','','','','','','',''

}; 

private static final char[] units = new char[]{

'','','','','','','','',''

};

public static void main(String[] args) {

// TODO Auto-generated method stub

System.out.println(

convert(135689123));

}

 

public static String convert(int money)

{

StringBuffer sbf = new StringBuffer();

int unit = 0;

while(money!=0)

{

sbf.insert(0,units[unit++]);

int number = money%10;

sbf.insert(0, data[number]);

money /= 10;

}

 

return sbf.toString();

}

}

2. html&JavaScript&ajax部分

1. 判斷第二個日期比第一個日期大

如何用腳本判斷用戶輸入的的字符串是下面的時間格式2004-11-21 必須要保證用戶的輸入是此格式,並且是時間,比如說月份不大於12等等,另外我需要用戶輸入兩個,並且後一個要比前一個晚,只允許用JAVASCRIPT,請詳細幫助作答,

//這裏可用正則表達式判斷提前判斷一下格式,然後按下提取各時間字段內容

<script type="text/javascript">

window.onload = function()

{

//這麼寫是爲了實現js代碼與html代碼的分離,當我修改js時,不能影響html代碼。

document.getElementById("frm1").onsubmit = 

function(){

var d1 = this.d1.value;

var d2 = this.d2.value;

if(!verifyDate (d1)) {alert("第一個日期格式不對");return false;}

if(!verifyDate (d2)) {alert("第二個日期格式不對");return false;}

if(!compareDate(d1,d2)) {alert("第二個日期比第一日期小");return false;}

};

}

function compareDate(d1,d2)

{

var arrayD1 = d1.split("-");

var date1 = new Date(arrayD1[0],arrayD1[1],arrayD1[2]);

var arrayD2 = d2.split("-");

var date2 = new Date(arrayD2[0],arrayD2[1],arrayD2[2]);

if(date1 > date2) return false;

return true;

function verifyDate(d)

{

var datePattern = /^\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2]\d|3[0-1])$/;

return datePattern.test(d);

}

</script>

 

<form id="frm1" action="xxx.html">

<input type="text" name="d1" />

<input type="text" name="d2" />

<input type="submit"/>

</form>

1. 用table顯示n條記錄,每3行換一次顏色,即123用紅色字體,456用綠色字體,789用紅顏色字體。

<body>

<table id="tbl">

<tr><td>1</td></tr>

<tr><td>2</td></tr>

<tr><td>3</td></tr>

<tr><td>4</td></tr>

<tr><td>5</td></tr>

<tr><td>6</td></tr>

<tr><td>7</td></tr>

<tr><td>8</td></tr>

<tr><td>9</td></tr>

<tr><td>10</td></tr>

</table>

</body>

<script type="text/javascript">

window.οnlοad=function()

{

var tbl = document.getElementById("tbl");

rows = tbl.getElementsByTagName("tr");

for(i=0;i<rows.length;i++)

{

var j = parseInt(i/3);

if(j%2==0) rows[i].style.backgroundColor="#f00";

else  rows[i].style.backgroundColor="#0f0";

}

}

</script>

1HTML 的 form 提交之前如何驗證數值文本框的內容全部爲數字? 否則的話提示用戶並終止提交

<form οnsubmit=’return chkForm(this)’>

<input type="text" name="d1"/>

<input type="submit"/>

</form>

<script type=”text/javascript” />

function chkForm(this)

var value = thist.d1.value;

var len = value.length;

for(var i=0;i<len;i++)

{

if(value.charAt(i)>"9" || value.charAt(i)<"0")

{

alert("含有非數字字符"); return false;

}

}

return true;

}

</script>

 

2、請寫出用於校驗HTML文本框中輸入的內容全部爲數字的javascript代碼

<input type="text" id="d1" οnblur=" chkNumber (this)"/>

<script type=”text/javascript” />

function chkNumber(eleText) 

var value = eleText.value;

var len = value.length;

for(var i=0;i<len;i++)

{

if(value.charAt(i)>"9" || value.charAt(i)<"0")

{

alert("含有非數字字符"); 

eleText.focus();

break; 

}

}

}

</script>

除了寫完代碼,還應該在網頁上寫出實驗步驟和在代碼中加入實現思路,讓面試官一看就明白你的意圖和檢查你的結果。

 

1、說說你用過那些ajax技術和框架,說說它們的區別

:去掉對web.xml的監視,把jsp提前編輯成Servlet

有富餘物理內存的情況,加大tomcat使用的jvm的內存

 

3. Java web部分

1Tomcat的優化經驗

:去掉對web.xml的監視,把jsp提前編輯成Servlet

有富餘物理內存的情況,加大tomcat使用的jvm的內存

 

 

1HTTP請求的GETPOST方式的區別

:servlet有良好的生存期的定義,包括加載和實例化、初始化、處理請求以及服務結束。這個生存期由javax.servlet.Servlet接口的init,servicedestroy方法表達。

62、解釋一下什麼是servlet;

:servlet有良好的生存期的定義,包括加載和實例化、初始化、處理請求以及服務結束。這個生存期由javax.servlet.Servlet接口的init,servicedestroy方法表達。

1、說一說Servlet的生命週期

:servlet有良好的生存期的定義,包括加載和實例化、初始化、處理請求以及服務結束。這個生存期由javax.servlet.Servlet接口的init,servicedestroy方法表達。

 

Servlet被服務器實例化後,容器運行其init方法,請求到達時運行其service方法,service方法自動派遣運行與請求對應的doXXX方法(doGetdoPost)等,當服務器決定將實例銷燬的時候調用其destroy方法。

web容器加載servlet,生命週期開始。通過調用servletinit()方法進行servlet的初始化。通過調用service()方法實現,根據請求的不同調用不同的do***()方法。結束服務,web容器調用servletdestroy()方法。 

 

4Servlet的基本架構 

public class ServletName extends HttpServlet { 

public void doPost(HttpServletRequest request, HttpServletResponse response) throws 

ServletException, IOException { 

public void doGet(HttpServletRequest request, HttpServletResponse response) throws 

ServletException, IOException { 

3SERVLET APIforward() redirect()的區別? 

:前者僅是容器中控制權的轉向,在客戶端瀏覽器地址欄中不會顯示出轉向後的地址;後者則是完全的跳轉,瀏覽器將會得到跳轉的地址,並重新發送請求鏈接。這樣,從瀏覽器的地址欄中可以看到跳轉後的鏈接地址。所以,前者更加高效,在前者可以滿足需要時,儘量使用forward()方法,並且,這樣也有助於隱藏實際的鏈接。在有些情況下,比如,需要跳轉到一個其它服務器上的資源,則必須使用

sendRedirect()方法。 

 

60、什麼情況下調用doGet()doPost()? 

Jsp頁面中的FORM標籤裏的method屬性爲get時調用doGet(),爲post時調用doPost()。 

 

66Request對象的主要方法: 

setAttribute(String name,Object):設置名字爲namerequest的參數值 

getAttribute(String name):返回由name指定的屬性值 

getAttributeNames():返回request對象所有屬性的名字集合,結果是一個枚舉的實例 

getCookies():返回客戶端的所有Cookie對象,結果是一個Cookie數組 

getCharacterEncoding():返回請求中的字符編碼方式 

getContentLength():返回請求的Body的長度 

getHeader(String name):獲得HTTP協議定義的文件頭信息 

getHeaders(String name):返回指定名字的request Header的所有值,結果是一個枚舉的實例 

getHeaderNames():返回所以request Header的名字,結果是一個枚舉的實例 

getInputStream():返回請求的輸入流,用於獲得請求中的數據 

getMethod():獲得客戶端向服務器端傳送數據的方法 

getParameter(String name):獲得客戶端傳送給服務器端的有name指定的參數值 

getParameterNames():獲得客戶端傳送給服務器端的所有參數的名字,結果是一個枚舉的實例 

getParametervalues(String name):獲得有name指定的參數的所有值 

getProtocol():獲取客戶端向服務器端傳送數據所依據的協議名稱 

getQueryString():獲得查詢字符串 

getRequestURI():獲取發出請求字符串的客戶端地址 

getRemoteAddr():獲取客戶端的IP地址 

getRemoteHost():獲取客戶端的名字 

getSession([Boolean create]):返回和請求相關Session 

getServerName():獲取服務器的名字 

getServletPath():獲取客戶端所請求的腳本文件的路徑 

getServerPort():獲取服務器的端口號 

removeAttribute(String name):刪除請求中的一個屬性 

 

 

 

19forward redirect的區別 

forward是服務器請求資源,服務器直接訪問目標地址的URL,把那個URL的響應內容讀取過來,然後把這些內容再發給瀏覽器,瀏覽器根本不知道服務器發送的內容是從哪兒來的,所以它的地址欄中還是原來的地址。 

   redirect就是服務端根據邏輯,發送一個狀態碼,告訴瀏覽器重新去請求那個地址,一般來說瀏覽器會用剛纔請求的所有參數重新請求,所以session,request參數都可以獲取。

4request.getAttribute() 和 request.getParameter() 有何區別?

1. jsp有哪些內置對象?作用分別是什麼分別有什麼方法? 

:JSP共有以下9個內置的對象: 

request 用戶端請求,此請求會包含來自GET/POST請求的參數 

response 網頁傳回用戶端的迴應 

pageContext 網頁的屬性是在這裏管理 

session 與請求有關的會話期 

application servlet 正在執行的內容 

out 用來傳送回應的輸出 

config servlet的構架部件 

page JSP網頁本身 

exception 針對錯誤網頁,未捕捉的例外 

 

request表示HttpServletRequest對象。它包含了有關瀏覽器請求的信息,並且提供了幾個用於獲取cookie, header, session數據的有用的方法。 

   response表示HttpServletResponse對象,並提供了幾個用於設置送回 瀏覽器的響應的方法(如cookies,頭信息等) 

   out對象是javax.jsp.JspWriter的一個實例,並提供了幾個方法使你能用於向瀏覽器回送輸出結果。 

   pageContext表示一個javax.servlet.jsp.PageContext對象。它是用於方便存取各種範圍的名字空間、servlet相關的對象的API,並且包裝了通用的servlet相關功能的方法。 

   session表示一個請求的javax.servlet.http.HttpSession對象。Session可以存貯用戶的狀態信息 

   applicaton 表示一個javax.servle.ServletContext對象。這有助於查找有關servlet引擎和servlet環境的信息 

   config表示一個javax.servlet.ServletConfig對象。該對象用於存取servlet實例的初始化參數。 

   page表示從該頁面產生的一個servlet實例 

 

2. jsp有哪些動作?作用分別是什麼

(這個問題似乎不重要,不明白爲何有此題)

:JSP共有以下6種基本動作 

jsp:include:在頁面被請求的時候引入一個文件。 

jsp:useBean:尋找或者實例化一個JavaBean。 

jsp:setProperty:設置JavaBean的屬性。 

jsp:getProperty:輸出某個JavaBean的屬性。 

jsp:forward:把請求轉到一個新的頁面。 

jsp:plugin:根據瀏覽器類型爲Java插件生成OBJECTEMBED標記

59JSP的常用指令 

isErrorPage(是否能使用Exception對象)isELIgnored(是否忽略表達式

 

3. JSP中動態INCLUDE與靜態INCLUDE的區別? 

答:動態INCLUDEjsp:include動作實現 

<jsp:include page=included.jsp flush=true />它總是會檢查所含文件中的變化,適合用於包含動態頁面,並且可以帶參數 靜態INCLUDEinclude僞碼實現,定不會檢查所含文件的變化,適用於包含靜態頁面 <%@ include file=included.htm %> 

 

4、兩種跳轉方式分別是什麼?有什麼區別

(下面的回答嚴重錯誤,應該是想問forwardsendRedirect 的區別,畢竟出題的人不是專業搞文字藝術的人,可能表達能力並不見得很強,用詞不一定精準,加之其自身的技術面也可能存在一些問題,不一定真正將他的意思表達清楚了,嚴格意思上來講,一些題目可能根本就無人能答,所以,答題時要掌握主動,只要把自己知道的表達清楚就夠了,而不要去推敲原始題目的具體含義是什麼,不要一味想着是在答題)

答:有兩種,分別爲: 

<jsp:include page=included.jsp flush=true> 

<jsp:forward page= nextpage.jsp/> 

前者頁面不會轉向include所指的頁面,只是顯示該頁的結果,主頁面還是原來的頁面。執行完後還會回來,相當於函數調用。並且可以帶參數.後者完全轉向新頁面,不會再回來。相當於go to 語句。

 

63、頁面間對象傳遞的方法 

requestsessionapplicationcookie等 

64JSPServlet有哪些相同點和不同點,他們之間的聯繫是什麼? 

JSPServlet技術的擴展,本質上是Servlet的簡易方式,更強調應用的外表表達。JSP編譯後是"servlet"ServletJSP最主要的不同點在於,Servlet的應用邏輯是在Java文件中,並且完全從表示層中的HTML裏分離開來。而JSP的情況是JavaHTML可以組合成一個擴展名爲.jsp的文件。JSP側重於視圖,Servlet主要用於控制邏輯。 

 

1MVC的各個部分都有那些技術來實現?如何實現

:MVCModelViewController的簡寫。Model 代表的是應用的業務邏輯(通過JavaBeanEJB組件實現), View 是應用的表示面(由JSP頁面產生),Controller 是提供應用的處理過程控制(一般是一個Servlet),通過這種設計模型把應用邏輯,處理過程和顯示邏輯分成不同的組件實現。這些組件可以進行交互和重用。 

 

68、我們在web應用開發過程中經常遇到輸出某種編碼的字符,如iso8859-1等,如何輸出一個某種編碼的字符串? 

 Public String translate (String str) { 

   String tempStr = ""; 

   try { 

     tempStr = new String(str.getBytes("ISO-8859-1"), "GBK"); 

     tempStr = tempStr.trim(); 

   } 

   catch (Exception e) { 

     System.err.println(e.getMessage()); 

   } 

   return tempStr; 

 } 

1.現在輸入n個數字,以逗號,分開;然後可選擇升或者降序排序;按提交鍵就在另一頁面顯示按什麼排序,結果爲,提供reset

4. 數據庫部分

1、用兩種方式根據部門號從高到低,工資從低到高列出每個員工的信息。

employee:

     eid,ename,salary,deptid;

 select * from employee order by deptid desc,salary

 

 

2、列出各個部門中工資高於本部門的平均工資的員工數和部門號,並按部門號排序

創建表:

       mysql> create table employee921(id int primary key auto_increment,name varchar(5

0),salary bigint,deptid int);

 

插入實驗數據:

mysql> insert into employee921 values(null,'zs',1000,1),(null,'ls',1100,1),(null

,'ww',1100,1),(null,'zl',900,1) ,(null,'zl',1000,2), (null,'zl',900,2) ,(null,'z

l',1000,2) , (null,'zl',1100,2);

 

編寫sql語句:

 

()select avg(salary) from employee921 group by deptid;

()mysql> select employee921.id,employee921.name,employee921.salary,employee921.dep

tid tid from  employee921 where salary > (select avg(salary) from employee921 where  deptid = tid);

   效率低的一個語句,僅供學習參考使用(在group by之後不能使用where,只能使用having,在group by之前可以使用where,即表示對過濾後的結果分組):

mysql> select employee921.id,employee921.name,employee921.salary,employee921.dep

tid tid from  employee921 where salary > (select avg(salary) from employee921 group by deptid having deptid = tid);

()select count(*) ,tid 

from (

select employee921.id,employee921.name,employee921.salary,employee921.deptid tid 

from   employee921 

where salary >

  (select avg(salary) from employee921 where  deptid = tid)

) as t 

group by tid ;

 

另外一種方式:關聯查詢

select a.ename,a.salary,a.deptid 

 from emp a,

    (select deptd,avg(salary) avgsal from emp group by deptid ) b 

 where a.deptid=b.deptid and a.salary>b.avgsal;

1、存儲過程與觸發器必須講,經常被面試到?

create procedure insert_Student (_name varchar(50),_age int ,out _id int)

begin

insert into student value(null,_name,_age);

select max(stuId) into _id from student;

end;

 

call insert_Student('wfz',23,@id);

select @id;

 

mysql> create trigger update_Student BEFORE update on student FOR EACH ROW

-> select * from student;

觸發器不允許返回結果

 

create trigger update_Student BEFORE update on student FOR EACH ROW  

insert into  student value(null,'zxx',28);

mysql的觸發器目前不能對當前表進行操作

 

create trigger update_Student BEFORE update on student FOR EACH ROW  

delete from articles  where id=8;

這個例子不是很好,最好是用刪除一個用戶時,順帶刪除該用戶的所有帖子

這裏要注意使用OLD.id

 

觸發器用處還是很多的,比如校內網、開心網、Facebook,你發一個日誌,自動通知好友,其實就是在增加日誌時做一個後觸發,再向通知表中寫入條目。因爲觸發器效率高。而UCH沒有用觸發器,效率和數據處理能力都很低。

存儲過程的實驗步驟:

mysql> delimiter |

mysql> create procedure insertArticle_Procedure (pTitle varchar(50),pBid int,out

 pId int)

    -> begin

    -> insert into article1 value(null,pTitle,pBid);

    -> select max(id) into pId from article1;

    -> end;

    -> |

Query OK, 0 rows affected (0.05 sec)

 

mysql> call insertArticle_Procedure('傳智播客',1,@pid);

    -> |

Query OK, 0 rows affected (0.00 sec)

 

mysql> delimiter ;

mysql> select @pid;

+------+

| @pid |

+------+

| 3    |

+------+

1 row in set (0.00 sec)

 

mysql> select * from article1;

+----+--------------+------+

| id | title        | bid  |

+----+--------------+------+

| 1  | test         | 1    |

| 2  | chuanzhiboke | 1    |

| 3  | 傳智播客     | 1    |

+----+--------------+------+

3 rows in set (0.00 sec)

 

觸發器的實驗步驟:

create table board1(id int primary key auto_increment,name varchar(50),ar

ticleCount int);

 

create table article1(id int primary key auto_increment,title varchar(50)

,bid int references board1(id));

 

delimiter |

 

create trigger insertArticle_Trigger after insert on article1 for each ro

w begin

    -> update board1 set articleCount=articleCount+1 where id= NEW.bid;

    -> end;

    -> |

 

delimiter ;

 

insert into board1 value (null,'test',0);

 

insert into article1 value(null,'test',1);

還有,每插入一個帖子,都希望將版面表中的最後發帖時間,帖子總數字段進行同步更新,用觸發器做效率就很高。下次課設計這樣一個案例,寫觸發器時,對於最後發帖時間可能需要用declare方式聲明一個變量,或者是用NEW.posttime來生成。

 

1數據庫三範式是什麼?

第一範式(1NF):字段具有原子性,不可再分。所有關係型數據庫系統都滿足第一範式)

數據庫表中的字段都是單一屬性的,不可再分。例如,姓名字段,其中的姓和名必須作爲一個整體,無法區分哪部分是姓,哪部分是名,如果要區分出姓和名,必須設計成兩個獨立的字段。

 

  第二範式(2NF):

第二範式(2NF)是在第一範式(1NF)的基礎上建立起來的,即滿足第二範式(2NF)必須先滿足第一範式(1NF)。

要求數據庫表中的每個實例或行必須可以被惟一地區分。通常需要爲表加上一個列,以存儲各個實例的惟一標識。這個惟一屬性列被稱爲主關鍵字或主鍵。

 

第二範式(2NF)要求實體的屬性完全依賴於主關鍵字。所謂完全依賴是指不能存在僅依賴主關鍵字一部分的屬性,如果存在,那麼這個屬性和主關鍵字的這一部分應該分離出來形成一個新的實體,新實體與原實體之間是一對多的關係。爲實現區分通常需要爲表加上一個列,以存儲各個實例的惟一標識。簡而言之,第二範式就是非主屬性非部分依賴於主關鍵字。

  

 第三範式的要求如下: 

滿足第三範式(3NF)必須先滿足第二範式(2NF)。簡而言之,第三範式(3NF)要求一個數據庫表中不包含已在其它表中已包含的非主關鍵字信息。

所以第三範式具有如下特徵:
         1,每一列只有一個值 
         2,每一行都能區分。 
         3,每一個表都不包含其他表已經包含的非主關鍵字信息。

例如,帖子表中只能出現發帖人的id,而不能出現發帖人的id,還同時出現發帖人姓名,否則,只要出現同一發帖人id的所有記錄,它們中的姓名部分都必須嚴格保持一致,這就是數據冗餘。

 

1、說出一些數據庫優化方面的經驗?

PreparedStatement 一般來說比Statement性能高:一個sql 發給服務器去執行,涉及步驟:語法檢查、語義分析, 編譯,緩存

“inert into user values(1,1,1)”-à二進制

“inert into user values(2,2,2)”-à二進制

“inert into user values(?,?,?)”-à二進制

 

 

 

有外鍵約束會影響插入和刪除性能,如果程序能夠保證數據的完整性,那在設計數據庫時就去掉外鍵。(比喻:就好比免檢產品,就是爲了提高效率,充分相信產品的製造商)

(對於hibernate來說,就應該有一個變化:empleyee->Deptment對象,現在設計時就成了employeeàdeptid

 

mysql幫助文檔子查詢章節的最後部分,例如,根據掃描的原理,下面的子查詢語句要比第二條關聯查詢的效率高:

1.  select e.name,e.salary where e.managerid=(select id from employee where name='zxx');

 

2.   select e.name,e.salary,m.name,m.salary from employees e,employees m where

 e.managerid = m.id and m.name='zxx';

 

表中允許適當冗餘,譬如,主題帖的回覆數量和最後回覆時間等

將姓名和密碼單獨從用戶表中獨立出來。這可以是非常好的一對一的案例喲!

 

sql語句全部大寫,特別是列名和表名都大寫。特別是sql命令的緩存功能,更加需要統一大小寫,sql語句à發給oracle服務器à語法檢查和編譯成爲內部指令à緩存和執行指令。根據緩存的特點,不要拼湊條件,而是用?PreparedStatment

 

還有索引對查詢性能的改進也是值得關注的。

 

備註:下面是關於性能的討論舉例

 

4航班 3個城市

 

m*n

 

select * from flight,city where flight.startcityid=city.cityid and city.name='beijing';

 

m + n

 

 

select * from flight where startcityid = (select cityid from city where cityname='beijing');

 

select flight.id,'beijing',flight.flightTime from flight where startcityid = (select cityid from city where cityname='beijing')

2unionunion all有什麼不同?

假設我們有一個表Student,包括以下字段與數據:

drop table student;

create table student
(
id int primary key,
name nvarchar2(50) not null,
score number not null
);

insert into student values(1,'Aaron',78);
insert into student values(2,'Bill',76);
insert into student values(3,'Cindy',89);
insert into student values(4,'Damon',90);
insert into student values(5,'Ella',73);
insert into student values(6,'Frado',61);
insert into student values(7,'Gill',99);
insert into student values(8,'Hellen',56);
insert into student values(9,'Ivan',93);
insert into student values(10,'Jay',90);

commit;

UnionUnion All的區別。 

select *
from student
where id < 4

union

select *
from student
where id > 2 and id < 6

結果將是

1    Aaron    78
2    Bill    76
3    Cindy    89
4    Damon    90
5    Ella    73

如果換成Union All連接兩個結果集,則返回結果是:

1    Aaron    78
2    Bill    76
3    Cindy    89
3    Cindy    89
4    Damon    90
5    Ella    73

可以看到,UnionUnion All的區別之一在於對重複結果的處理。

 

  UNION在進行錶鏈接後會篩選掉重複的記錄,所以在錶鏈接後會對所產生的結果集進行排序運算,刪除重複的記錄再返回結果。實際大部分應用中是不會產生重複的記錄,最常見的是過程表與歷史表UNION。如:
select * from gc_dfys
union
select * from ls_jg_dfys
  這個SQL在運行時先取出兩個表的結果,再用排序空間進行排序刪除重複的記錄,最後返回結果集,如果表數據量大的話可能會導致用磁盤進行排序。
 而UNION ALL只是簡單的將兩個結果合併後就返回。這樣,如果返回的兩個結果集中有重複的數據,那麼返回的結果集就會包含重複的數據了。
 從效率上說,UNION ALL 要比UNION快很多,所以,如果可以確認合併的兩個結果集中不包含重複的數據的話,那麼就使用UNION ALL

3.分頁語句

取出sql表中第31到40的記錄(以自動增長ID爲主鍵)

sql server方案1:

select top 10 * from t where id not in (select top 30 id from t order by id ) orde by id

sql server方案2:

select top 10 * from t where id in (select top 40 id from t order by id) order by id desc

 

mysql方案:select * from t order by id limit 30,10

 

oracle方案:select * from (select rownum r,* from t where r<=40) where r>30

 

--------------------待整理進去的內容-------------------------------------

pageSize=20;

pageNo = 5;

 

1.分頁技術1(直接利用sql語句進行分頁,效率最高和最推薦的)

 

mysql:sql = "select * from articles limit " + (pageNo-1)*pageSize + "," + pageSize;

oracle: sql = "select * from " +

"(select rownum r,* from " +

"(select * from articles order by postime desc)" +

"where rownum<= " + pageNo*pageSize +") tmp " +

"where r>" + (pageNo-1)*pageSize;

註釋:第7行保證rownum的順序是確定的,因爲oracle的索引會造成rownum返回不同的值

簡洋提示:沒有order by時,rownum按順序輸出,一旦有了order byrownum不按順序輸出了,這說明rownum是排序前的編號。如果對order by從句中的字段建立了索引,那麼,rownum也是按順序輸出的,因爲這時候生成原始的查詢結果集時會參照索引表的順序來構建。

 

sqlserver:sql = "select top 10 * from id not id(select top " + (pageNo-1)*pageSize + "id from articles)"

 

DataSource ds = new InitialContext().lookup(jndiurl);

Connection cn = ds.getConnection();

//"select * from user where id=?"  --->binary directive

PreparedStatement pstmt = cn.prepareSatement(sql);

ResultSet rs = pstmt.executeQuery()

while(rs.next())

{

out.println(rs.getString(1));

}

 

2.不可滾動的遊標

pageSize=20;

pageNo = 5;

cn = null

stmt = null;

rs = null;

try

{

sqlserver:sql = "select  * from articles";

 

DataSource ds = new InitialContext().lookup(jndiurl);

Connection cn = ds.getConnection();

//"select * from user where id=?"  --->binary directive

PreparedStatement pstmt = cn.prepareSatement(sql);

ResultSet rs = pstmt.executeQuery()

for(int j=0;j<(pageNo-1)*pageSize;j++)

{

rs.next();

}

 

int i=0;

 

while(rs.next() && i<10)

{

i++;

out.println(rs.getString(1));

}

}

cacth(){}

finnaly

{

if(rs!=null)try{rs.close();}catch(Exception e){}

if(stm.........

if(cn............

}

 

3.可滾動的遊標

pageSize=20;

pageNo = 5;

cn = null

stmt = null;

rs = null;

try

{

sqlserver:sql = "select  * from articles";

 

DataSource ds = new InitialContext().lookup(jndiurl);

Connection cn = ds.getConnection();

//"select * from user where id=?"  --->binary directive

PreparedStatement pstmt = cn.prepareSatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,...);

//根據上面這行代碼的異常SQLFeatureNotSupportedException,就可判斷驅動是否支持可滾動遊標

 

ResultSet rs = pstmt.executeQuery()

rs.absolute((pageNo-1)*pageSize)

int i=0;

while(rs.next() && i<10)

{

i++;

out.println(rs.getString(1));

}

}

cacth(){}

finnaly

{

if(rs!=null)try{rs.close();}catch(Exception e){}

if(stm.........

if(cn............

}

3.用一條SQL語句 查詢出每門課都大於80分的學生姓名  

name   kecheng   fenshu 
張三     語文       81
張三     數學       75
李四     語文       76
李四     數學       90
王五     語文       81
王五     數學       100
王五     英語       90

準備數據的sql代碼:

create table score(id int primary key auto_increment,name varchar(20),subject varchar(20),score int);

insert into score values 

(null,'張三','語文',81),

(null,'張三','數學',75),

(null,'李四','語文',76),

(null,'李四','數學',90),

(null,'王五','語文',81),

(null,'王五','數學',100),

(null,'王五 ','英語',90);

 

提示:當百思不得其解時,請理想思維,把小變成大做,把大變成小做,

 

答案:
A: select distinct name from score  where  name not in (select distinct name from score where score<=80)

 

B:select distince name t1 from score where 80< all (select score from score where name=t1);

 

4.所有部門之間的比賽組合

一個叫department的表,裏面只有一個字段name,一共有4條紀錄,分別是a,b,c,d,對應四個球對,現在四個球對進行比賽,用一條sql語句顯示所有可能的比賽組合.

答:select a.name, b.name 
from team a, team b 
where a.name < b.name

 

4.每個月份的發生額都比101科目多的科目

請用SQL語句實現:從TestDB數據表中查詢出所有月份的發生額都比101科目相應月份的發生額高的科目。請注意:TestDB中有很多科目,都有112月份的發生額。
AccID:科目代碼,Occmonth:發生額月份,DebitOccur:發生額。
數據庫名:JcyAudit,數據集:Select * from TestDB

準備數據的sql代碼:

drop table if exists TestDB;

create table TestDB(id int primary key auto_increment,AccID varchar(20), Occmonth date, DebitOccur bigint);

insert into TestDB values 

(null,'101','1988-1-1',100),

(null,'101','1988-2-1',110),

(null,'101','1988-3-1',120),

(null,'101','1988-4-1',100),

(null,'101','1988-5-1',100),

(null,'101','1988-6-1',100),

(null,'101','1988-7-1',100),

(null,'101','1988-8-1',100);

--複製上面的數據,故意把第一個月份的發生額數字改小一點

insert into TestDB values 

(null,'102','1988-1-1',90),

(null,'102','1988-2-1',110),

(null,'102','1988-3-1',120),

(null,'102','1988-4-1',100),

(null,'102','1988-5-1',100),

(null,'102','1988-6-1',100),

(null,'102','1988-7-1',100),

(null,'102','1988-8-1',100);

--複製最上面的數據,故意把所有發生額數字改大一點

insert into TestDB values 

(null,'103','1988-1-1',150),

(null,'103','1988-2-1',160),

(null,'103','1988-3-1',180),

(null,'103','1988-4-1',120),

(null,'103','1988-5-1',120),

(null,'103','1988-6-1',120),

(null,'103','1988-7-1',120),

(null,'103','1988-8-1',120);

--複製最上面的數據,故意把所有發生額數字改大一點

insert into TestDB values 

(null,'104','1988-1-1',130),

(null,'104','1988-2-1',130),

(null,'104','1988-3-1',140),

(null,'104','1988-4-1',150),

(null,'104','1988-5-1',160),

(null,'104','1988-6-1',170),

(null,'104','1988-7-1',180),

(null,'104','1988-8-1',140);

--複製最上面的數據,故意把第二個月份的發生額數字改小一點

insert into TestDB values 

(null,'105','1988-1-1',100),

(null,'105','1988-2-1',80),

(null,'105','1988-3-1',120),

(null,'105','1988-4-1',100),

(null,'105','1988-5-1',100),

(null,'105','1988-6-1',100),

(null,'105','1988-7-1',100),

(null,'105','1988-8-1',100);

答案:
select distinct AccID from TestDB 

where AccID not in 

(select TestDB.AccIDfrom TestDB,

 (select * from TestDB where AccID='101') as db101 

where TestDB.Occmonth=db101.Occmonth and TestDB.DebitOccur<=db101.DebitOccur

);

 

4.統計每年每月的信息

year  month amount
1991   1     1.1
1991   2     1.2
1991   3     1.3
1991   4     1.4
1992   1     2.1
1992   2     2.2
1992   3     2.3
1992   4     2.4
查成這樣一個結果
year m1  m2  m3  m4
1991 1.1 1.2 1.3 1.4
1992 2.1 2.2 2.3 2.4 

提示:這個與工資條非常類似,與學生的科目成績也很相似。

 

準備sql語句:

drop table if exists sales;

create table sales(id int auto_increment primary key,year varchar(10), month varchar(10), amount float(2,1));

insert into sales values

(null,'1991','1',1.1),

(null,'1991','2',1.2),

(null,'1991','3',1.3),

(null,'1991','4',1.4),

(null,'1992','1',2.1),

(null,'1992','2',2.2),

(null,'1992','3',2.3),

(null,'1992','4',2.4);


答案一、
select sales.year ,

(select t.amount from sales t where t.month='1' and t.year= sales.year) '1',

(select t.amount from sales t where t.month='1' and t.year= sales.year) '2',

(select t.amount from sales t where t.month='1' and t.year= sales.year) '3',

(select t.amount from sales t where t.month='1' and t.year= sales.year) as '4' 

from sales  group by year;

 

5.顯示文章標題,發帖人、最後回覆時間

表:id,title,postuser,postdate,parentid

準備sql語句:

drop table if exists articles;

create table articles(id int auto_increment primary key,title varchar(50), postuser varchar(10), postdate datetime,parentid int references articles(id));

insert into articles values

(null,'第一條','張三','1998-10-10 12:32:32',null),

(null,'第二條','張三','1998-10-10 12:34:32',null),

(null,'第一條回覆1','李四','1998-10-10 12:35:32',1),

(null,'第二條回覆1','李四','1998-10-10 12:36:32',2),

(null,'第一條回覆2','王五','1998-10-10 12:37:32',1),

(null,'第一條回覆3','李四','1998-10-10 12:38:32',1),

(null,'第二條回覆2','李四','1998-10-10 12:39:32',2),

(null,'第一條回覆4','王五','1998-10-10 12:39:40',1);

 

答案:

select a.title,a.postuser,

(select max(postdate) from articles where parentid=a.id) reply 

from articles a where a.parentid is null;

 

註釋:子查詢可以用在選擇列中,也可用於where的比較條件中,還可以用於from從句中。

3.刪除除了id號不同,其他都相同的學生冗餘信息

2.學生表 如下:
id號   學號   姓名 課程編號 課程名稱 分數
1        2005001  張三  0001      數學    69
2        2005002  李四  0001      數學    89
3        2005001  張三  0001      數學    69
A: delete from tablename where id號 not in(select min(id) from tablename group by 學號,姓名,課程編號,課程名稱,分數)

實驗:

create table student2(id int auto_increment primary key,code varchar(20),name varchar(20));

insert into student2 values(null,'2005001','張三'),(null,'2005002','李四'),(null,'2005001','張三');

 

//如下語句,mysql報告錯誤,可能刪除依賴後面統計語句,而刪除又導致統計語句結果不一致。

 

delete from student2 where id not in(select min(id) from student2 group by name);

//但是,如下語句沒有問題:

select *  from student2 where id not in(select min(id) from student2 group by name);

//於是,我想先把分組的結果做成虛表,然後從虛表中選出結果,最後再將結果作爲刪除的條件數據。

delete from student2 where id not in(select mid from (select min(id) mid

from student2 group by name) as t);

或者:

delete from student2 where id not in(select min(id) from (select * from s

tudent2) as t group by t.name);

4.航空網的幾個航班查詢題:

表結構如下:

flight{flightID,StartCityID ,endCityID,StartTime}

city{cityID, CityName)

實驗環境:

create table city(cityID int auto_increment primary key,cityName varchar(20));

create table flight (flightID int auto_increment primary key,

StartCityID int references city(cityID),

endCityID  int references city(cityID),

StartTime timestamp); 

//航班本來應該沒有日期部分纔好,但是下面的題目當中涉及到了日期

insert into city values(null,'北京'),(null,'上海'),(null,'廣州');

insert into flight values

(null,1,2,'9:37:23'),(null,1,3,'9:37:23'),(null,1,2,'10:37:23'),(null,2,3,'10:37:23');

 

 

1、查詢起飛城市是北京的所有航班,按到達城市的名字排序

 

 

參與運算的列是我起碼能夠顯示出來的那些列,但最終我不一定把它們顯示出來。各個表組合出來的中間結果字段中必須包含所有運算的字段。

 

  select  * from flight f,city c 

where f.endcityid = c.cityid and startcityid = 

(select c1.cityid from city c1 where c1.cityname = "北京")

order by c.cityname asc;

 

mysql> select flight.flightid,'北京' startcity, e.cityname from flight,city e wh

ere flight.endcityid=e.cityid and flight.startcityid=(select cityid from city wh

ere cityname='北京');

 

mysql> select flight.flightid,s.cityname,e.cityname from flight,city s,city e wh

ere flight.startcityid=s.cityid and s.cityname='北京' and flight.endCityId=e.cit

yID order by e.cityName desc;

 

 

2、查詢北京到上海的所有航班紀錄(起飛城市,到達城市,起飛時間,航班號)

select c1.CityName,c2.CityName,f.StartTime,f.flightID

from city c1,city c2,flight f

where f.StartCityID=c1.cityID 

and f.endCityID=c2.cityID

and c1.cityName='北京'

and c2.cityName='上海'

3、查詢具體某一天(2005-5-8)的北京到上海的的航班次數

select count(*) from 

(select c1.CityName,c2.CityName,f.StartTime,f.flightID

from city c1,city c2,flight f

where f.StartCityID=c1.cityID 

and f.endCityID=c2.cityID

and c1.cityName='北京'

and c2.cityName='上海'

and 查幫助獲得的某個日期處理函數(startTime) like '2005-5-8%'

 

mysql中提取日期部分進行比較的示例代碼如下:

select * from flight where date_format(starttime,'%Y-%m-%d')='1998-01-02'

5.查出比經理薪水還高的員工信息:

Drop table if not exists employees;

create table employees(id int primary key auto_increment,name varchar(50)

,salary int,managerid int references employees(id));

insert into employees values (null,' lhm',10000,null), (null,' zxx',15000,1

),(null,'flx',9000,1),(null,'tg',10000,2),(null,'wzg',10000,3);

 

Wzg大於flx,lhm大於zxx

 

解題思路:

     根據sql語句的查詢特點,是逐行進行運算,不可能兩行同時參與運算。

涉及了員工薪水和經理薪水,所有,一行記錄要同時包含兩個薪水,所有想到要把這個表自關聯組合一下。

     首先要組合出一個包含有各個員工及該員工的經理信息的長記錄,譬如,左半部分是員工,右半部分是經理。而迪卡爾積會組合出很多垃圾信息,先去除這些垃圾信息。

 

select e.* from employees e,employees m where e.managerid=m.id and e.sala

ry>m.salary;

6、求出小於45歲的各個老師所帶的大於12歲的學生人數

數據庫中有3個表 teacher 表,student表,tea_stu關係表。 
teacher 表 teaID name age 
student 表 stuID name age 
teacher_student表 teaID stuID 
要求用一條sql查詢出這樣的結果 
1.顯示的字段要有老師name, age 每個老師所帶的學生人數 
只列出老師age40以下,學生age12以上的記錄

預備知識:

      1.sql語句是對每一條記錄依次處理,條件爲真則執行動作(select,insert,delete,update

       2.只要是迪卡爾積,就會產生“垃圾”信息,所以,只要迪卡爾積了,我們首先就要想到清除“垃圾”信息

實驗準備:

drop table if exists tea_stu;

drop table if exists teacher;

drop table if exists student;

      create table teacher(teaID int primary key,name varchar(50),age int);

      create table student(stuID int primary key,name varchar(50),age int);

      create table tea_stu(teaID int references teacher(teaID),stuID int references student(stuID));

insert into teacher values(1,'zxx',45), (2,'lhm',25) , (3,'wzg',26) , (4,'tg',27);

insert into student values(1,'wy',11), (2,'dh',25) , (3,'ysq',26) , (4,'mxc',27);

insert into tea_stu values(1,1), (1,2), (1,3);

insert into tea_stu values(2,2), (2,3), (2,4);

 insert into tea_stu values(3,3), (3,4), (3,1);

insert into tea_stu values(4,4), (4,1), (4,2) , (4,3);

 

結果:2à3,3à2,4à3

 

解題思路:(真實面試答題時,也要寫出每個分析步驟,如果紙張不夠,就找別人要)

1要會統計分組信息,統計信息放在中間表中:

select teaid,count(*) from tea_stu group by teaid;

 

2接着其實應該是篩除掉小於12歲的學生,然後再進行統計,中間表必須與student關聯才能得到12歲以下學生和把該學生記錄從中間表中剔除,代碼是:

select tea_stu.teaid,count(*) total from student,tea_stu 

where student.stuid=tea_stu.stuid and student.age>12 group by tea_stu.teaid

 

3.接着把上面的結果做成虛表與teacher進行關聯,並篩除大於45的老師

select teacher.teaid,teacher.name,total from teacher ,(select tea_stu.tea

id,count(*) total from student,tea_stu where student.stuid=tea_stu.stuid and stu

dent.age>12 group by tea_stu.teaid) as tea_stu2 where teacher.teaid=tea_stu2.tea

id and teacher.age<45;

 

 

7.求出發帖最多的人:

select authorid,count(*) total from articles 

group by authorid 

having total=

(select max(total2) from (select count(*) total2 from articles group by authorid) as t);

 

select t.authorid,max(t.total) from

(select authorid,count(*) total from articles )as t

這條語句不行,因爲max只有一列,不能與其他列混淆。

 

select authorid,count(*) total from articles 

group by authorid having total=max(total)也不行。

 

10、一個用戶表中有一個積分字段,假如數據庫中有100多萬個用戶,若要在每年第一天凌晨將積分清零,你將考慮什麼,你將想什麼辦法解決?

alter table drop column score;

alter table add colunm score int;

可能會很快,但是需要試驗,試驗不能拿真實的環境來操刀,並且要注意,

這樣的操作時無法回滾的,在我的印象中,只有inert update deleteDML語句才能回滾,

對於create table,drop table ,alter tableDDL語句是不能回滾。

 

 

解決方案一,update user set score=0; 

解決方案二,假設上面的代碼要執行好長時間,超出我們的容忍範圍,那我就alter table user drop column score;alter table user add column score int

 

下面代碼實現每年的那個凌晨時刻進行清零。

Runnable runnable = 

new Runnable(){

public void run(){

clearDb();

schedule(this,new Date(new Date().getYear()+1,0,0));

}

};

 

schedule(runnable,

new Date(new Date().getYear()+1,0,1));

 

10、一個用戶具有多個角色,請查詢出該表中具有該用戶的所有角色的其他用戶。

select count(*) as num,tb.id 

from 

 tb,

 (select role from tb where id=xxx) as t1

where

 tb.role = t1.role and tb.id != t1.id

group by tb.id 

having 

num = select count(role) from tb where id=xxx;

8. xxx公司的sql面試

Table EMPLOYEES Structure:

EMPLOYEE_ID      NUMBER        Primary Key,

FIRST_NAME       VARCHAR2(25),

LAST_NAME       VARCHAR2(25),

Salary number(8,2),

HiredDate DATE,

Departmentid number(2)

Table Departments Structure:

Departmentid number(2)        Primary Key,

DepartmentName  VARCHAR2(25).

 

 (2)基於上述EMPLOYEES表寫出查詢:寫出僱用日期在今年的,或者工資在[1000,2000]之間的,或者員工姓名(last_name)以’Obama’打頭的所有員工,列出這些員工的全部個人信息。(4分)

select * from employees 

where Year(hiredDate) = Year(date()) 

or (salary between 1000 and 200)

or left(last_name,3)='abc';

 

(3) 基於上述EMPLOYEES表寫出查詢:查出部門平均工資大於1800元的部門的所有員工,列出這些員工的全部個人信息。4分)

mysql> select id,name,salary,deptid did from employee1 where (select avg(salary)

 from employee1 where deptid = did) > 1800;

 

(4) 基於上述EMPLOYEES表寫出查詢:查出個人工資高於其所在部門平均工資的員工,列出這些員工的全部個人信息及該員工工資高出部門平均工資百分比。(5分)

select employee1.*,(employee1.salary-t.avgSalary)*100/employee1.salary 

from employee1,

(select deptid,avg(salary) avgSalary from employee1 group by deptid) as t

where employee1.deptid = t.deptid and employee1.salary>t.avgSalary;

 

1、註冊Jdbc驅動程序的三種方式

 

1、用JDBC如何調用存儲過程

代碼如下:

package com.huawei.interview.lym;

 

import java.sql.CallableStatement;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.sql.Types;

 

public class JdbcTest {

 

/**

 * @param args

 */

public static void main(String[] args) {

// TODO Auto-generated method stub

Connection cn = null;

CallableStatement cstmt = null;

try {

//這裏最好不要這麼幹,因爲驅動名寫死在程序中了

Class.forName("com.mysql.jdbc.Driver");

//實際項目中,這裏應用DataSource數據,如果用框架,

//這個數據源不需要我們編碼創建,我們只需Datasource ds = context.lookup()

//cn = ds.getConnection();

cn = DriverManager.getConnection("jdbc:mysql:///test","root","root");

cstmt = cn.prepareCall("{call insert_Student(?,?,?)}");

cstmt.registerOutParameter(3,Types.INTEGER);

cstmt.setString(1, "wangwu");

cstmt.setInt(2, 25);

cstmt.execute();

//get第幾個,不同的數據庫不一樣,建議不寫

System.out.println(cstmt.getString(3));

catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

finally

{

 

/*try{cstmt.close();}catch(Exception e){}

try{cn.close();}catch(Exception e){}*/

try {

if(cstmt != null)

cstmt.close();

if(cn != null)

cn.close();

catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

1JDBC中的PreparedStatement相比Statement的好處

答:一個sql命令發給服務器去執行的步驟爲:語法檢查,語義分析,編譯成內部指令,緩存指令,執行指令等過程。

select * from student where id =3----緩存--àxxxxx二進制命令

select * from student where id =3----直接取-àxxxxx二進制命令

select * from student where id =4--- -à會怎麼幹?

如果當初是select * from student where id =?--- -à又會怎麼幹?

 上面說的是性能提高

可以防止sql注入。

1. 寫一個用jdbc連接並訪問oracle數據的程序代碼

2Class.forName的作用?爲什麼要用

答:按參數中指定的字符串形式的類名去搜索並加載相應的類,如果該類字節碼已經被加載過,則返回代表該字節碼的Class實例對象,否則,按類加載器的委託機制去搜索和加載該類,如果所有的類加載器都無法加載到該類,則拋出ClassNotFoundException。加載完這個Class字節碼後,接着就可以使用Class字節碼的newInstance方法去創建該類的實例對象了。

有時候,我們程序中所有使用的具體類名在設計時(即開發時)無法確定,只有程序運行時才能確定,這時候就需要使用Class.forName去動態加載該類,這個類名通常是在配置文件中配置的,例如,springioc中每次依賴注入的具體類就是這樣配置的,jdbc的驅動類名通常也是通過配置文件來配置的,以便在產品交付使用後不用修改源程序就可以更換驅動類名。

3、大數據量下的分頁解決方法。

答:最好的辦法是利用sql語句進行分頁,這樣每次查詢出的結果集中就只包含某頁的數據內容。再sql語句無法實現分頁的情況下,可以考慮對大的結果集通過遊標定位方式來獲取某頁的數據。

sql語句分頁,不同的數據庫下的分頁方案各不一樣,下面是主流的三種數據庫的分頁sql

sql server:

String sql = 

"select top " + pageSize + " * from students where id not in" +

 

 "(select top " + pageSize * (pageNumber-1) + " id from students order by id)" + 

 

 "order by id";

 

mysql:

  

String sql = 

"select * from students order by id limit " + pageSize*(pageNumber-1) + "," + pageSize;

oracle:

 

String sql = 

 "select * from " +  

 (select *,rownum rid from (select * from students order by postime desc) where rid<=" + pagesize*pagenumber + ") as t" + 

 "where t>" + pageSize*(pageNumber-1);

4用 JDBC 查詢學生成績單把主要代碼寫出來考試概率極大). 

Connection cn = null;

PreparedStatement pstmt =null;

Resultset rs = null;

try

{

Class.forname(driveClassName);

cn =  DriverManager.getConnection(url,username,password);

pstmt = cn.prepareStatement(“select  score.* from score ,student “ + 

“where score.stuId = student.id and student.name = ?”);

pstmt.setString(1,studentName);

Resultset rs = pstmt.executeQuery();

while(rs.next())

{

system.out.println(rs.getInt(“subject”)  +  “    ” + rs.getFloat(“score”) );

}

}catch(Exception e){e.printStackTrace();}

finally

{

if(rs != null) try{ rs.close() }catch(exception e){}

if(pstmt != null) try{pstmt.close()}catch(exception e){}

if(cn != null) try{ cn.close() }catch(exception e){}

}

 

 

5這段代碼有什麼不足之處

try {
Connection conn = ...;
Statement stmt = ...;

ResultSet rs = stmt.executeQuery("select * from table1");

while(rs.next()) {

}
} catch(Exception ex) {

答:沒有finally語句來關閉各個對象,另外,使用finally之後,要把變量的定義放在try語句塊的外面,以便在try語句塊之外的finally塊中仍可以訪問這些變量。

 

36、說出數據連接池的工作機制是什麼

J2EE服務器啓動時會建立一定數量的池連接,並一直維持不少於此數目的池連接。客戶端程序需要連接時,池驅動程序會返回一個未使用的池連接並將其表記爲忙。如果當前沒有空閒連接,池驅動程序就新建一定數量的連接,新建連接的數量有配置參數決定。當使用的池連接調用完成後,池驅動程序將此連接表記爲空閒,其他調用就可以使用這個連接。 

實現方式,返回的Connection是原始Connection的代理,代理Connectionclose方法不是真正關連接,而是把它代理的Connection對象還回到連接池中。

 

4爲什麼要用 ORM?  和 JDBC 有何不一樣

orm是一種思想,就是把object轉變成數據庫中的記錄,或者把數據庫中的記錄轉變成objecdt,我們可以用jdbc來實現這種思想,其實,如果我們的項目是嚴格按照oop方式編寫的話,我們的jdbc程序不管是有意還是無意,就已經在實現orm的工作了。

現在有許多orm工具,它們底層調用jdbc來實現了orm工作,我們直接使用這些工具,就省去了直接使用jdbc的繁瑣細節,提高了開發效率,現在用的較多的orm工具是hibernate。也聽說一些其他orm工具,如toplink,ojb等。 

5. XML部分

1xml有哪些解析技術?區別是什麼

:DOM,SAX,STAX等 

DOM:處理大型文件時其性能下降的非常厲害。這個問題是由DOM的樹結構所造成的,這種結構佔用的內存較多,而且DOM必須在解析文件之前把整個文檔裝入內存,適合對XML的隨機訪問SAX:不現於DOM,SAX是事件驅動型的XML解析方式。它順序讀取XML文件,不需要一次全部裝載整個文件。當遇到像文件開頭,文檔結束,或者標籤開頭與標籤結束時,它會觸發一個事件,用戶通過在其回調事件中寫入處理代碼來處理XML文件,適合對XML的順序訪問 

STAX:Streaming API for XML (StAX) 

講解這些區別是不需要特別去比較,就像說傳智播客與其他培訓機構的區別時,我們只需說清楚傳智播客有什麼特點和優點就行了,這就已經間接回答了彼此的區別。

 

2、你在項目中用到了xml技術的哪些方面?如何實現的

:用到了數據存貯,信息配置兩方面。在做數據交換平臺時,將不能數據源的數據組裝成XML文件,然後將XML文件壓縮打包加密後通過網絡傳送給接收者,接收解密與解壓縮後再同XML文件中還原相關信息進行處理。在做軟件配置時,利用XML可以很方便的進行,軟件的各種配置參數都存貯在XML文件中。 

3、用jdom解析xml文件時如何解決中文問題?如何解析

:看如下代碼,用編碼方式加以解決 
package test; 
import java.io.*; 
public class DOMTest 

private String inFile = "c:\\people.xml" 
private String outFile = "c:\\people.xml" 
public static void main(String args[]) 

new DOMTest(); 

public DOMTest() 

try 

javax.xml.parsers.DocumentBuilder builder = 

javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder(); 
org.w3c.dom.Document doc = builder.newDocument(); 
org.w3c.dom.Element root = doc.createElement("老師"); 
org.w3c.dom.Element wang = doc.createElement(""); 
org.w3c.dom.Element liu = doc.createElement(""); 
wang.appendChild(doc.createTextNode("我是王老師")); 
root.appendChild(wang); 
doc.appendChild(root); 
javax.xml.transform.Transformer transformer = 
javax.xml.transform.TransformerFactory.newInstance().newTransformer(); 
transformer.setOutputProperty(javax.xml.transform.OutputKeys.ENCODING, "gb2312"); 
transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes"); 

transformer.transform(new javax.xml.transform.dom.DOMSource(doc), 
new 

javax.xml.transform.stream.StreamResult(outFile)); 

catch (Exception e) 

System.out.println (e.getMessage()); 


4、編程用JAVA解析XML的方式

:SAX方式解析XMLXML文件如下: 

<?xml version=1.0 encoding=gb2312?> 

<person> 

<name>王小明</name> 

<college>信息學院</college> 

<telephone>6258113</telephone> 

<notes>,1955年生,博士,95年調入海南大學</notes> 

</person> 

事件回調類SAXHandler.java 

import java.io.*; 

import java.util.Hashtable; 

import org.xml.sax.*; 

public class SAXHandler extends HandlerBase 

private Hashtable table = new Hashtable(); 

private String currentElement = null; 

private String currentValue = null; 

public void setTable(Hashtable table) 

this.table = table; 

public Hashtable getTable() 

return table; 

public void startElement(String tag, AttributeList attrs) 

throws SAXException 

currentElement = tag; 

public void characters(char[] ch, int start, int length) 

throws SAXException 

currentValue = new String(ch, start, length); 

public void endElement(String name) throws SAXException 

if (currentElement.equals(name)) 

table.put(currentElement, currentValue); 

 

JSP內容顯示源碼,SaxXml.jsp: 

<HTML> 

<HEAD> 

<TITLE>剖析XML文件people.xml</TITLE> 

</HEAD> 

<BODY> 

<%@ page errorPage=ErrPage.jsp 

contentType=text/html;charset=GB2312 %> 

<%@ page import=java.io.* %> 

<%@ page import=java.util.Hashtable %> 

<%@ page import=org.w3c.dom.* %> 

<%@ page import=org.xml.sax.* %> 

<%@ page import=javax.xml.parsers.SAXParserFactory %> 

<%@ page import=javax.xml.parsers.SAXParser %> 

<%@ page import=SAXHandler %> 

<% 

File file = new File(c:\people.xml); 

FileReader reader = new FileReader(file); 

Parser parser; 

SAXParserFactory spf = SAXParserFactory.newInstance(); 

SAXParser sp = spf.newSAXParser(); 

SAXHandler handler = new SAXHandler(); 

sp.parse(new InputSource(reader), handler); 

Hashtable hashTable = handler.getTable(); 

out.println(<TABLE BORDER=2><CAPTION>教師信息表</CAPTION>); 

out.println(<TR><TD>姓名</TD> + <TD> + 

(String)hashTable.get(new String(name)) + </TD></TR>); 

out.println(<TR><TD>學院</TD> + <TD> + 

(String)hashTable.get(new String(college))+</TD></TR>); 

out.println(<TR><TD>電話</TD> + <TD> + 

(String)hashTable.get(new String(telephone)) + </TD></TR>); 

out.println(<TR><TD>備註</TD> + <TD> + 

(String)hashTable.get(new String(notes)) + </TD></TR>); 

out.println(</TABLE>); 

%> 

</BODY> 

</HTML> 

70XML文檔定義有幾種形式?它們之間有何本質區別?解析XML文檔有哪幾種方式? 

a: 兩種形式 dtd  schemab: 本質區別:schema本身是xml的,可以被XML解析器解析(這也是從DTD上發展schema的根本目的)c:DOM,SAX,STAX等 

   DOM:處理大型文件時其性能下降的非常厲害。這個問題是由DOM的樹結構所造成的,這種結構佔用的內存較多,而且DOM必須在解析文件之前把整個文檔裝入內存,適合對XML的隨機訪問 

SAX:不現於DOM,SAX是事件驅動型的XML解析方式。它順序讀取XML文件,不需要一次全部裝載整個文件。當遇到像文件開頭,文檔結束,或者標籤開頭與標籤結束時,它會觸發一個事件,用戶通過在其回調事件中寫入處理代碼來處理XML文件,適合對XML的順序訪問 

   STAX:Streaming API for XML (StAX) 

 

5. 流行的框架與新技術

 

1談談你對Struts理解。

: 

1. struts是一個按MVC模式設計的Web層框架,其實它就是一個大大的servlet,這個Servlet名爲ActionServlet,或是ActionServlet的子類。我們可以在web.xml文件中將符合某種特徵的所有請求交給這個Servlet處理,這個Servlet再參照一個配置文件(通常爲/WEB-INF/struts-config.xml)將各個請求分別分配給不同的action去處理。

一個擴展知識點:struts的配置文件可以有多個,可以按模塊配置各自的配置文件,這樣可以防止配置文件的過度膨脹;

2. ActionServlet把請求交給action去處理之前,會將請求參數封裝成一個formbean對象(就是一個java類,這個類中的每個屬性對應一個請求參數),封裝成一個什麼樣的formbean對象呢?看配置文件。

3.要說明的是, ActionServlet把formbean對象傳遞給action的execute方法之前,可能會調用formbean的validate方法進行校驗,只有校驗通過後纔將這個formbean對象傳遞給action的execute方法,否則,它將返回一個錯誤頁面,這個錯誤頁面由input屬性指定,(看配置文件)作者爲什麼將這裏命名爲input屬性,而不是error屬性,我們後面結合實際的運行效果進行分析。

4.action執行完後要返回顯示的結果視圖,這個結果視圖是用一個ActionForward對象來表示的,actionforward對象通過struts-config.xml配置文件中的配置關聯到某個jsp頁面,因爲程序中使用的是在struts-config.xml配置文件爲jsp頁面設置的邏輯名,這樣可以實現action程序代碼與返回的jsp頁面名稱的解耦。

 

你對struts可能還有自己的應用方面的經驗,那也要一併說出來。

2談談你對Hibernate的理解。

:

1. 面向對象設計的軟件內部運行過程可以理解成就是在不斷創建各種新對象、建立對象之間的關係,調用對象的方法來改變各個對象的狀態和對象消亡的過程,不管程序運行的過程和操作怎麼樣,本質上都是要得到一個結果,程序上一個時刻和下一個時刻的運行結果的差異就表現在內存中的對象狀態發生了變化。

2.爲了在關機和內存空間不夠的狀況下,保持程序的運行狀態,需要將內存中的對象狀態保存到持久化設備和從持久化設備中恢復出對象的狀態,通常都是保存到關係數據庫來保存大量對象信息。從Java程序的運行功能上來講,保存對象狀態的功能相比系統運行的其他功能來說,應該是一個很不起眼的附屬功能,java採用jdbc來實現這個功能,這個不起眼的功能卻要編寫大量的代碼,而做的事情僅僅是保存對象和恢復對象,並且那些大量的jdbc代碼並沒有什麼技術含量,基本上是採用一套例行公事的標準代碼模板來編寫,是一種苦活和重複性的工作。

3.通過數據庫保存java程序運行時產生的對象和恢復對象,其實就是實現了java對象與關係數據庫記錄的映射關係,稱爲ORM(即Object Relation Mapping),人們可以通過封裝JDBC代碼來實現了這種功能,封裝出來的產品稱之爲ORM框架,Hibernate就是其中的一種流行ORM框架。使用Hibernate框架,不用寫JDBC代碼,僅僅是調用一個save方法,就可以將對象保存到關係數據庫中,僅僅是調用一個get方法,就可以從數據庫中加載出一個對象。

4.使用Hibernate的基本流程是:配置Configuration對象、產生SessionFactory、創建session對象,啓動事務,完成CRUD操作,提交事務,關閉session

5.使用Hibernate時,先要配置hibernate.cfg.xml文件,其中配置數據庫連接信息和方言等,還要爲每個實體配置相應的hbm.xml文件,hibernate.cfg.xml文件中需要登記每個hbm.xml文件。

6.在應用Hibernate時,重點要了解Session的緩存原理,級聯,延遲加載和hql查詢。

3AOP的作用

3、你對Spring的理解。

1.Spring實現了工廠模式的工廠類(在這裏有必要解釋清楚什麼是工廠模式),這個類名爲BeanFactory(實際上是一個接口),在程序中通常BeanFactory的子類ApplicationContextSpring相當於一個大的工廠類,在其配置文件中通過<bean>元素配置用於創建實例對象的類名和實例對象的屬性。

2. Spring提供了對IOC良好支持,IOC是一種編程思想,是一種架構藝術,利用這種思想可以很好地實現模塊之間的解耦。IOC也稱爲DIDepency Injection),什麼叫依賴注入呢?

譬如,Class Programmer

{

Computer computer = null;

public void code()

{

//Computer computer = new IBMComputer();

//Computer computer = beanfacotry.getComputer();

computer.write();

}

public void setComputer(Computer computer)

{

this.computer = computer;

}

}
另外兩種方式都由依賴,第一個直接依賴於目標類,第二個把依賴轉移到工廠上,第三個徹底與目標和工廠解耦了。在spring的配置文件中配置片段如下:

<bean id=”computer” class=”cn.itcast.interview.Computer”>

</bean>

 

<bean id=”programmer” class=”cn.itcast.interview.Programmer”>

<property name=”computer”  ref=”computer”></property>

</bean>

3. Spring提供了對AOP技術的良好封裝, AOP稱爲面向切面編程,就是系統中有很多各不相干的類的方法,在這些衆多方法中要加入某種系統功能的代碼,例如,加入日誌,加入權限判斷,加入異常處理,這種應用稱爲AOP。實現AOP功能採用的是代理技術,客戶端程序不再調用目標,而調用代理類,代理類與目標類對外具有相同的方法聲明,有兩種方式可以實現相同的方法聲明,一是實現相同的接口,二是作爲目標的子類在,JDK中採用Proxy類產生動態代理的方式爲某個接口生成實現類,如果要爲某個類生成子類,則可以用CGLI B。在生成的代理類的方法中加入系統功能和調用目標類的相應方法,系統功能的代理以Advice對象進行提供,顯然要創建出代理對象,至少需要目標類和Advice類。spring提供了這種支持,只需要在spring配置文件中配置這兩個元素即可實現代理和aop功能,例如,

<bean id=”proxy” type=”org.spring.framework.aop.ProxyBeanFactory”>

<property name=”target” ref=””></property>

<property name=”advisor” ref=””></property>

 

</bean>

 

11談談Struts中的Action servlet

 

12Struts優缺點 
優點: 
 1. 實現MVC模式,結構清晰,使開發者只關注業務邏輯的實現.

2有豐富的tag可以用 ,Struts的標記庫(Taglib),如能靈活動用,則能大大提高開發效率

3. 頁面導航

使系統的脈絡更加清晰。通過一個配置文件,即可把握整個系統各部分之間的聯繫,這對於後期的維護有着莫大的好處。尤其是當另一批開發者接手這個項目時,這種優勢體現得更加明顯。

4. 提供Exception處理機制 

5. 數據庫鏈接池管理 

6. 支持I18N 

缺點

一、 轉到展示層時,需要配置forward,如果有十個展示層的jsp,需要配置十次struts,而且還不包括有時候目錄、文件變更,需要重新修改forward,注意,每次修改配置之後,要求重新部署整個項目,而tomcate這樣的服務器,還必須重新啓動服務器

二、 二、 Struts Action必需是threadsafe方式,它僅僅允許一個實例去處理所有的請求。所以action用到的所有的資源都必需統一同步,這個就引起了線程安全的問題。

三、  測試不方便. Struts的每個Action都同Web層耦合在一起,這樣它的測試依賴於Web容器,單元測試也很難實現。不過有一個Junit的擴展工具Struts TestCase可以實現它的單元測試。 

四、  類型的轉換. StrutsFormBean把所有的數據都作爲String類型,它可以使用工具Commons-Beanutils進行類型轉化。但它的轉化都是在Class級別,而且轉化的類型是不可配置的。類型轉化時的錯誤信息返回給用戶也是非常困難的。

五、 對Servlet的依賴性過強. Struts處理Action時必需要依賴ServletRequest ServletResponse,所有它擺脫不了Servlet容器。 

六、  前端表達式語言方面.Struts集成了JSTL,所以它主要使用JSTL的表達式語言來獲取數據。可是JSTL的表達式語言在Collection和索引屬性方面處理顯得很弱。 

七、  對Action執行的控制困難. Struts創建一個Action,如果想控制它的執行順序將會非常困難。甚至你要重新去寫Servlet來實現你的這個功能需求。 

八、  對Action 執行前和後的處理. Struts處理Action的時候是基於classhierarchies,很難在action處理前和後進行操作。 

九、  對事件支持不夠struts中,實際是一個表單Form對應一個Action(DispatchAction),換一句話說:在Struts中實際是一個表單只能 對應一個事件,struts這種事件方式稱爲application eventapplication eventcomponent event相比是一種粗粒度的事件

 

 

119STRUTS的應用(STRUTS架構

Struts是採用Java Servlet/JavaServer Pages技術,開發Web應用程序的開放源碼的framework。 採用Struts能開發出基於MVC(Model-View-Controller)設計模式的應用構架。 Struts有如下的主要功能: 一.包含一個controller servlet,能將用戶的請求發送到相應的Action對象。 二.JSP自由tag庫,並且在controller servlet中提供關聯支持,幫助開發員創建交互式表單應用。 三.提供了一系列實用對象:XML處理、通過Java reflection APIs自動處理JavaBeans屬性、國際化的提示和消息。

 

110、說說struts1struts2的區別

1.都是MVCWEB框架,

2 struts1的老牌框架,應用很廣泛,有很好的羣衆基礎,使用它開發風險很小,成本更低!struts2雖然基於這個框架,但是應用羣衆並多,相對不成熟,未知的風險和變化很多,開發人員相對不好招,使用它開發項目的風險係數更大,用人成本更高!

3.struts2畢竟是站在前輩的基礎設計出來,它會改善和完善struts1中的一些缺陷,struts1中一些懸而未決問題在struts2得到了解決。

4.struts1的前端控制器是一個Servlet,名稱爲ActionServletstruts2的前端控制器是一個filter,在struts2.0中叫FilterDispatcher,在struts2.1中叫StrutsPrepareAndExecuteFilter。

5.struts1action需要繼承Action類,struts2action可以不繼承任何類;struts1對同一個路徑的所有請求共享一個Action實例,struts2對同一個路徑的每個請求分別使用一個獨立Action實例對象,所有對於struts2Action不用考慮線程安全問題。

6.struts1中使用formbean封裝請求參數,在struts2中直接使用action的屬性來封裝請求參數。

7.struts1中的多個業務方法放在一個Action中時(即繼承DispatchAction時),要麼都校驗,要麼都不校驗;對於struts2,可以指定只對某個方法進行校驗,當一個Action繼承了ActionSupport且在這個類中只編寫了validateXxx()方法,那麼則只對Xxx()方法進行校驗。

 

(一個請求來了的執行流程進行分析,struts2是自動支持分模塊開發,並可以不同模塊設置不同的url前綴,這是通過packagenamespace來實現的;struts2是支持多種類型的視圖;struts2的視圖地址可以是動態的,即視圖的名稱是支持變量方式的,舉例,論壇發帖失敗後回來還要傳遞boardid。視圖內容顯示方面:它的標籤用ognl,要el強大很多,在國際化方面支持分模塊管理,兩個模塊用到同樣的key,對應不同的消息;)

 

Struts1不同,Struts2對用戶的每一次請求都會創建一個Action,所以Struts2中的Action是線程安全的。

 

給我印象最深刻的是:struts配置文件中的redirect視圖的url不能接受參數,而struts2配置文件中的redirect視圖可以接受參數。

 

 

110hibernate中的update()saveOrUpdate()的區別,sessionload()get()的區別。

110簡述 Hibernate 和 JDBC 的優缺點如何書寫一個 one to many 配置文件.

7、iBatisHibernate有什麼不同?

相同點:屏蔽jdbc api的底層訪問細節,使用我們不用與jdbc api打交道,就可以訪問數據。

jdbc api編程流程固定,還將sql語句與java代碼混雜在了一起,經常需要拼湊sql語句,細節很繁瑣。

ibatis的好處:屏蔽jdbc api的底層訪問細節;將sql語句與java代碼進行分離;提供了將結果集自動封裝稱爲實體對象和對象的集合的功能,queryForList返回對象集合,用queryForObject返回單個對象;提供了自動將實體對象的屬性傳遞給sql語句的參數。

 

Hibernate是一個全自動的orm映射工具,它可以自動生成sql語句,ibatis需要我們自己在xml配置文件中寫sql語句,hibernate要比ibatis功能負責和強大很多。因爲hibernate自動生成sql語句,我們無法控制該語句,我們就無法去寫特定的高效率的sql。對於一些不太複雜的sql查詢,hibernate可以很好幫我們完成,但是,對於特別複雜的查詢,hibernate就很難適應了,這時候用ibatis就是不錯的選擇,因爲ibatis還是由我們自己寫sql語句。

 

 

7、寫Hibernate的一對多和多對一雙向關聯的orm配置?

9hibernateinverse屬性的作用?

解決方案一,按照Object[]數據取出數據,然後自己組bean

解決方案二,對每個表的bean寫構造函數,比如表一要查出field1,field2兩個字段,那麼有一個構造函數就是Bean(type1 filed1,type2 

field2) ,然後在hql裏面就可以直接生成這個bean了。

 

10、在DAO中如何體現DAO設計模式?

解決方案一,按照Object[]數據取出數據,然後自己組bean

解決方案二,對每個表的bean寫構造函數,比如表一要查出field1,field2兩個字段,那麼有一個構造函數就是Bean(type1 filed1,type2 

field2) ,然後在hql裏面就可以直接生成這個bean了。

 

10spring+Hibernate中委託方案怎麼配置?

解決方案一,按照Object[]數據取出數據,然後自己組bean

解決方案二,對每個表的bean寫構造函數,比如表一要查出field1,field2兩個字段,那麼有一個構造函數就是Bean(type1 filed1,type2 

field2) ,然後在hql裏面就可以直接生成這個bean了。

 

10spring+Hibernate中委託方案怎麼配置?

解決方案一,按照Object[]數據取出數據,然後自己組bean

解決方案二,對每個表的bean寫構造函數,比如表一要查出field1,field2兩個字段,那麼有一個構造函數就是Bean(type1 filed1,type2 

field2) ,然後在hql裏面就可以直接生成這個bean了。

 

8. hibernate進行多表查詢每個表中各取幾個字段,也就是說查詢出來的結果集沒有一個實體類與之對應如何解決; 

 

解決方案一,按照Object[]數據取出數據,然後自己組bean

解決方案二,對每個表的bean寫構造函數,比如表一要查出field1,field2兩個字段,那麼有一個構造函數就是Bean(type1 filed1,type2 

field2) ,然後在hql裏面就可以直接生成這個bean了。

8.介紹一下Hibernate的二級緩存

按照以下思路來回答:(1)首先說清楚什麼是緩存,(2)再說有了hibernateSession就是一級緩存,即有了一級緩存,爲什麼還要有二級緩存,(3)最後再說如何配置Hibernate的二級緩存。

1)緩存就是把以前從數據庫中查詢出來和使用過的對象保存在內存中(一個數據結構中),這個數據結構通常是或類似Hashmap,當以後要使用某個對象時,先查詢緩存中是否有這個對象,如果有則使用緩存中的對象,如果沒有則去查詢數據庫,並將查詢出來的對象保存在緩存中,以便下次使用。下面是緩存的僞代碼:

引出hibernate的第二級緩存,用下面的僞代碼分析了Cache的實現原理

Dao

{

hashmap map = new map();

User getUser(integer id)

{

User user = map.get(id)

if(user == null)

{

user = session.get(id);

map.put(id,user);

}

return user;

}

}

 

Dao

{

Cache cache = null

setCache(Cache cache)

{

this.cache = cache

}

User getUser(int id)

{

if(cache!=null)

{

User user = cache.get(id);

if(user ==null)

{

user = session.get(id);

cache.put(id,user);

}

return user;

}

return session.get(id);

}

}

2HibernateSession就是一種緩存,我們通常將之稱爲Hibernate的一級緩存,當想使用session從數據庫中查詢出一個對象時,Session也是先從自己內部查看是否存在這個對象,存在則直接返回,不存在纔去訪問數據庫,並將查詢的結果保存在自己內部。由於Session代表一次會話過程,一個Session與一個數據庫連接相關連,所以Session最好不要長時間保持打開,通常僅用於一個事務當中,在事務結束時就應關閉。並且Session是線程不安全的,被多個線程共享時容易出現問題。通常只有那種全局意義上的緩存纔是真正的緩存應用,纔有較大的緩存價值,因此,HibernateSession這一級緩存的緩存作用並不明顯,應用價值不大。Hibernate的二級緩存就是要爲Hibernate配置一種全局緩存,讓多個線程和多個事務都可以共享這個緩存。我們希望的是一個人使用過,其他人也可以使用,session沒有這種效果。

3)二級緩存是獨立於Hibernate的軟件部件,屬於第三方的產品,多個廠商和組織都提供有緩存產品,例如,EHCacheOSCache等等。在Hibernate中使用二級緩存,首先就要在hibernate.cfg.xml配置文件中配置使用哪個廠家的緩存產品,接着需要配置該緩存產品自己的配置文件,最後要配置Hibernate中的哪些實體對象要納入到二級緩存的管理中。明白了二級緩存原理和有了這個思路後,很容易配置起Hibernate的二級緩存。擴展知識:一個SessionFactory可以關聯一個二級緩存,也即一個二級緩存只能負責緩存一個數據庫中的數據,當使用Hibernate 的二級緩存後,注意不要有其他的應用或SessionFactory來更改當前數據庫中的數據,這樣緩存的數據就會與數據庫中的實際數據不一致。 

 

111Spring 的依賴注入是什麼意思給一個 Bean 的 message 屬性字符串類型注入值爲 "Hello" 的 XML 配置文件該怎麼寫?

 

120Jdo是什麼

JDOJava對象持久化的新的規範,爲java data object的簡稱,也是一個用於存取某種數據倉庫中的對象的標準化APIJDO提供了透明的對象存儲,因此對開發人員來說,存儲數據對象完全不需要額外的代碼(如JDBC API的使用)。這些繁瑣的例行工作已經轉移到JDO產品提供商身上,使開發人員解脫出來,從而集中時間和精力在業務邏輯上。另外,JDO很靈活,因爲它可以在任何數據底層上運行。JDBC只是面向關係數據庫(RDBMSJDO更通用,提供到任何數據底層的存儲功能,比如關係數據庫、文件、XML以及對象數據庫(ODBMS)等等,使得應用可移植性更強。 

 

什麼是springIOC  AOP

STRUTS的工作流程!

spring EJB的區別!!

 

9. 軟件工程與設計模式

111UML方面 

標準建模語言UML。用例圖,靜態圖(包括類圖、對象圖和包圖),行爲圖,交互圖(順序圖,合作圖),實現圖。 

112. 軟件開發的

92j2ee常用的設計模式?說明工廠模式。 

總共23種,分爲三大類:創建型,結構型,行爲型

我只記得其中常用的67種,分別是:

創建型(工廠、工廠方法、抽象工廠、單例)

結構型(包裝、適配器,組合,代理)

行爲(觀察者,模版,策略)

然後再針對你熟悉的模式談談你的理解即可。   

 

Java中的23種設計模式: 

Factory(工廠模式),      Builder(建造模式),       Factory Method(工廠方法模式), 

Prototype(原始模型模式),Singleton(單例模式),    Facade(門面模式), 

Adapter(適配器模式),    Bridge(橋樑模式),        Composite(合成模式), 

Decorator(裝飾模式),    Flyweight(享元模式),     Proxy(代理模式), 

Command(命令模式),      Interpreter(解釋器模式), Visitor(訪問者模式), 

Iterator(迭代子模式),   Mediator(調停者模式),    Memento(備忘錄模式), 

Observer(觀察者模式),   State(狀態模式),         Strategy(策略模式), 

Template Method(模板方法模式), Chain Of Responsibleity(責任鏈模式) 

工廠模式:工廠模式是一種經常被使用到的模式,根據工廠模式實現的類可以根據提供的數據生成一組類中某一個類的實例,通常這一組類有一個公共的抽象父類並且實現了相同的方法,但是這些方法針對不同的數據進行了不同的操作。首先需要定義一個基類,該類的子類通過不同的方法實現了基類中的方法。然後需要定義一個工廠類,工廠類可以根據條件生成不同的子類實例。當得到子類的實例後,開發人員可以調用基類中的方法而不必考慮到底返回的是哪一個子類的實例。 

113、開發中都用到了那些設計模式?用在什麼場合

每個模式都描述了一個在我們的環境中不斷出現的問題,然後描述了該問題的解決方案的核心。通過這種方式,你可以無數次地使用那些已有的解決方案,無需在重複相同的工作。主要用到了MVC的設計模式。用來開發JSP/Servlet或者J2EE的相關應用。簡單工廠模式等。 

 

6. j2ee部分

117BSCS的聯繫與區別。 

C/SClient/Server的縮寫。服務器通常採用高性能的PC、工作站或小型機,並採用大型數據庫系統,如OracleSybaseInFORMix或 SQL Server。客戶端需要安裝專用的客戶端軟件。 

B/S是Brower/Server的縮寫,客戶機上只要安裝一個瀏覽器(Browser),如Netscape NavigatorInternet Explorer,服務器安裝OracleSybaseInFORMix或 SQL Server等數據庫。在這種結構下,用戶界面完全通過WWW瀏覽器實現,一部分事務邏輯在前端實現,但是主要事務邏輯在服務器端實現。瀏覽器通過Web Server 同數據庫進行數據交互。 

C/S 與 B/S 區別: 

1.硬件環境不同

  C/S 一般建立在專用的網絡上小範圍裏的網絡環境局域網之間再通過專門服務器提供連接和數據交換服務

  B/S 建立在廣域網之上的不必是專門的網絡硬件環境,例與電話上網租用設備信息自己管理有比C/S更強的適應範圍一般只要有操作系統和瀏覽器就行 

2.對安全要求不同 

  C/S 一般面向相對固定的用戶羣對信息安全的控制能力很強一般高度機密的信息系統採用C/S 結構適宜可以通過B/S發佈部分可公開信息

  B/S 建立在廣域網之上對安全的控制能力相對弱可能面向不可知的用戶。 

3.對程序架構不同 

  C/S 程序可以更加註重流程可以對權限多層次校驗對系統運行速度可以較少考慮

  B/S 對安全以及訪問速度的多重的考慮建立在需要更加優化的基礎之上C/S有更高的要求 B/S結構的程序架構是發展的趨勢MS.Net系列的BizTalk 2000 Exchange 2000全面支持網絡的構件搭建的系統. SUN IBM推的JavaBean 構件技術等,使 B/S更加成熟

4.軟件重用不同 

  C/S 程序可以不可避免的整體性考慮構件的重用性不如在B/S要求下的構件的重用性好

  B/S 對的多重結構,要求構件相對獨立的功能能夠相對較好的重用.就入買來的餐桌可以再利用,而不是做在牆上的石頭桌子 

5.系統維護不同   

  C/S 程序由於整體性必須整體考察處理出現的問題以及系統升級升級難可能是再做一個全新的系統 

  B/S 構件組成,方面構件個別的更換,實現系統的無縫升級系統維護開銷減到最小.用戶從網上自己下載安裝就可以實現升級

6.處理問題不同 

  C/S 程序可以處理用戶面固定並且在相同區域安全要求高需求與操作系統相關應該都是相同的系統 

  B/S 建立在廣域網上面向不同的用戶羣分散地域這是C/S無法作到的與操作系統平臺關係最小

7.用戶接口不同 

  C/S 多是建立的Window平臺上,表現方法有限,對程序員普遍要求較高 

  B/S 建立在瀏覽器上有更加豐富和生動的表現方式與用戶交流並且大部分難度減低,減低開發成本

8.信息流不同 

  C/S 程序一般是典型的中央集權的機械式處理交互性相對低 

  B/S 信息流向可變化, B-B B-C B-G等信息、流向的變化更像交易中心。 

2、應用服務器與WEB SERVER的區別?

應用服務器:WeblogicTomcatJboss 

WEB SERVERIIS、 Apache 

32、應用服務器有那些? 

BEA WebLogic ServerIBM WebSphere Application ServerOracle9i Application ServerjBossTomcat 

 

3J2EE是什麼? 

:Je22Sun公司提出的多層(multi-diered),分佈式(distributed),基於組件(component-base)的企業級應用模型(enterpriese application model).在這樣的一個應用系統中,可按照功能劃分爲不同的組件,這些組件又可在不同計算機上,並且處於相應的層次(tier)中。所屬層次包括客戶層(clietn tier)組件,web層和組件,Business層和組件,企業信息系統(EIS)層。

 

一個另類的回答:j2ee就是增刪改查。 

67J2EE是技術還是平臺還是框架? 什麼是J2EE

   J2EE本身是一個標準,一個爲企業分佈式應用的開發提供的標準平臺。 

   J2EE也是一個框架,包括JDBCJNDIRMIJMSEJBJTA等技術。








計算機基礎知識:

  1CISC體系與RISC體系分別指什麼?

             RISC 和CISC 是目前設計製造微處理器的兩種典型技術,雖然它們都是試圖在體系結構、操作運行、軟件硬件、編譯時間和運行時間等諸多因素中做出某種平衡,以求達到高效的目的,但採用的方法不同,因此,在很多方面差異很大,它們主要有:

  (1) 指令系統:RISC 設計者把主要精力放在那些經常使用的指令上,儘量使它們具有簡單高效的特色。對不常用的功能,常通過組合指令來完成。因此,在RISC 機器上實現特殊功能時,效率可能較低。但可以利用流水技術和超標量技術加以改進和彌補。而CISC 計算機的指令系統比較豐富,有專用指令來完成特定的功能。因此,處理特殊任務效率較高。
  (2) 存儲器操作:RISC 對存儲器操作有限制,使控制簡單化;而CISC 機器的存儲器操作指令多,操作直接。
  (3) 程序:RISC 彙編語言程序一般需要較大的內存空間,實現特殊功能時程序複雜,不易設計;而CISC 彙編語言程序編程相對簡單,科學計算及複雜操作的程序設計相對容易,效率較高。
  (4) 中斷:RISC 機器在一條指令執行的適當地方可以響應中斷;而CISC 機器是在一條指令執行結束後響應中斷。
  (5) CPU:RISC CPU 包含有較少的單元電路,因而面積小、功耗低;而CISC CPU 包含有豐富的電路單元,因而功能強、面積大、功耗大。
  (6) 設計週期:RISC 微處理器結構簡單,佈局緊湊,設計週期短,且易於採用最新技術CISC 微處理器結構複雜,設計週期長。
  (7) 用戶使用:RISC 微處理器結構簡單,指令規整,性能容易把握,易學易用;CISC微處理器結構複雜,功能強大,實現特殊功能容易。
  (8) 應用範圍:由於RISC 指令系統的確定與特定的應用領域有關,故RISC 機器更適合於專用機;而CISC 機器則更適合於通用機。


2ISO\OSI網絡參考模型分哪些層?

一物理層
二數據鏈路層
三網絡層
四傳輸層
五會話層
六表示層
七應用層


3簡述TCP/IP協定的特性及TCP和IP代表什麼協定?它們的功能是什麼?

          ip是網際協議,向下調用鏈路層的接口發送數據,向上爲TCP層提供ip地址,ip層是無連接的不可靠的協議,可以支持路由,內置DV和LS路由算法,能夠查找最近路由。


         TCP : 向下調用ip層的接口,向上應用層提供分解複用功能,提供socket接口。是面向連接的可靠的協議:丟包會重傳、自帶擁塞控制,對一每一連接提供公平行原則。 建立連接需要三次握手。一般應用於內容敏感的場合。


         UDP : 不可靠的無連接的,向下調用ip層的接口,向上應用層提供分解複用功能,提供socket接口。一般應用於數據實時性敏感的場合。


4String是最基本的數據類型嗎?

基本數據類型包括byte、int、char、long、float、double、boolean和short。
java.lang.String類是final類型的,因此不可以繼承這個類、不能修改這個類。爲了提高效率節省空間,我們應該用StringBuffer類

java:


1面向對象的三個基本特徵是什麼?


1.抽象
         抽象就是忽略一個主題中與當前目標無關的那些方面,以便更充分地注意與當前目標有關的方面。抽象並不打算了解全部問題,而只是選擇其中的一部分,暫時不用部分細節。比如,我們要設計一個學生成績管理系統,考察學生這個對象時,我們只關心他的班級、學號、成績等,而不用去關心他的身高、體重這些信息。抽象包括兩個方面,一是過程抽象,二是數據抽象。過程抽象是指任何一個明確定義功能的操作都可被使用者看作單個的實體看待,儘管這個操作實際上可能由一系列更低級的操作來完成。數據抽象定義了數據類型和施加於該類型對象上的操作,並限定了對象的值只能通過使用這些操作修改和觀察。


2.繼承: 

     繼承是一種聯結類的層次模型,並且允許和鼓勵類的重用,它提供了一種明確表述共性的方法。對象的一個新類可以從現有的類中派生,這個過程稱爲類繼承。新類繼承了原始類的特性,新類稱爲原始類的派生類(子類),而原始類稱爲新類的基類(父類)。派生類可以從它的基類那裏繼承方法和實例變量,並且類可以修改或增加新的方法使之更適合特殊的需要。這也體現了大自然中一般與特殊的關係。繼承性很好的解決了軟件的可重用性問題。比如說,所有的Windows應用程序都有一個窗口,它們可以看作都是從一個窗口類派生出來的。但是有的應用程序用於文字處理,有的應用程序用於繪圖,這是由於派生出了不同的子類,各個子類添加了不同的特性。


3.封裝:

       封裝是面向對象的特徵之一,是對象和類概念的主要特性。封裝是把過程和數據包圍起來,對數據的訪問只能通過已定義的界面。面向對象計算始於這個基本概念,即現實世界可以被描繪成一系列完全自治、封裝的對象,這些對象通過一個受保護的接口訪問其他對象。一旦定義了一個對象的特性,則有必要決定這些特性的可見性,即哪些特性對外部世界是可見的,哪些特性用於表示內部狀態。在這個階段定義對象的接口。通常,應禁止直接訪問一個對象的實際表示,而應通過操作接口訪問對象,這稱爲信息隱藏。事實上,信息隱藏是用戶對封裝性的認識,封裝則爲信息隱藏提供支持。封裝保證了模塊具有較好的獨立性,使得程序維護修改較爲容易。對應用程序的修改僅限於類的內部,因而可以將應用程序修改帶來的影響減少到最低限度。


4. 多態性:


        多態性是指允許不同類的對象對同一消息作出響應。比如同樣的加法,把兩個時間加在一起和把兩個整數加在一起肯定完全不同。又比如,同樣的選擇編輯-粘貼操作,在字處理程序和繪圖程序中有不同的效果。多態性包括參數化多態性和包含多態性。多態性語言具有靈活、抽象、行爲共享、代碼共享的優勢,很好的解決了應用程序函數同名問題。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

2抽象類和接口的異同:

       1、不能實例化; 2、包含未實現的方法聲明; 3、派生類必須實現未實現的方法,抽象類是抽象方法,接口則是所有成員(不僅是方法包括其他成員); 另外,接口有如下特性: 接口除了可以包含方法之外,還可以包含屬性、索引器、事件,而且這些成員都被定義爲公有的。除此之 外,不能包含任何其他的成員,例如:常量、域、構造函數、析構函數、靜態成員。 一個類可以直接繼承多個接口,但只能直接繼承一個類(包括抽象類)。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

3運行時異常(RuntimeException)與一般異常有何不同?
                                    一般異常是可捕捉到的。運行時異常是不可預知的異常


4Sleep()和wait()有什麼區別?
             sleep是線程類(Thread)的方法,導致此線程暫停執行指定時間,把執行機會給其他線程,但是監控狀態依然保持,到時後會自動恢復。調用sleep不會釋放對象鎖。


             wait().會釋放鎖


5實現多線程有幾種方法?
三種,

     
                1.繼承Thread類,重寫run函數


                2.實現Runnable接口,重寫run函數


                3.實現Callable接口,重寫call函數

6Anonymous Inner Class (匿名內部類)是否可以extends(繼承)其它類,是否可以implements(實現)interface(接口)?

      匿名類本身就是通過繼承類或者接口來實現的。但是不能再顯式的extends 或者implements了。


7淺談final,finalize,finally區別:

           1、final

    修飾符(關鍵字)如果一個類被聲明爲final,意味着它不能再派生出新的子類,不能作爲父類被繼承。因此一個類不能既被聲明爲 abstract的,又被聲明爲final的。將變量或方法聲明爲final,可以保證它們在使用中不被改變。被聲明爲final的變量必須在聲明時給定初值,而在以後的引用中只能讀取,不可修改。被聲明爲final的方法也同樣只能使用,不能重載。 一句話:final修飾類時:沒有祖先的光棍(不能繼承也不能被繼承),final修飾變量或者方法時:固定的,只能拿來用,不能改。
          2、finally

    在異常處理時提供 finally 塊來執行任何清除操作。如果拋出一個異常,那麼相匹配的 catch 子句就會執行,然後控制就會進入 finally 塊(如果有的話)。 
         3、finalize

    方法名。Java 技術允許使用 finalize() 方法在垃圾收集器將對象從內存中清除出去之前做必要的清理工作。這個方法是由垃圾收集器在確定這個對象沒有被引用時對這個對象調用的。它是在 Object 類中定義的,因此所有的類都繼承了它。子類覆蓋 finalize() 方法以整理系統資源或者執行其他清理工作。finalize() 方法是在垃圾收集器刪除對象之前對這個對象調用的。 



8Hashtable與HashMap區別:

第一個不同主要是歷史原因。Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現。


也許最重要的不同是Hashtable的方法是同步的,而HashMap的方法不是。這就意味着,雖然你可以不用採取任何特殊的行爲就可以在一個多線程的應用程序中用一個Hashtable,但你必須同樣地爲一個HashMap提供外同步。一個方便的方法就是利用Collections類的靜態的synchronizedMap()方法,它創建一個線程安全的Map對象,並把它作爲一個封裝的對象來返回。這個對象的方法可以讓你同步訪問潛在的HashMap。這麼做的結果就是當你不需要同步時,你不能切斷Hashtable中的同步(比如在一個單線程的應用程序中),而且同步增加了很多處理費用。


第三點不同是,只有HashMap可以讓你將空值作爲一個表的條目的key或value。HashMap中只有一條記錄可以是一個空的key,但任意數量的條目可以是空的value。這就是說,如果在表中沒有發現搜索鍵,或者如果發現了搜索鍵,但它是一個空的值,那麼get()將返回null。如果有必要,用containKey()方法來區別這兩種情況。


9說出ArrayList,Vector, LinkedList的存儲性能和特性:
       ArrayList和Vector都是使用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及數組元素移動等內存操作,所以索引數據快而插入數據慢,Vector由於使用了synchronized方法(線程安全),通常性能上較ArrayList差,而LinkedList使用雙向鏈表實現存儲,按序號索引數據需要進行前向或後向遍歷,但是插入數據時只需要記錄本項的前後項即可,所以插入速度較快。


10&和&&的區別。 
      &是位運算符,表示按位與運算,&&是邏輯運算符,表示邏輯與(and)。


11接口是否可繼承接口? 抽象類是否可實現(implements)接口? 抽象類是否可繼承實體類(concrete class)?
     接口可以繼承接口。抽象類可以實現(implements)接口,抽象類是否可繼承實體類,但前提是實體類必須有明確的構造函數。


12List, Set, Map是否繼承自Collection接口?
      List,Set是,Map不是

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章