Java研發工程師面試題

基礎題html

1、String,StringBuffer, StringBuilder 的區別是什麼?String爲何是不可變的?
1. String是字符串常量,StringBuffer和StringBuilder是字符串變量。StringBuffer是線程安全的,StringBuilder是非線程安全的。具體來講String是一個不可變的對象,每次修改String對象其實是創新新對象,並將引用指向新對象。效率很低。StringBuffer
java

是可變的,即每次修改只是針對其自己,大部分狀況下比String效率高,StringBuffer保證同步(synchronized),因此線程安全。StringBuilder沒有實現同步,因此非線程安全。但效率應該比StringBuffer高。StringBuffer使用時最好指定容量,這樣會比不指定容量快30%-40%,甚至比不指定容量的StringBuilder還快。
2、VECTOR,ARRAYLIST, LINKEDLIST的區別是什麼?
vector是同步的,arraylist和linkedlist不是同步的。底層方面,vector與arraylist都是基於object[]array實現的,但考慮vector線程安全,因此arraylist效率上回比vector較快。元素隨機訪問上,vector與arraylist是基本相同的,時間複雜度是O(1),linkedlist的隨機訪問元素的複雜度爲O(n)。但在插入刪除數據上,linkedlist則比arraylist要快不少。linkedlist比arraylist更佔內存,由於linkedlist每一個節點上還要存儲對先後兩個節點的引用。
3、HASHTABLE, HASHMAP,TreeMap區別
Hashmap和HashTable都實現了Map接口,但HashTable是線程安全的,HashMap是非線程安全的。HashMap中容許key-value值均爲null,但HashTable則不容許。HashMap適合單線程,HashTable適合多線程。HashTAble中的hash數字默認大小是11,增長方式爲old*2+1,HashMap中的hash默認大小爲16,且均爲2的指數。TreeMap則能夠將保持的數據根據key值進行排列,能夠按照指定的排序方式。默認爲升序。
web

4、ConcurrentHashMap和HashTable的區別
二者均應用於多線程中,但當HashTable增大到必定程度時,其性能會急劇降低。由於迭代時會被鎖很長時間。但ConcurrentHashMap則經過引入分割來保證鎖的個數不會很大。簡而言之就是HashTable會鎖住真個map,而ConcurrentHashMap則只須要鎖住map的一個部分。
5、Tomcat,apache,jboss的區別
Tomcat是servlet容器,用於解析jsp,servlet。是一個輕量級的高效的容器;缺點是不支持EJB,只能用於Java應用。
算法

Apache是http服務器(web服務器),相似於IIS能夠用來創建虛擬站點,編譯處理靜態頁面。支持SSL技術,支持多個虛擬主機等功能。sql

Jboss是應用服務器,運行EJB的javaee應用服務器,遵循javaee規範,可以提供更多平臺的支持和更多集成功能,如數據庫鏈接,JCA等。其對servlet的支持是經過集成其餘servlet容器來實現的。如tomcat。
6、GET POST區別
get是從服務器上獲取數據,post是向服務器發送數據。
數據庫

get是把參數數據隊列加到提交表單的action屬性所指的URL中,值和表單內各個字段一一對應,在url中能夠看到。post是經過HTTPpost機制,將表單內各個字段與其內容放置在html header內一塊兒傳送到action屬性所指的url地址。apache

對於get方式,服務區端用request.QueryString獲取變量值,對於post方式,服務器端用request.Form獲取提交的數據。get傳送的數據量較小,post較大,通常不受限制。get安全性比post要低,但執行效率較高。數組

7、SESSION, COOKIE區別
session數據放在服務器上,cookie則放在客戶瀏覽器上。cookie不太安全,由於能夠分析出本地cookie,並進行cookie欺騙,考慮安全應使用session。session會在必定時間內保存在服務器上,當訪問增多時,會比較佔用服務器的性能,考慮減輕服務器壓力則應該使用cookie。單個cookie保持的數據不超過4k,不少瀏覽器都限制要給站點最多保存20個cookie。
8、Servlet的生命週期
主要分三個階段:初始化——調用init()方法,響應客戶請求階段——調用service()方法,終止階段——調用destroy方法。工做原理:客戶發送一個請求,servlet調用service方法對請求進行響應,即對請求方式進行匹配,選擇調用doGet、doPost方法等,而後進入對於的方法中調用邏輯層的方法,實現對客戶的響應。自定義的servlet必須首先servlet接口。
瀏覽器

