前言:本篇隨筆,主要記錄Java的基礎知識點,不管是用於項目或者面試中,筆者認為都非常有用,所以將持續更新......
1.Java的訪問權限
Java中有四種訪問權限:默認訪問權限、public、private、protected
這四種訪問權限中,只有默認訪問權限和public才能修飾類(這里所說的類為外部類,對於內部類,四種權限都可以進行修飾),對於字段和方法,四種權限都可以進行修飾。
默認訪問權限(字段或類前不加任何修飾符):用默認訪問權限進行修飾,只能在同包中進行訪問。
public:任何地方都可見(方法、字段、包)。
private:用private修飾的方法或字段只能在本類中進行訪問。
protected:用protected修飾類的方法或字段,在同包中可以被訪問,對於不同的包,只能通過繼承對其方法或字段進行訪問。
具體細節參考:http://www.cnblogs.com/dolphin0520/p/3734915.html,這篇博文中有詳細解釋。
2.Java中"=="與equals()方法的區別
1)對於8種基礎數據類型,"=="比較值是否相等。
如果作用於引用類型的變量,則比較的是所指向對象的地址。
注:equals方法是不能作用與基礎類型數據的,只能作用與引用類型數據。
2)對於equals方法:
如果equals方法未被重寫,則比較的是引用類型變量所指向的對象地址。
對於String、Integer、Date等復寫了equals方法的對象,則比較的是對象內容。
注:重寫了equals方法的對象:String、8種基礎類型的包裝類、Date等,這里並未列舉完。
具體參考:
https://www.cnblogs.com/wangjiangwu/p/5770634.html
http://www.cnblogs.com/dolphin0520/p/3592500.html
3.在重寫equals方法,為什么有必要同時重寫hashCode方法
具體參考:http://www.cnblogs.com/happyPawpaw/p/3744971.html
重寫hashCode方法,主要是為了維護hashCode方法的協定,該協定規定,相等的對象必須有相同的哈希碼。
4.String、StringBuffer和StringBuilder
這三個對象在平時使用和面試中出現的頻次非常的高。
要點:
String是不可變對象。這點可以從String的源碼中看到。String源碼分析傳送門:String源碼分析
StringBuffer是線程安全的。從源碼中可以看到函數上使用了synchronized進行修飾。
StringBuilder是非線程安全的。
特別指出String中的intern()方法,該方法從源代碼中可以看出為本地方法(並且與jdk的版本有關系,以jdk1.6為分界點),並且在面試題中極其容易出現,具體區別為:
在jdk1.6以前:
調用intern方法時,首先會去常量池中查找是否存在與當前String值相同的值,
如果存在的話,則直接返回常量池中這個String值的引用;如果不存在的話,則會將原先堆中的該字符串拷貝一份到常量池中,並返回該字符串在常量池中的引用。
jdk1.7:
調用intern方法時,首先會去常量池中查找是否存在與當前String值相同的值,
如果存在的話,則直接返回常量池中這個String值的引用;如果不存在的話,則只會將原先堆中該字符串的引用放置在常量池中。注意:不會拷貝這個字符串到常量池中。
注意:由於jdk1.7對字符串常量池做出了調整,從PermGen區中調整到了堆中,所以在使用intern方法時,並不會進行字符串的拷貝。
下面給出相應例子,更清楚的說明intern方法。
1 String str1 = "abcd"; 2 String str2 = new String("ab") + new String("cd"); 3 System.out.println(str2.intern() == str1); 4 System.out.println(str2 == str1);
jdk1.6中輸出:
false
false
jdk1.7中輸出:
true
false
解釋:
在jdk1.6中字符串常量池和堆區被完全區分開,所以會返回兩個false。
在jdk1.7中
在執行第1行String str1=“abcd”時,會將“abcd”直接存儲到常量池中。
在執行第2行String str2=new String("ab")+new String("cd")時,在類加載的時候,會在常量池中存儲"ab"和"cd"。
當執行str2.intern()方法時,發現常量池中存在"abcd"(第一行代碼的結果),所以返回此時"abcd"字符串的引用,即str1,所以str2.intern()==str1為true,兩處的引用相同的。
第四行,str2==str1,兩個引用的地址明顯不同,str2指向堆,str1指向字符串常量池中,所以為false。
將上述代碼進行變形,形式如下:
1 String str2 = new String("ab") + new String("cd"); 2 str2.intern(); 3 String str1="abcd"; 4 System.out.println(str2 == str1);
在jdk1.6中,同樣輸出false。
但是在jdk1.7中輸出true。
解釋:
在執行第1行String str2=new String("ab")+new String("cd")時,在類加載的時候,會在常量池中存儲"ab"和"cd"。注意:這時常量池中是沒有"abcd"的。
在執行第2行str2.intern()方法時,發現常量池中沒有"abcd",於是將str2的引用放入常量池中,並不會進行拷貝。
在執行第3行時,發現常量池中已經存在"abcd"的引用了,直接賦值給str1,所以最后的結果為true。
將上述代碼再次變形,將第2行與第3行互換位置。形式如下:
1 String str2 = new String("ab") + new String("cd"); 2 String str1 = "abcd"; 3 str2.intern(); 4 System.out.println(str2 == str1);
在jdk1.6與jdk1.7中都是輸出false。
這個原理比較簡單了,str2與str1,明顯是兩個不同的引用,str2指向堆,str1指向字符串常量池,所以為false。
具體參考:
http://www.cnblogs.com/dolphin0520/p/3778589.html
http://blog.csdn.net/seu_calvin/article/details/52291082
http://blog.csdn.net/bigtree_3721/article/details/74907670
http://blog.csdn.net/hzw19920329/article/details/51262925
5.關於集合類
具體細節參考這篇博文:https://www.cnblogs.com/leeplogs/p/5891861.html,總結得非常詳細。
重點歸納:
List有序集合,可以包含重復元素。
Set無序(TreeSet有序,二叉樹排序),不能包含重復元素。
Map不能包含重復的鍵值,因為鍵值對,重復鍵會被覆蓋。
注:參考博文中說,所有集合類都實現了Iterator接口,但是Map集合是沒有實現該接口的。
下面對常見集合的主要特點進行總結:
HashMap:
#1.非同步的,也就說是線程不安全,與Hashtable相反。
#2.無序,允許null鍵和null值(HashTable不允許鍵或值為null),不能包含重復的鍵,出現重復的鍵值時,在put操作時會進行覆蓋。
#3.在HashMap中擴容時,是非常耗性能的;HashMap默認數據容量大小為16,loadFactor(擴容因子默認值為0.75),當元素個數大於16*0.75=12時,就會進行擴容,擴大一倍:2*16=32。
#5.HashMap線程不安全體現傳送門:HashMap線程不安全的體現
#6.HashMap源碼分析傳送門:HashMap源碼分析——基於jdk1.7
Hashtable:
#1.Hashtable是線程安全的。
#2.無序,不允許null鍵或null值。
#3.繼承Dictionary接口,也實現了Map接口。
#4.Hashtable擴容時,擴大的容量為:2n*+1,擴大一倍並加1。Hashtable默認數據容量為11。
#5.Hashtable源碼分析傳送門:Hashtable源碼分析
ConcurrentHashMap的實現原理,參考:
https://my.oschina.net/hosee/blog/639352
https://www.cnblogs.com/chengxiao/p/6842045.html
https://my.oschina.net/hosee/blog/675884
ConcurrentHashMap:
1)線程安全的,主要使用鎖分離技術(分段鎖)。
2)初始容量大小為16,默認並發度也為16。
3)由於使用分段鎖技術,只有對於同一段數據操作,才會考慮線程同步。
4)無序,不允許null鍵或null值。(源碼put函數可以得出該結論)
by Shawn Chen,2018.3.19日,下午。
