1、實例方法和靜態方法有什么不一樣?
答:實例方法只能在其類下調用,而靜態方法可以直接調用。
答:1、在外部調用靜態方法時可以用“類名.方法名”和“對象名.方法名”調用方法;而實例方法只能用“對象名.方法名”調用方法。(調用靜態方法可以無需創建對象)2、靜態方法在訪問本類時不能直接調用實例成員(實例成員變量和實例方法),只能調用靜態成員;而實例方法則都可以。
2、Java中的異常有哪幾類?分別怎么使用?
答:常見的異常有:
1、java.lang.nullpointerexception “程序遇上了空指針”,即調用了未經初始化的對象或者是不存在。
2、java.lang.classnotfoundexception “指定類不存在”,這里主要注意類的名稱或路徑是否正確。
3、java.lang.arrayindexoutofboundsexception “數組下標越界”,即調用的數組下標超過了數組的范圍。
4、FileNotFoundException “文件未找到異常”,檢查文件名是否正確或是否存在。
5、IOException “輸入輸出流異常” ,進行輸入輸出操作時出問題或找不到文件。
6、NoSuchMehodException “方法異常”,調用的放法未定義。
三、常用的集合類有哪些?
答:List,Set,Map。
1、List:實現類ArrayList和LinkedList
①、ArrayList:索引從零開始,線性存儲,有索引,有順序、可重復
②、LinkedList:線性存儲,有索引、有順序、鏈表結構、可重復
2、Set:不需要編號與名,存放速度快但不好取,不允許重復,具體的 Set 實現類依賴添加的對象的 equals() 方法來檢查等同性,實現類HashSet和TreeSet
①、HashSet:無序,調用對象的hashCode()方法,獲取哈希碼,從在集合中計算存放對象的位置;底層通過比較哈希碼與equals()方法來判別是否重復。
②、TreeSet:樹型排序,只能對實現了Comparable借口的對象排序。
3、Map:以鍵值對的形式存儲對象,鍵不能重復,實現類HashMap和TreeMap
①、HashMap:無序、按照哈希算法來存取鍵對象,可重載hashCode()和equals()方法來比較鍵,但兩者必須一致。
②、TreeMap:可樹型排序,通過傳遞Comparator的實現類構造TreeMap。
4、ArrayList和LinkedList的內部實現?
答:ArrayList是基于數組的數據結構,其在增加時若數組不滿足增加量時會進行數組擴容,同時還需要數據搬遷,同理在刪除時也需要數據搬遷。
LinkedList是基于鏈表的數據結構,通過內部的一個元素類內存放元素,增加和刪除只需要在上下指針增減新元素。
所以,ArrayList的讀取性較好,基于數組索引的index索引,但寫入率不太好,需要數據搬遷,適合于隨機讀取;而LinkedList的讀取率不太好,需要遍歷鏈表,但寫入率可以,更適用于順序讀取。
5、內存溢出?
答:即運行所需內存超過JVM所提供的內存承受范圍,JVM所管理的內存大致分為三部分區域:①永久保存區域 ? ②堆區域 ?③JAVA棧區域?
①永久保存區域:主要保存class 和 mete的信息,class需要保存的內容主要包括方法和靜態屬性;
②堆區域:主要存放的是對象,每次用new創建一個對象實例時,對象實例存儲于堆區域,這部分空間會被JVM的垃圾回收機制管理,堆區域只有一個;
③JAVA棧區域:主要存放基本類型變量和方法的輸入輸出參數以及對象的引用,JAVA程序的每個線程就有一個獨立的Java棧。
6、ClassLoader?
答:類加載器。Java程序(class文件)并不是本地的可執行文件。當運行Java文件時,首先運行JVM,然后再把Java class加載到JVM中運行,負責加載Java class的部分就叫ClassLoader。
7、==和equals的區別?
答:對于基本數據類型,==比較的是值是否相同,對于引用對象,==比較的是一個對象在內存中的地址。
而equals 不用于比較基本類型但可以用于比較基本數據類型包裝類的值是否相等,對于引用對象,equals在Java.lang.object中定義的是同樣用==對內存地址進行比較,而在許多類中都重寫類該方法,比如String會對內存地址引用不相等時,還會進行值比較,所以如果沒有重寫父類object的equals時,它用法與==一樣。
8、hashCode()方法的作用?
答:hashCode()在Object中定義,根據對象的特定字段運用哈希算法得出特定的哈希碼,一般hashCode()方法運用于集合中根據哈希碼加快查詢的速率,迅速地查找出相匹配的桶取出值,同時hashCode()常用于equals()方法中根據哈希碼比對對象的內存地址是否相同。
9、Object類常用的方法?
答:boolean equals(Object object)判斷某對象是否與此對象“相等”。
int hashCode()返回對象的哈希碼值。
String toString()返回對象的字符串表達。
10、NIO是什么?
答:即non-blocking IO,為所有的原始類型提供緩存支持,定義為數據容器的緩沖區。其Channel不同于IO的單向Stream,Channel是雙向的可讀可寫;Buffer(緩沖區)相當于一個容器,NIO寫數據和讀數據放進Buffer中;Selector是NIO的核心類,Selector能夠檢測多個注冊通道上是否有事件發生,若有,便獲取事件然后對事件進行相應的響應。這樣便可以單個線程管理多個連接,同時大大減少了系統開銷,不必創建多個線程。
11、GC(垃圾回收)算法?
答:①、引用計數(reference counting)原理:此對象有一個引用,則+1;此對象刪除一個引用,則-1。GC收集為0的對象。
②、復制(copying)原理:把內存空間分為兩個相等的區域,每次只使用一個區域。垃圾回收時,便利當前區域把正在使用的對象復制到另一份區域。
③、標記-清掃(Mark and sweep)原理:對于“活”的對象,一定可以追溯到其存活在堆棧和靜態存儲區的引用。這個引用鏈條可能穿過數個對象層次,算法基于有向圖,采用深度游戲搜索。先從GC roots開始遍歷所有引用,對活的對象進行標記,然后對堆進行遍歷把未標記的對象清除。
④、標記-壓縮(Mark-Compact)原理:同標記-清除,標記活的對象,然后將所有標記了的對象整理到堆的底部。
⑤、分代(generationl collecting)原理:基于對象生命周期分析得出的垃圾回收算法。把對象分為年輕代、年老代、持久代,對不同的生命周期進行不同的算法進行回收。
新生代的GC(Minor GC)Minor GC非常頻繁,一般回收速度也比較快。新生代存活時間較短,因此基于Copying算法來進行回收,對于新生代就是就是在Eden和FromSpace或ToSpace之間copy,新生代采用空閑指針的方式來控制GC觸發,指針保持最后一個分配的對象在新生代區間的位置,當有新的對象要分配內存時,用于檢查空間是否足夠,不夠就觸發GC。當連續分配對象時,對象會逐漸從eden到survivor。
舊生代的GC(MajorGC/FullGC)對象存活比較久,比較穩定,因此采用Mark算法進行回收,掃描標記處活的對象,然后未標記的對象進行回收,回收后對空出來的空間進行合并,要么標記出來便于下次分配,總之減少內存碎片帶來的損耗。
MajorGC 的速度一般會比 Minor GC 慢 10倍以上。
java GC即是“自適應、分代的、停止-復制、標記-掃描”式的垃圾回收器。
12、CMS(Concurrent Mark Sweep)?
答:并行垃圾處理機制,GC和程序并發執行。
Young GC,Stop the world凍結所有內存,程序執行,但并發的程序需要一些Stop the world的時間和Copying collector,多線程操作掃描和Copy,減少Stop the world的時間。
Old GC,程序和GC并發執行:
Initial Phase:短暫停,標記GC根集合,單線程執行。
Concurrent making phase:GC多線程標記從根集合可達的所有活對象。由于程序和GC并發運行,可能有活對象未被標記。
Concurrent pre-clean:單線程,并發執行。
Remark phase: 短暫停,多線程標記在Concurrent marking phase中有變化的相關對象。
Concurrent sweep phase:和程序并發執行。單線程執行。不做compacting。
concurrent reset:單線程,并發執行。
CMS需要更多的內存空間,因為mark phase時程序還是在運行,程序可以申請更多的old空間。在mark phase中,CMS保證標識活對象,但是該過程中,活對象可能轉變為垃圾,只能等待下一次GC才能回收。
和其他Collector不同,CMS不是等到old滿時才GC,基于以前的統計數據(GC時間,Old空間消耗速度)來決定何時GC。CMS GC也可以基于old空間的占用率。
13、創建類的實例的方法?
①、用new語句創建對象,這是最常見的創建對象的方法。
②、通過工廠方法返回對象,如:String str = String.valueOf(23);
③、運用反射手段,調用java.lang.Class或者java.lang.reflect.Constructor類的newInstance()實例方法。如:Object obj = Class.forName("java.lang.Object").newInstance();
④、調用對象的clone()方法。
⑤、通過I/O流(包括反序列化),如運用反序列化手段,調用java.io.ObjectInputStream對象的 readObject()方法。
14、final/finally/finalize的區別?
答:①:final為用于標示常量的關鍵字,若定義的是基本類型,表示基本類型被賦予的值不可變;若定義方法,表示方法不能被覆蓋;若定義類,表示類不能被繼承。
②:finally是異常處理try/catch語句的一部分,表示無論是try或catch,finally里的語句都會在最后被執行。
③:finalize()是Object類的一個子方法,由垃圾收集器在確定這個對象沒有被引用時對這個對象調用的。它是在 Object 類中定義的,因此所有的類都繼承了它。子類覆蓋 finalize() 方法以整理系統資源或者執行其他清理工作。
15、Session/Cookie的區別?
答:①,session 在服務器端,cookie 在客戶端(瀏覽器)
②,session 默認被存在在服務器的一個文件里(不是內存)
③,session 的運行依賴 session id,而 session id 是存在 cookie 中的,也就是說,如果瀏覽器禁用了 cookie ,同時 session 也會失效(但是可以通過其它方式實現,比如在 url 中傳遞 session_id)
④,session 可以放在 文件、數據庫、或內存中都可以。
⑤,用戶驗證這種場合一般會用 session
16、StringBuffer/StringBuilder的區別,擴展再問他們的實現?
①.? 在執行速度方面的比較:StringBuilder >? StringBuffer
②.? StringBuffer與StringBuilder,他們是字符串變量,是可改變的對象,每當我們用它們對字符串做操作時,實際上是在一個對象上操作的,不像String一樣創建一些對象進行操作,所以速度就快了。
③.? StringBuilder:線程非安全的
StringBuffer:線程安全的
StringBuffer與StringBuilder都繼承自AbstractStringBuilder
AbstractStringBuilder的實現原理:我們知道使用StringBuffer等無非就是為了提高java中字符串連接的效率,因為直接使用+進行字符串連接的話,jvm會創建多個String對象,因此造成一定的開銷。AbstractStringBuilder中采用一個char數組來保存需要append的字符串,char數組有一個初始大小,當append的字符串長度超過當前char數組容量時,則對char數組進行動態擴展,也即重新申請一段更大的內存空間,然后將當前char數組拷貝到新的位置,因為重新分配內存并拷貝的開銷比較大,所以每次重新申請內存空間都是采用申請大于當前需要的內存空間的方式,這里是2倍。
17、Servlet的生命周期?
①、初始化階段,調用Init()方法。(Servlet初始化的時刻:①、Servlet容器啟動時自動裝載某些Servlet,實現它要在Web.xml文件中的<Servlet></Servlet>之間調到代碼;②、在Servlet容器啟動時,客戶首次向Servlet發送請求;③、Servlet類文件更新后,重新裝載Servlet。)
Servlet被裝載后,Servlet容器創建Servlet實例并調用Init()方法進行初始化,整個Servlet周期內,Init()方法只被調用一次。
②、響應客戶請求,調用Service()方法。
③、終止階段,調用Destory()方法。
Servlet工作原理:
首先簡單解釋一下Servlet接收和響應客戶請求的過程,首先客戶發送一個請求,Servlet是調用service()方法對請求進行響應的,service()方法中對請求的方式進行了匹配,選擇調用doGet,doPost等這些方法,然后再進入對應的方法中調用邏輯層的方法,實現對客戶的響應。在Servlet接口和GenericServlet中是沒有doGet,doPost等等這些方法的,HttpServlet中定義了這些方法,但是都是返回error信息,所以,我們每次定義一個Servlet的時候,都必須實現doGet或doPost等這些方法。
每一個自定義的Servlet都必須實現Servlet的接口,Servlet接口中定義了五個方法,其中比較重要的三個方法涉及到Servlet的生命周期,分別是上文提到的init(),service(),destroy()方法。GenericServlet是一個通用的,不特定于任何協議的Servlet,它實現了Servlet接口。而HttpServlet繼承于GenericServlet,因此HttpServlet也實現了Servlet接口。所以我們定義Servlet的時候只需要繼承HttpServlet即可。
Servlet接口和GenericServlet是不特定于任何協議的,而HttpServlet是特定于HTTP協議的類,所以HttpServlet中實現了service()方法,并將請求ServletRequest,ServletResponse強轉為HttpRequest和HttpResponse。