具體生命週期包括:裝載Servlet、服務器建立Servlet實例、服務器調用Servlet的init()方法、客戶請求到達服務器、服務器建立請求對象、服務建立相應對象、服務器激活Servlet的service方法,請求對象和響應對象做爲service()方法的參數、service()方法得到關於請求對象的信息,處理請求,訪問其餘資源,得到須要的信息、service()方法可能激活其餘方法以處理請求,如doGet(),doPost()
9、HTTP 報文包含內容
緩存

請求方法包括GET,POST,HEAD,PUT,TRACE,OPTIONS,DELETE。請求頭如:Host、User-Agent、Connection、Accept-Charset等。請求頭部的最後會有一個空行,表示請求頭部結束,接下來爲請求正文,這一行很是重要,必不可少。請求正文爲可選部分,如get就沒有。
10、Statement與PreparedStatement的區別,什麼是SQL注入,如何防止SQL注入
使用PreparedStatement能夠提高代碼的可讀性和可維護性,能夠盡最大可能提升性能。由於Statement每次執行一個SQL命令都會對其編譯,但PreparedStatement則只編譯一次。PreparedStatement就相似於流水線生產。另外一方面PreparedStatement能夠極大提升安全性:它對傳遞過來的參數進行了強制參數類型轉換,確保插入或查詢數據時,與底層數據庫格式匹配。

SQL注入:就是經過將sql命令插入到web表單遞交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意SQL命令。如sql命令:select id from test where name='1' or 1=1; drop table test,但用PreparedStatement就能夠避免這種問題。
11、redirect, forward區別
redirect:服務器根據邏輯,發送一個狀態碼,告訴瀏覽器從新去請求那個地址。因此地址欄顯示是新的url。forward是指服務器請求資源,直接訪問目標地址url,把響應的內容讀取過來並再發送給瀏覽器,瀏覽器並不知道資源從哪裏來,因此地址欄不變。

redirect不能共享數據,forward轉發頁面和轉發到頁面能夠貢獻request中的數據。redirect用於註銷,forward用於登錄。forward效率高於redirect。

12、關於JAVA內存模型,一個對象(兩個屬性,四個方法)實例化100次,如今內存中的存儲狀態,幾個對象,幾個屬性,幾個方法。
Java新建的對象都放在堆裏,若是實例化100次,堆中產生100個對象,通常對象與其屬性和方法屬於一個總體,但若是屬性和方法是靜態的,則屬性和方法只在內存中存一份。
十3、
談談Hibernate的理解,一級和二級緩存的做用,在項目中Hibernate都是怎麼使用緩存的
一級緩存爲session基本的緩存,是內置的不能卸載。一個Session作了一個查詢操做,它會把這個結果放在一級緩存中,若是短期內這個session又作了同一個操做,那麼hibernate就直接從一級緩存中獲取數據。

二級緩存是SessionFactory的緩存,分爲內置緩存和外置緩存兩類。即查詢結果放在二級緩存中,若是同一個sessionFactory建立的某個session執行了相同的操做,hibernate就會從二級緩存中獲取結果。適合放在二級緩存中的數據包括:不多被修改的數據,不是很重要的數據,容許出現偶偶併發的數據,不會被併發訪問的數據,參考數據。不適合放在二級緩存中的數據:常常被修改的數據,財務數據,絕對不容許出現併發,與其餘應用共享的數據。
十4、反射講一講,主要是概念,都在哪須要反射機制,反射的性能,如何優化
可以分析類能力的程序稱爲反射。反射機制能夠用來:在運行中分析類的能力,在運行中查看對象,如編寫一個toString方法供全部類使用。實現通用的數據操做代碼。利用Method對象,這個對象很像C++的指針。

反射性能優化方法主要爲設置不用作安全檢查。

十5、談談Hibernate與Ibatis的區別,哪一個性能會更高一些
Ibatis至關較爲簡單,容易上手,Hibernate比較複雜,門檻較高。若是系統須要處理數據量很大,性能要求很高,須要執行高度優化的sql語句才能達到性能要求,則此時Ibatis會比較好。

對不一樣數據庫支持方面Hibernate較好,由於Ibatis須要修改的字段較多。另外Hibernate現已成爲主流的o/r Mapping框架,開發效率高。
十6、對Spring的理解,項目中都用什麼?怎麼用的?對IOC、和AOP的理解及實現原理

