1.權限修飾符 public ,protected ,默認, private 的區別是?java
當前類 相同包下 子類 項目中其餘包下數組
public √ √ √ √ 安全
protected √ √ √ ×多線程
默認 √ √ × ×app
private √ × × × ide
2.java中的基本數據類型有哪些? String 屬於基本類型嗎?性能
答:java中基本類型有8種 , byte short,int ,long ,float , double ,char ,boolean ,String 屬於引用類型,不屬於基本類型測試
整數類型: byte, short ,int ,log 優化
byte (1字節,8位 取值範圍:-128 ~ 127) ,short(2字節,16 位,不多用) ,int(4字節,32位最經常使用) ,long(8字節,64位) ui
數值類型
小數類型: float(4字節 32位) , double (8字節,64位)
字符類型 : char 佔2個字節,16位 ; 單引號引發的字符,能夠爲中文
布爾類型 : boolean 值爲true 或者 false
java中默認的整數類型是 int , 默認的小數類型是double
類型的自動提高:
例如:
double d = 1L;//類型小轉大,能夠自動提高 long l = 1.0; //類型大轉小,只能強轉
3. int 與 Integer 的區別是什麼?
答:一、Integer是int的包裝類,int則是java的一種基本數據類型
二、Integer變量必須實例化後才能使用,而int變量不須要
三、Integer實際是對象的引用,當new一個Integer時,其實是生成一個指針指向此對象;而int則是直接存儲數據值
四、Integer的默認值是null,int的默認值是0
拓展: int 與 Integer 的比較 , Integer 與 Integer 的比較
//情形1 Integer 與 int類型比較 Integer i = 1; int j = 1; System.out.println(i == j); //情形2 Integer 與 Integer 比較(不經過new 的形式) Integer i1 = 100; Integer i2 = 100; System.out.println(i1 == i2); //情形3 Integer 與 Integer 比較(不經過new 的形式) Integer i3 = 128; Integer i4 = 128; System.out.println(i3 == i4); //情形4 Integer 與 Integer 經過new Integer i5 = new Integer(110); Integer i6 = 110; System.out.println(i5 == i6); //情形5 Integer 與 Integer 經過new Integer i7 = new Integer(120); Integer i8 = new Integer(120); System.out.println(i7 == i8);
最終執行結果:
true true false false false
分析:
//寫在前面 ,對於 == ,int 類型之間的比較,比較的是值, Integer對象之間比較的是內存地址 /* 情形一: Integer 與 int 的比較 , 會將Integer 拆箱成 int 類型的值再作比較,因此最終是兩個int類型的比較. 而兩個int類型比較的是字面值,因此結果爲true */ /* 情形二: Integer i1 = 100;這句最終執行的代碼是 Integer i1 = Integer.valueOf(100); 此時查看Integer.valueOf(int)的源碼: */ public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } //繼續查看IntegerCache的源碼: private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; //即至關於 new Integer[256]; cache = new Integer[(high - low) + 1]; int j = low; //最終cache[0] ~ cache[255] 等價於 -128 ~ 127 for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} } /* 也就是說, i1 與 i2 都是從IntegerCache 數據中取出,且內存地址一致.因此結果爲true; */ /* 情形三: 同上,仍然會調用Integer.valueOf()方法,因爲不知足判斷條件: */ if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } /* 因此 兩次i3 ,i4 至關於分別執行了 new Integer(128); 而Integer 對象之間的比較,比較的是內存地址; 因爲new 了兩次,因此內存地址不一樣,故結果爲false; */ /* 情形四: 參考情形二, i5,i6 至關於從新new了兩次,內存地址不一致,故比較結果爲false 情形五: 同上,每次new 都會新開闢內存空間,故結果爲false; */
4.String s = "Hello", s = "World" 此時s的值已經改變了, 爲何還說String 是不可變的?
答: 第一次 s = ''Hello'',至關於建立了 1個 String對象 ''Hello'' , 同時將該對象在內存中的引用地址賦給了變量s
而當執行 s = ''Hello''時,一樣也會建立一個String對象 "World", 將此對線的地址賦給 變量s ,並打破原來的引用關係
也就是說,每次更改 s 的值都會新開闢一塊內存空間,而不是修改原有內存空間中的值 ,因此說 String 是不可變的;
如何驗證?
能夠經過System.identityHashCode(obj)驗證,該方法能夠根據變量的內存地址計算出相應的hashCode值(官方API,並無這麼說):
String s = "Hello"; System.out.println(System.identityHashCode(s)); //s = "World"; System.out.println(System.identityHashCode(s));
此時執行的結果爲:
1068824137 1068824137
不難發現,兩次執行的結果是一致的,所以 s 引用的內存地址沒有改變, 將上面的註釋打開再執行,結果爲:
1068824137 864237698
能夠發現,兩次的值不一致,能夠直觀的說明.s的內存地址已經發生了改變
除此以外,查看String 代碼能夠發現 String 是有 char[] 組成;
private final char value[];//等價於 private final char[] value; 只是寫法不一樣而已
而char[] value 使用了private 與 final修飾 因此一旦初始化就不能夠更改;
經過 內存地址 與 String中的成員變量 足以說明String是不可變的;
4. String ,StringBuilder,StringBuffer 之間的區別是什麼?
從拼接速度上來講:StringBuilder > StringBuffer > String
測試案例:
@Test public void testAppend() { long start_time = 0; long end_time = 0; start_time = System.currentTimeMillis(); StringBuffer sf = new StringBuffer("str"); for (int j = 0; j < 100000; j++) { sf = sf.append("str"); } end_time = System.currentTimeMillis(); System.out.println("StringBuffer 拼接總耗時:"+(end_time - start_time)+"ms"); /*start_time = System.currentTimeMillis(); StringBuilder sb = new StringBuilder("str"); for (int j = 0; j < 100000; j++) { sb = sb.append("str"); } end_time = System.currentTimeMillis(); System.out.println("StringBuilder 拼接總耗時:"+(end_time - start_time)+"ms");*/ /*start_time = System.currentTimeMillis(); String s = "str"; for (int j = 0; j < 100000; j++) { s += "str"; } end_time = System.currentTimeMillis(); System.out.println("String 拼接總耗時:"+(end_time - start_time)+"ms");*/ }
一樣執行10W次拼接str字符串,5次執行取平均耗時結果:
StringBuffer :4.4ms
StringBuilder:3.4ms
String:16.4ms
從結果來看 StringBuffer 與 StringBuilder的拼接速度遠遠大於String的拼接, 這是由於 StringBuffer與StringBuilder 的拼接是對同一對象進行操做,而String的拼接則是不停的開闢新的內存
StringBuilder 與 StringBuffer 的差別會隨着拼接次數的增大而增大,有興趣的夥伴能夠動手試一下
從線程安全上來看:StringBuffer > StringBuilder
緣由:StringBuffer 的 append方法 都加上了 synchronized關鍵字,實現了方法的同步,多線程下是安全的,而StringBuilder中在多線程中可能出現數據不一致的狀況
5. java中重寫是什麼意思? 重寫的原則是什麼?
答:重寫是指複寫父類中的方法
原則: 1同 , 2小, 1大
1同:方法簽名相同,即方法名稱,參數類型,參數個數徹底相同
2小:子類拋出的異常類型小於等於父類 , 子類的返回值類型小於等於父類
1大:子類方法的訪問權限大於等於父類
6.什麼是overload ,即方法的重載?
類中存在多個,方法名稱相同,可是參數列表不一樣(參數個數, 參數類型)的方法 .這些方法爲重載關係
重載的注意事項:
- 在使用重載時只能經過不一樣的參數樣式。例如,不一樣的參數類型,不一樣的參數個數,不一樣的參數順序(固然,同一方法內的幾個參數類型必須不同,例如能夠是fun(int,float),可是不能爲fun(int,int));
- 不能經過訪問權限、返回類型、拋出的異常進行重載;
- 方法的異常類型和數目不會對重載形成影響;
- 對於繼承來講,若是某一方法在父類中是訪問權限是priavte,那麼就不能在子類對其進行重載,若是定義的話,也只是定義了一個新方法,而不會達到重載的效果。
7.Error 與 Exception 有什麼區別? 運行時異常與受檢異常有什麼區別?
答:
Error 與 Exception 都是Throwable的子類:
1.Error 表示是JVM沒法處理的重大錯誤,例如:OutOfMemoryError ;Error是咱們沒法處理的錯誤 ;
2.Exception 能夠分爲兩大類: Check(受檢)異常,Runtime(運行時)異常:
通常運行時異常指的是RuntimeException下的子類,除了RuntimeException外.其餘的Exception都稱之爲受檢異常
2.1 受檢異常:咱們必需要在程序中去處理他,不然代碼編譯不經過;
處理的方式有兩種:①在方法聲明時經過throws直接拋出 ②使用try ... catch ...代碼塊捕獲處理
常見的受檢異常有:IOException
2.2 運行時異常:程序不要求代碼中必定要處理他,不會影響編譯經過,只有在運行時的時候出現纔會拋出;
通常RuntimeException的出現,都是代碼編寫的邏輯不夠嚴謹致使的;
常見的RuntimeException有:
Java.lang.ArithmeticException (算數異常)
Java.lang.NumberFormatException (數字格式化異常:;例如:Integer.parseInt("a");)
Java.lang.ClassCastException(類型轉換異常)
Java.lang.IndexOutOfBoundsException(索引越界)
Java.lang.NullPointerException(常見的空指針異常)
如下列會觸發上述異常的代碼:
//System.out.println(1 / 0);//java.lang.ArithmeticException: / by zero
//int a = Integer.parseInt("a");//java.lang.NumberFormatException: For input string: "a"
//new ArrayList<>().get(0);//java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
String s = null; s.toString();//java.lang.NullPointerException
8. ArrayList,Vector, LinkedList 的存儲性能和特性的區別:
對於查找,更改而言:
ArrayList 與 Vector 基於Object數組,能夠直接根據下標獲取到元素,LinkedList 是基於鏈表的結構,獲取某個元素,須要經過首尾一級級才能夠找到
對於增刪而言:
而Object數組 在指定索引位置插入 或 刪除一個數據則須要將索引後面的全部元素索引進行加一,鏈表結構則比較擅長插入與刪除
結論: ArrayList,Vector 查找和更改速度優於 LinkedList , 增刪速度則慢於LinkedList;
ArrayList 與Vector的區別:
安全性方面:
Vector中的大部分方法都是synchronized的,因此Vector是線程安全的,ArrayList則不是
速度方面:
synchronized會增長性能的消耗,所以ArrayList處理速度是要快於Vector的
如何選擇:
若是是多線程場景建議選擇Vector,保證數據的安全;
若是是單線程,沒有線程安全的問題;則選擇ArrayList更好
9.HashMap ,Hashtable的區別?
從兩方面解答:
1.安全性方面:Hashtable中的許多方法是synchronized的,而HashMap不是;
2.速度方面:安全意味着性能的下降;
3.key,value方面:HashMap的key,value 均可覺得null ; 而 Hashtable中不容許爲null,不然會拋出NullPointerException異常
10. final, finally, finalize 的區別?
雖然長得挺像,可是功能卻差異很大,此題只需回答出各自的功能就行;
final:
修飾類:表示該類不能夠被繼承
修飾方法:表示方法不能夠被重寫
修飾變量:若是修飾的是基本類型的變量,則表示該變量初始化後 值不能夠再被更改;修飾引用類型的變量則初始化後,不能再指向別的對象
finally:
通常搭配 try - catch - finally 或 try - finally 使用;表示無論try-catch語句中發生了什麼 ,執行完try - cathch後都會執行finally中的代碼;
finalize:
是object中的一個protected方法,在GC(垃圾收集器)清理對象以前,會調用該對象的finalize方法
11.java中 try - catch - finally 語句中若是都還有return,那麼執行哪一個return?
12.在try-catch代碼塊中若是有return,那麼在執行return以前會判斷是否存在finally代碼塊?
若是不存在:很好理解,程序未出異常則執行try中的return ,若是出了異常則執行catch中的return
若是存在:再判斷finally中是否有return語句
若是沒有return:等待finally執行完畢以後再執行 try 或 catch中的return
若是有return:則再也不使用try 或 catch中的return,直接使用finally中的return做爲返回值;
額外的,若是try-catch-finally中無論執行了誰的return, 程序都再也不日後執行
13.關於 new String("HelloWorld");總共建立了幾個對象?
對於String而言,經過new 關鍵字建立對象,是必定會在堆中建立1個對象;
但java對String作了優化,除了堆中以外,還有一個String的常量池;
每當建立String類型的對象時(不論是經過new的形式 仍是 字面量的形式) ,都會首先在常量池中尋找是否已經有了"HelloWorld"這個對象
若是有的話則不會在額外建立,若是沒有的話,則會在常量池中建立1個新的對象
因此答案是:最少建立1個新對象,可能建立1個或2個新對象;
而String s = "HelloWorld" 則是 最少0個,可能建立1個新對象;
更詳細的能夠參考這篇博客:new String()究竟建立幾個對象?
14.String中的實例方法,intern()做用是什麼?
答:intern方法的做用時,檢查常量池中是否存在某個字符串,若是存在則該方法返回該字符串在常量池中的引用,不然將字符串添加到常量池中同時返回在常量池中的引用;
String s = new String("hello") + new String("World"); System.out.println(s == "helloWorld");//false 此時比較的是s在堆中的地址 System.out.println(s.intern() == "helloWorld");//true 此時比較的是"helloWorld"在常量池中的地址
更詳細的intern()介紹,請參考該博客(提示:文章有必定長度,請耐心看):Java技術——你真的瞭解String類的intern()方法嗎
15.關於String類型的拼接
若是是字面量值之間的拼接則會在編譯階段進行優化,例如:
String s = "Hello" + "World"
編譯優化後:
String s = "HelloWorld"
若是不是字面量值的拼接,則會轉爲StringBuilder的append拼接,例如:
String s = new String("Hello") + new String("World")
這種狀況,不會再進行編譯優化;經過反編譯能夠看到:
String s = (new StringBuilder("Hello")).append(new String("World")).toString();
詳情參考本文:關於字符串拼接的問題