我發現有不少程序員面試前都是準備地好好的,什麼疑難雜症,未解之謎都是準備得妥妥的,張口就來。反而到了最容易的Javajava
基礎的時候,各類翻車(多是以爲基礎的內容太簡單沒有花精力),原本是可以拿到更高的薪資,就由於基礎沒有回答好,被程序員
抓住當成藉口又砍了好幾K,實在是得不償失。因此今天給你們分享一份Java基礎的面試題彙總以及解析,以便你們更好地應對面試
面試,衝擊更高薪資!算法
主要是爲了」安全性「和」效率「的緣故,由於:數組
一、因爲String類不能被繼承,因此就不會沒修改,這就避免了由於繼承引發的安全隱患;緩存
二、String類在程序中出現的頻率比較高,若是爲了不安全隱患,在它每次出現時都用final來修飾,這無疑會下降程序的執行效安全
率,因此乾脆直接將其設爲final一提升效率;服務器
HashMap就是數組+鏈表的組合實現,每一個數組元素存儲一個鏈表的頭結點,本質上來講是哈希表「拉鍊法」的實現。數據結構
HashMap的鏈表元素對應的是一個靜態內部類Entry,Entry主要包含key,value,next三個元素多線程
主要有put和get方法,put的原理是,經過hash%Entry.length計算index,此時記做Entry[index]=該元素。若是index相同
就是新入的元素放置到Entry[index],原先的元素記做Entry[index].next
get就比較簡單了,先遍歷數組,再遍歷鏈表元素。
null key老是放在Entry數組的第一個元素
解決hash衝突的方法:鏈地址法
再散列rehash的過程:肯定容量超過目前哈希表的容量,從新調整table 的容量大小,當超過容量的最大值時,取
Integer.Maxvalue
集合類存放於java.util包中。
集合類存放的都是對象的引用,而非對象自己,出於表達上的便利,咱們稱集合中的對象就是指集合中對象的引用(reference)。
集合類型主要有3種:set(集)、list(列表)和map(映射)。
集合接口分爲:Collection和Map,list、set實現了Collection接口
ArrayList,LinkedList都實現了java.util.List接口,
Java中的隊列都有哪些,其實是問queue的實現有哪些,如:ConcurrentLinkedQueue、LinkedBlockingQueue 、
ArrayBlockingQueue、LinkedList。
關於ConcurrentLinkedQueue和LinkedBlockingQueue:
Java中Class.forName和classloader均可以用來對類進行加載。
Class.forName除了將類的.class文件加載到jvm中以外,還會對類進行解釋,執行類中的static塊。
而classloader只幹一件事情,就是將.class文件加載到jvm中,不會執行static中的內容,只有在newInstance纔會去執行static塊。
Class.forName(name,initialize,loader)帶參數也可控制是否加載static塊。而且只有調用了newInstance()方法採用調用構造函數,建立類的對象。
如下特性爲我的比較關注的特性,並不齊全;想了解更多,請自行搜索官方文檔。
Java7特性:
1.switch case可使用String,原來只能用int和char;
2.支持2進制0b開頭;支持數字中間有下劃線,解析時自動剔除;
3.一次抓多個異常;用|隔開;
4.try-with-resource,在try中打開資源,系統自動在使用完後關閉;
5. Map<String, List<String>> anagrams = new HashMap<>(); 對抗Google的guava.
6.集合類能夠像js中的數組同樣賦值和引用了。
List<String> list = ["item"];
String item = list[0];
Set<String> set = {"item"};
Map<String, Integer> map = {"key" : 1};
int value = map["key"];
7. 把字符串常量池從permgen區移到了堆區;致使String.intern()方法在1.7以前和以後表現出現不一致;
Java8特性:
1.lambda表達式;
2.新增stream,Date,Time,Base64工具類;
3.使用metaspace,元空間替代permgen區;
4.類依賴分析器:jdeps,能夠以包,目錄,文件夾做爲輸入,輸出依賴關係,沒有的會顯示 not found
5.jjs,能夠執行JavaScript代碼;
數組在隨機訪問數據、隨機增長數據、隨機刪除數據的執行效率上比鏈表的效率高,數據量越小,二者之間效率的差距越小,數據量越大差距越大。
也歡迎你們一塊兒討論面試終於到的各類奇葩問題,特意建了一個Java技術交流羣:895244712,但願有個小圈子的朋友能夠加進來,不定時分享一些技術乾貨,但願能帶來幫助。
詳細解析:https://blog.csdn.net/sinat_29581293/article/details/70214436
這三個類之間的區別主要是在兩個方面,即運行速度和線程安全這兩方面。
String最慢的緣由:
String爲字符串常量,而StringBuilder和StringBuffer均爲字符串變量,即String對象一旦建立以後該對象是不可更改的,但後二者的對象是變量,是能夠更改的。
2. 再來講線程安全
在線程安全上,StringBuilder是線程不安全的,而StringBuffer是線程安全的
若是一個StringBuffer對象在字符串緩衝區被多個線程使用時,StringBuffer中不少方法能夠帶有synchronized關鍵字,因此能夠保證線程是安全的,但StringBuilder的方法則沒有該關鍵字,因此不能保證線程安全,有可能會出現一些錯誤的操做。因此若是要進行的操做是多線程的,那麼就要使用StringBuffer,可是在單線程的狀況下,仍是建議使用速度比較快的StringBuilder。
3. 總結一下
String:適用於少許的字符串操做的狀況
StringBuilder:適用於單線程下在字符緩衝區進行大量操做的狀況
StringBuffer:適用多線程下在字符緩衝區進行大量操做的狀況
11.hashtable和hashmap的區別
1. 存儲結構
HashMap | HashTable |
數組 + 鏈表/紅黑樹 | 數組 + 鏈表 |
HashMap的存儲規則:
優先使用數組存儲, 若是出現Hash衝突, 將在數組的該位置拉伸出鏈表進行存儲(在鏈表的尾部進行添加), 若是鏈表的長度大於設定值後, 將鏈表轉爲紅黑樹.
HashTable的存儲規則:
優先使用數組存儲, 存儲元素時, 先取出下標上的元素(可能爲null), 而後添加到數組元素Entry對象的next屬性中(在鏈表的頭部進行添加).
出現Hash衝突時, 新元素next屬性會指向衝突的元素. 若是沒有Hash衝突, 則新元素的next屬性就是null
描述的有點模糊, 貼出源碼會清晰一點:
Entry<K,V> e = (Entry<K,V>) tab[index]; tab[index] = new Entry<>(hash, key, value, e);
2. 擴容方式
HashMap | HashTable |
oldCap * 2 | oldCap * 2 + 1 |
3. 關於null值
HashMap |
HashTable |
key, value 都可覺得 null |
key, value 均不能夠爲 null |
4. 線程安全
HashMap | HashTable |
線程不安全 | 線程安全 |
大神的解釋:https://blog.csdn.net/qq_27093465/article/details/52268531
傳送門:http://www.javashuo.com/article/p-aryreled-a.html
String類中提供了大量的操做方法,這裏例舉13種關於String類經常使用的方法供你們參考。參考代碼以下: package cn.mc; public class StringTestMc { private String str = "helloWorld"; /** * 將字符串變成一個字符數組 */ public void tocharyArry() { char c[] = str.toCharArray(); for (int i = 0; i < c.length; i++) { System.out.println("轉爲數組輸出:" + c[i]); } } /** * 從字符串中取出指定位置的字符 */ public void tocharAt() { char c = str.charAt(3); System.out.println("指定字符爲:" + c); } /** * 將字符串變成一個byte數組 */ public void tobyte() { byte b[] = str.getBytes(); System.out.println("轉換成byte數組輸出爲:" + new String(b)); } /** * 取得一個字符串的長度 */ public void tolength() { int l = str.length(); System.out.println("這個字符串的長度爲:" + l); } /** * 查找一個指定的字符串是否存在,返回的是字符串的位置,若是不存在,則返回-1 */ public void toindexOf() { int a1 = str.indexOf("e");// 查找字符e的位置 int a2 = str.indexOf("l", 2);// 查找l的位置,從第3個開始查找 System.out.println("e的位置爲:" + a1); System.out.println("l的位置爲:" + a2); } /** * 去掉字符串左右空格 */ public void totrim() { String str1 = " hello "; System.out.println("去掉左右空格後輸出:" + str1.trim()); } /** * 字符串的截取 */ public void tosubstring() { System.out.println("截取後的字符爲:" + str.substring(0, 3));// 截取0-3個位置的內容 System.out.println("從第3個位置開始截取:" + str.substring(2));// 從第3個位置開始截取 } /** * 按照指定的字符串拆分字符,拆分的數據將以字符串數組的形式返回 */ public void tosplit() { String s[] = str.split("e");// 按hello中的e進行字符串拆分 for (int i = 0; i < s.length; i++) { System.out.println("拆分後結果爲:" + s[i]); } } /** * 將字符串進行大小寫轉換 */ public void tochange() { System.out.println("將\"hello\"轉換成大寫爲:" + str.toUpperCase());// 將hello轉換成大寫 System.out.println("將\"HELLO\"轉換成大寫爲:" + str.toUpperCase().toLowerCase());// 將HELLO轉換成小寫 } /** * 判斷是否以指定的字符串開頭或者結尾 */ public void tostartsWithOrendWith() { if(str.startsWith("he"))//判斷字符串是否以he開頭 { System.out.println("字符串是以he開頭"); } if(str.endsWith("lo")) { System.out.println("字符串是以lo結尾"); } } /** * 兩個String類型內容比較 */ public void toequals() { String str3="world"; if(str.equals(str3)) { System.out.println("這倆個String類型的值相等"); } else System.out.println("這倆個String類型的不值相等"); } /** * 兩個字符串不區分大小寫進行比較 */ public void toequalslgnoreCase() { String str4="HELLO"; if(str.equalsIgnoreCase(str4)) { System.out.println("hello和HELLO忽略大小寫比較值相等"); } } /** * 將一個指定獲得字符串替換成其餘字符串 */ public void toreplaceAll() { String str5=str.replaceAll("l", "a"); System.out.println("替換後的結果爲:"+str5); } public static void main(String[] args) { StringTest obj = new StringTest(); obj.tocharyArry(); obj.tocharAt(); obj.tobyte(); obj.tolength(); obj.toindexOf(); obj.totrim(); obj.tosubstring(); obj.tosplit(); obj.tochange(); obj.tostartsWithOrendWith(); obj.toequals(); obj.toequalslgnoreCase(); obj.toreplaceAll(); } }
有這樣一類對象:當內存空間還足夠,則可保留在內存中;若是內存空間在gc以後仍是很是緊張,則可拋棄這些對象。不少系統的緩存功能適合這樣的場景,因此jdk1.2之後
java將引用分爲了強引用、軟引用、弱引用、虛引用四種,引用強度一次減弱。
接口是公開的,裏面不能有私有的方法或變量,是用於讓別人使用的,而抽象類是能夠有私有方法或私有變量的,
另外,實現接口的必定要實現接口裏定義的全部方法,而實現抽象類能夠有選擇地重寫須要用到的方法,通常的應用裏,最頂級的是接口,而後是抽象類實現接口,最後纔到具體類實現。
還有,接口能夠實現多重繼承,而一個類只能繼承一個超類,但能夠經過繼承多個接口實現多重繼承,接口還有標識(裏面沒有任何方法,如Remote接口)和數據共享(裏面的變量全是常量)的做用.
java數據類型 字節 表示範圍
byte(字節型) 1 -128~127
boolean(布爾型) 1 true或false
short(短整型) 2 -32768~32767
char(字符型) 2 從字符型對應的整型數來劃分,其表示範圍是0~65535
int(整型) 4 -2147483648~2147483647
float(浮點型) 4 -3.4E38~3.4E38
double(雙精度型) 8 -1.7E308~1.7E308
long(長整型) 8 -9223372036854775808 ~ 9223372036854775807
大神又來了:https://blog.csdn.net/qq_27093465/article/details/52279473
Hash算法解決衝突的方法通常有如下幾種經常使用的解決方法
1, 開放定址法:
所謂的開放定址法就是一旦發生了衝突,就去尋找下一個空的散列地址,只要散列表足夠大,空的散列地址總能找到,並將記錄存入
公式爲:fi(key) = (f(key)+di) MOD m (di=1,2,3,……,m-1)
※ 用開放定址法解決衝突的作法是:當衝突發生時,使用某種探測技術在散列表中造成一個探測序列。沿此序列逐個單元地查找,直到找到給定的關鍵字,或者
碰到一個開放的地址(即該地址單元爲空)爲止(若要插入,在探查到開放的地址,則可將待插入的新結點存人該地址單元)。查找時探測到開放的地址則代表表
中無待查的關鍵字,即查找失敗。
好比說,咱們的關鍵字集合爲{12,67,56,16,25,37,22,29,15,47,48,34},表長爲12。 咱們用散列函數f(key) = key mod l2
當計算前S個數{12,67,56,16,25}時,都是沒有衝突的散列地址,直接存入:
計算key = 37時,發現f(37) = 1,此時就與25所在的位置衝突。
因而咱們應用上面的公式f(37) = (f(37)+1) mod 12 = 2。因而將37存入下標爲2的位置:
2, 再哈希法:
再哈希法又叫雙哈希法,有多個不一樣的Hash函數,當發生衝突時,使用第二個,第三個,….,等哈希函數
計算地址,直到無衝突。雖然不易發生彙集,可是增長了計算時間。
3, 鏈地址法:
鏈地址法的基本思想是:每一個哈希表節點都有一個next指針,多個哈希表節點能夠用next指針構成一個單向鏈表,被分配到同一個索引上的多個節點能夠用這個單向
鏈表鏈接起來,如:
鍵值對k2, v2與鍵值對k1, v1經過計算後的索引值都爲2,這時及產生衝突,可是能夠通道next指針將k2, k1所在的節點鏈接起來,這樣就解決了哈希的衝突問題
4, 創建公共溢出區:
這種方法的基本思想是:將哈希表分爲基本表和溢出表兩部分,凡是和基本表發生衝突的元素,一概填入溢出表
參考地址:https://blog.csdn.net/neosmith/article/details/17068365
好了,今天的分享就到這裏了,但願可以幫助到須要面試的道友順利渡劫。高深的問題當然要好好回答,但基礎也不能落下,顧
此失彼致使薪資被砍相信也不是你們但願看到的,反正我是經歷過,很難受,哈哈。