十7、線程同步,併發操做怎麼控制
線程同步不必定就是同時,而是協同步驟,或協同步調。線程同步就是多個線程在邏輯上互有因果關係,因此要對其執行順序進行協調。

線程併發是指同一時間間隔內,多個線程同時執行。若是線程在時間上可以區分,那麼就能夠上線程休眠指定的時間來進行同步,可用sleep()方法完成。若是線程在時間上不能區分,但在邏輯順序上能夠區分的話,那麼可用jion()方法來完成,一個先執行完,而後執行另外一個。若是線程設計較爲複雜,那麼就只有經過wait(),notify()方法來完成了

十8、描述struts的工做流程。

簡略過程就是web應用啓動,接收用戶請求並進行匹配,返回用戶請求信息。
1. 在web應用啓動時,加載並初始化ActionServlet,ActionServlet從struct-config.xml文件中讀取配置信息,把它們存放到各個配置對象中。

2. 當ActionServlet接收到一個客戶請求時,首先檢索和用戶請求相配的ActionMapping實例,若是不存在,返回用戶請求路徑無效信息。

3. 如ActionForm實例不存在,則建立一個ActionForm對象,把客戶提交的表單數據保存到ActionForm對象中。

4. 根據配置信息決定是否須要表單驗證。若是須要驗證,就調用ActionForm的Validate()方法。若是Valiedate()方法返回null或返回一個不包含ActionMessage的ActionErrors對象,則表示表單驗證成功。

5. ActionServlet更加ActionMapping實例包含的映射信息決定請請求轉發給哪一個Action。若是相應的Action實例不存在,則先建立這個實例,而後調用Action的execute()方法。

6. Action的execute()方法返回一個ActionForward對象,ActionServlet再把客戶請求轉發給ActionForward對象指向的JSP組建。

7. ActionForward對象指向的jsp組件生成的動態網頁,返回給客戶。

十9、Tomcat的session處理,若是讓你實現一個tomcatserver,如何實現session機制
當一個session開始時,Servlet容器會建立一個HttpSession對象,在某些狀況下把這些HttpSession對象從內存中轉移到文件系統中或數據庫中。須要訪問的時候將它們載入到內存中。這樣的好處就是節省內存,當web服務器產生故障時,還能夠從文件系統或數據庫中恢復Session的數據。管理session有兩個類:1)StandardManager,這是一個默認的類,當tomcat啓動或重載時將會session對象保存到指定文件中。2)PersistentManager,管理方式更加靈活,具備容錯能力,能夠及時把Session備份到Session Store中,能夠控制內存中Session的數量。
二10、關於Cache(Ehcache,Memcached)
Memcache:分佈式內存對象緩存系統,佔用其餘機子的內存。不少互聯網,負載均衡三臺(以三臺爲例)web服務器能夠共享一臺Memcache的資源。傳遞的信息以鍵值對的形式存儲。傳遞的數據要實現序列化。

Oscache:頁面級緩存(網上強調最多的東西),佔用本機的內存資源。可 以選擇緩存到硬盤,如存取到硬盤重啓服務也可從新得到上次持久化的資源,而若是緩存到內存就不行。通常不必緩存到硬盤,由於I/O操做也是比較耗資源,和從數據庫取每每優點很小。Oscache存取數據的做用域分爲application和session兩種。

EhCache:Hibernate緩存,DAO緩存,安全性憑證緩存(Acegi),Web緩存,應用持久化和分佈式緩存。EhCache在默認狀況下,即在用戶未提供自身配置文件ehcache.xml或ehcache-failsafe.xml時,EhCache會依據其自身Jar存檔包含的ehcache-failsafe.xml文件所定製的策略來管理緩存。若是用戶在classpath下提供了ehcache.xml或ehcache-failsafe.xml文件,那麼EhCache將會應用這個文件。若是兩個文件同時提供,那麼EhCache會使用ehcache.xml文件的配置。
二1、sql的優化相關問題
1. 對查詢優化,避免全表掃描

2. 儘可能避免where子句中對段進行null值判斷,不然將致使引擎放棄使用索引而進行全表掃描。

3. 儘可能避免where子句中出現!=或<>,不然將致使引擎放棄使用索引而進行全表掃描。

4. 儘可能避免where子句中出現or來鏈接條件。

5. 慎用in和not in,不然致使全表掃描

6. where中不要用函數操做。

7. Update 語句,若是隻更改一、2個字段,不要Update所有字段,不然頻繁調用會引發明顯的性能消耗,同時帶來大量日誌。

8. 對於多張大數據量(這裏幾百條就算大了)的表JOIN,要先分頁再JOIN,不然邏輯讀會很高,性能不好。

9. 儘量的使用 varchar/nvarchar 代替 char/nchar,節省空間,提升查詢效率

10. select count(*) from table;這樣不帶任何條件的count會引發全表掃描,而且沒有任何業務意義,是必定要杜絕的。

二2、oracle中 rownum與rowid的理解,一千條記錄我查200到300的記錄怎麼查?

二3、如何分析ORACLE的執行計劃?

二4、 DB中索引原理,種類,使用索引的好處和問題是什麼?
原理:由於檢索磁盤比對數據,須要大量的時間和IO,因此就須要構造某列的數據的btree、hash值、位圖索引。通常的索引能快速的查找比對,而索引的值記錄了磁盤的位置,直接讀取數據庫字段對應位置的內容。

索引好處:加快數據檢索速度、加速表與表之間的鏈接特別是實現數據的參考完整性方面有特別的意義、減小查詢中分組和排序的時間,使用優化隱藏器,提升系統性能。

缺點:建立和維護索引須要時間,索引須要佔用物理空間,當對錶中的數據驚醒增刪改時全部也須要動態維護。
二5、JVM垃圾回收實現原理。垃圾回收的線程優先級。
JVM的堆空間中主要分爲年輕代、年老代和永久代。年輕代和年老代是存儲動態產生的對象。永久代主要是存儲java類信息,包括解析獲得的方法屬性、字段等等。永久代基本不參與垃圾回收。年輕代分爲一個eden區和兩個相同的survior區。剛開始建立的對象都放置在eden區。這樣主要是爲了將生命週期短的對象儘可能留在年輕代中。當eden區申請不到空間時,進行minorGC,把存活的對象拷貝到survior。年老代主要存放生命週期比較長的對象,如緩存對象。具體JVM垃圾回收過程以下:

一、對象在Eden區完成內存分配。二、當Eden區滿了,在建立對象就會申請不到空間,則觸發minorGC,進行young(eden區和1survivor區的垃圾回收)。三、在minorGC時,Eden不能被回收的對象唄放入到空的survior(即Eden確定被清空),另外一個survivor裏不能被GC回收的地想也會被放入到這個survivor,始終保證一個survivor是空的。四、當完成第三步的時候、若是發現survivor滿了,則這些對象唄copy到old區,或者survivor並無滿,但有些對象已經足夠old了,也被放入到old區。當old區北放滿以後,進行fullGC。

二6、jvm 最大內存設置。設置的原理。結合垃圾回收講講。

 JVM內存能夠分爲堆內存和非堆內存,堆內存給開發人員用的,非堆內存給JVM自己用的,用來存放類型信息,即便GC時也不會釋放空間。

堆內存設置:

-Xms 初始堆內存,默認物理內存1/64,也是最小分配堆內存,當空餘堆內存小於40%時,會增長到-Xms的最大限制。

-Xmx 最大堆內存分配,默認物理內存1/4,當空餘堆內存大於70%時,會減少打-Xms的最小限制。

非堆內存設置:

-XX:PermSize 非堆內存的初始值,默認物理內存的1/64,也是最小非堆內存。

-XX:MaxPermSize 非堆內存最大值,默認物理內存的1/4。

查看堆大小命令爲Runtime.getRuntime().maxMemory()。

二7、jvm怎樣經過參數調整內存大小

 本地環境變量中JVM參數設置:

new一個JAVA_OPTS:

variable name: JAVA_OPTS

variable value: -Xms256M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=512M

eclipse中參數設置:在缺省VM參數中輸入:-Xmx128m -Xms64m -Xmn32m -Xss16m

二8、進程與線程的區別

 線程是進程的一個單元,也是進程內的可調度實體。區別就是:一、進程內的線程共享地址空間,進程則本身獨立的地址空間。二、進程是資源分配和擁有的單位,同一個進程內的線程共享進程資源。三、線程是處理器調度的基本單位。四、二者都可併發執行。

二9、怎樣避免死鎖

1. 使用事務時,儘可能縮短事務idea邏輯處理過程,及早提交或回滾事務

2. 設置死鎖的超時參數爲合理範圍,如3-10分鐘,若超過期間,自動放棄本次操做,避免進程懸掛。

3. 優化程序,檢查並避免死鎖現象出現。

4. 對全部的腳本和sp都要仔細測試。

5. 全部的sp都要有錯誤處理。

6. 通常不要修改sql事務的默認級別。不推薦強行加鎖。

三10、垃圾回收算法使用的產品、場景

標記-清除算法:標記階段,肯定全部要回收的對象,並標記,清除階段則將須要回收的對象清除。

複製算法:把內存分爲大小相等的兩塊,每次使用其中的一塊,當垃圾回收時,把存活的對象複製到另外一塊上,而後把這塊內存整個清理掉。兩塊內存比是8:1

標記整理算法:把存活的對象往內存的一端移動,而後直接回收邊界之外的內存。標記-整理算法提升了內存的利用率,而且它適合在收集對象存活時間較長的老年代。

分代回收算法:根據對象的存活時間把內存分爲新生代和老年代,根據各代對象的存活特色,每代採用不一樣的GC算法。新生代用標記-複製算法,老年代用標記-整理算法。

三1、實際項目中JVM調優

一、JVM啓動參數:調整各代的內存比例和垃圾回收算法,提升吞吐量。

二、改進程序邏輯算法,提升性能

三、自定義封裝線程池,解決用戶響應時間長的問題。好比設置線程最小數量、最大數量

四、鏈接池

三2、jdk併發包的集合介紹

Map併發包,其實現爲ConcurrentHashMap,它實現了ConcurrentMap接口。put方法爲根據計算出的hash值去獲取segment對象。找到segment對象後調用該對象的put方法完成操做。segment中的put方法則是先加鎖,以後判斷數組大小,而後以爲是否擴充。而後獲得key索要放置的位置。

List併發包,客在高併發環境下使用CopyOnWriteArrayList代替ArrayList。添加元素是利用數組的copy功能和加鎖機制。併發狀況下,CopyOnWriteArrayList比ArrayList略快了些。

set併發,CopyOnWriteSet和CopyOnWriteArrayList底層實現差很少就是在添加元素時會進行惟一性判斷,若是對象數組已經含有重複的元素,不進行增長處理。

queue併發,併發類是ArrayBlockingQueue,底層爲數組,並對關鍵的方法入隊、出隊操做加入了鎖隊機制。

Atomic系列類,好比AtomicInteger類,經過使用計數器操做時,通常爲了不線程安全問題,在方法上加鎖操做。有了併發包下的原子系列類,咱們就能夠直接使用。

三3、線程之間的通訊

主要包括互斥鎖、條件變量、讀寫鎖和線程信號燈。

互斥鎖:以排他方式防止數據被併發修改。互斥鎖兩個狀態0和1。具體爲申請鎖、佔用鎖以防止數據被修改,此時默認阻塞等等,最後釋放鎖。

條件變量通訊機制:原理,條件變量出現時,能夠彌補互斥鎖的缺陷,有些問題僅僅依靠互斥鎖沒法解決。但條件變量不能單獨使用,必須配合互斥鎖一塊兒實現對資源的互斥訪問。

讀寫鎖:在對數據讀寫時,每每讀佔主要部分。基本原則是若是其餘線程讀數據,則容許其餘線程執行讀操做,但不容許寫操做。若是有其餘線程申請寫操做,則其餘線程不能申請讀操做和寫操做。

線程信號:線程擁有與信號相關的私有數據——線程信號掩碼。線程能夠向別的線程發送信號,每一個線程能夠設置本身的阻塞集合。全部線程中,同一信號子任何線程裏的對該信號的處理必定相同。

三4、介紹threadlocal

 能夠叫作線程本地變量或線程本地存儲。ThreadLocal爲變量在每一個線程中都建立了一個副本,每一個線程均可以訪問本身內部的副本變量。但可能這樣作會致使內存佔用較大。

ThreadLocal類的幾個方法:get() 用來獲取ThreadLocal在當前線程中保存的變量副本,set()用來設置當前線程中變量的副本,remove()用來一衝當前線程中的變量副本,initialValue()通常用來在使用時進行重寫,是一個延遲加載方法。最多見的ThreadLocal使用場景是用來解決數據庫鏈接、Session管理等。

三5、jdbc的操做過程

 加載數據庫驅動包、鏈接數據庫、使用sql語句操做數據庫、關閉數據庫鏈接

三6、HTTP1.1的新特性

 支持持續鏈接,經過創建一個TCP後,發送請求並獲得響應,而後發送更多的請求並獲得更多的響應。經過把簡歷和釋放TCP鏈接的開銷分攤到多個請求上,則對每一個請求而言,優於TCP而形成的相對開銷被大大下降。並且還能夠發送流水線請求。

三7、異常處理,包含了什麼

參考:http://lavasoft.blog.51cto.com/62575/18920/

三8、堆排序與快速排序

package cst.zju.algorithm;


/*
 * 快速排序
 */
public class Quicksort {

    public int[] data;
    
    public Quicksort(int a[]){
        this.data = a;
    }
    
    public void quicksort(int left, int right){
        int index;
        if(left < right){
            index = partition(left, right);
            quicksort(left, index-1);
            quicksort(index+1, right);
        }
    }
    public int partition(int left, int right){
        int pivot = this.data[left];
        while(left < right){
            while(left < right && this.data[right] >= pivot)
                right --;
            if(left < right)
                this.data[left++] = this.data[right];
            while(left < right && this.data[left] <= pivot){
                left ++;
            }
            if(left < right){
                this.data[right--] = this.data[left];
            }
        }
        this.data[left] = pivot;
        return left;
    }
    public void printdata(){
        for(int i = 0; i < this.data.length; i ++)
            System.out.print(this.data[i] + " ");
        System.out.println("");
    }
    public static void main(String[] args) {
        int[] a = { 5, 3, 6, 2, 1, 9, 4, 8, 7 };
        Quicksort qs = new Quicksort(a);
        qs.quicksort(0, a.length-1);
        qs.printdata();
        
    }
}
View Code
package cst.zju.algorithm;

import java.awt.print.Printable;

import javax.security.auth.kerberos.KerberosKey;

/**
 * 堆排序,假設父節點爲i,則左節點爲2*i+1,右節點爲2*i+2
 * @author dandelion
 *
 */
public class Heapsort {
    public static int[] data;
    public Heapsort(int[] data){
        this.data = data;
    }
    
    public void printdata(){
        for(int i = 0; i < data.length; i ++){
            System.out.print(data[i] + " ");
        }
        System.out.println("");
    }
    public static void main(String[] args) {
        int[] a = { 5, 3, 6, 2, 1, 9, 4, 8, 7 };
        Heapsort t = new Heapsort(a);
        t.printdata();
        System.out.println("=========================");
        t.heapSort();
        System.out.println("=========================");
        t.printdata();
    }

    public void swap(int i, int j){
        if (i == j) return;
        this.data[i] = this.data[i] + this.data[j];
        this.data[j] = this.data[i] - this.data[j];
        this.data[i] = this.data[i] - this.data[j];
    }
    public void reconstructionHeap(int lastindex){
        for(int i = (lastindex-1)/2; i >= 0; i --){
            int j = i;
            //保證當前結點的子節點存在
            while(2*j+1 <= lastindex){
                int big = 2*j + 1;
                if(big < lastindex){
                    //保證右子節點存在
                    if(data[big] < data[big + 1]){
                        big = big + 1;
                    }
                }
                if(data[j] < data[big]){
                    swap(j, big);
                    j = big;
                }else{
                    break;
                }
            }
        }
    }
    public void heapSort(){
        for(int i = 0; i < this.data.length; i ++){
            int tmp = this.data.length - 1 - i;
            reconstructionHeap(tmp);
            swap(0,tmp);
            printdata();
        }
    }
}
View Code

堆排序是漸進最優的比較排序算法,達到了O(nlgn)這一下界,而快排有必定的可能性會產生最壞劃分,時間複雜度可能爲O(n^2)。堆排比較的幾乎都不是相鄰元素,對cache極不友好。數學複雜度並不必定表明實際運行的複雜度。

三9、Collection有哪些類

Set, List, Map, SortedSet, SortedMap, HashSet, TreeSet, ArrayList, LinkedList, Vector, Collections, Arrays, AbstractCollection

四10、Hashcode總爲1會怎樣,如何解決hash衝突

當全部對象Hashcode返回都爲1時,全部對象都出現hash衝突,其性能會降低

解決hash衝突:

線性再散列法、插入元素時,若是發生衝突,算法會簡單的遍歷hash表,直到找到表中的下一個空槽,並將該元素放入該槽中。查找元素時,首先散列值所指向的槽,若是沒有找到匹配,則繼續遍歷hash表,直到:(1)找到相應的元素;(2)找到一個空槽(指示查找的元素不存在);(3)整個hash表遍歷完畢(指示該元素不存在而且hash表是滿的)。

非線性再散列法、線性再散列法是從衝突位置開始,採用一個步長以順序方式遍歷hash表,來查找一個可用的槽,從上面的討論能夠看出,它容易產生彙集現象。非線性再散列法能夠避免遍歷散列表,它會計算一個新的hash值,並經過它跳轉到表中一個徹底不一樣的部分。

外部拉鍊法、將hash表看做是一個鏈表數組,表中的每一個槽要不爲空,要不指向hash到該槽的表項的鏈表。

四1、如何用兩個隊列實現棧

便可以將A隊列做爲棧push,B隊列做爲棧pop。量隊列數據相同。

四2、Object的通用方法

通用方法有equals(), finalize(), toString(), 其餘native方法有hashcode(), registerNatives(), getClass(), clone(), notify(), notifyAll(), wait()等。

四3、Java中如何實現多態

多態是OOP中的一個重要特性,主要用來實現動態聯編,程序的最終狀態只有在執行過程當中才被決定而非在編譯期間就決定了。有利於提升大型系統的靈活性和擴展性。

多態的三個必要條件:有繼承、有方法重寫、父類引用指向子類對象。

引用變量的兩種類型:編譯時類型由申明類型決定,運行時類型由實際對應的對象決定。

package cst.zju.oop;

public class Animal {
    public void voice(){
        System.out.println("動物叫聲");
    }

}
class Cat extends Animal{
    public void voice(){
        System.out.println("喵喵喵");
    }
    public void catchMouse(){
        System.out.println("抓老鼠");
    }
}

class Dog extends Animal{
    public void voice(){
        System.out.println("旺旺網");
    }
}

class Pig extends Animal{
    public void voice(){
        System.out.println("哼哼哼");
    }
}
View Code
package cst.zju.oop;

public class TestAnimal {
    
    public static void testvoice(Animal e){
        e.voice();
        if(e instanceof Cat){
            ((Cat) e).catchMouse();
        }
    }
    public static void main(String[] args) {
        Animal a = new Cat();
        Animal b = new Dog();
        Animal c = new Pig();

        testvoice(a);
        testvoice(b);
        testvoice(c);
        //報錯,由於Animal類中沒有這個方法
        //a.catchMouse();
        Cat a1 = (Cat) a;
        a1.catchMouse();
    }
}
View Code

多態內存:

 

   

四4、Java內存泄漏

內存泄漏通常狀況下有兩種狀況:C++/C語言中,在堆中分配的內存,沒有將其釋放掉就刪除了全部能訪問到這塊內存的方式所有刪除。(如指針從新賦值)

另外一種狀況就是在內存對象已經不須要時,還保留這塊內存和它的訪問方式(引用),因爲Java中GC機制,因此Java中的內存泄漏一般指第二種狀況。

儘管對於C/C++中的內存泄露狀況來講,Java內存泄露致使的破壞性小,除了少數狀況會出現程序崩潰的狀況外,大多數狀況下程序仍然能正常運行。可是,在移動設備對於內存和CPU都有較嚴格的限制的狀況下,Java的內存溢出會致使程序效率低下、佔用大量不須要的內存等問題。這將致使整個機器性能變差,嚴重的也會引發拋出OutOfMemoryError,致使程序崩潰。

在不涉及複雜數據結構狀況下,Java內存泄漏表現爲一個內存對象的生命週期超出程序須要它的長度。(稱爲對象遊離)。

內存泄漏實例:Java堆溢出、虛擬機棧和本地方法棧溢出、方法區和運行時常量池溢出、本機直接內存溢出

四5、final字段總結

1. final類不能被繼承,其中的方法也是默認final類型,沒有子類。

2. final方法不能被子類覆蓋,但能夠繼承

3. final變量表示常量,只能被賦值一次賦值後不改變

4. final不能用於構造方法

四6、override(重寫)和overload(重載)區別

override:子類在繼承父類時,子類能夠定義某些方法與父類的方法名稱、參數個數、類型、順序、返回值類型一致,但調用時自動調用子類的方法,父類至關於被覆蓋了。

overload:能夠表如今類的多態上,函數名相同,但其餘參數個數、類型、順序、返回值等都不相同。

四7、static初始化

未經初始化的全局靜態變量會被自動初始化爲0。

相關文章
相關標籤/搜索