1.哪些情況下的對象會被垃圾回收機制處理掉?
對象不可達時會被標記回收,哪些可以作為GCRoot呢,虛擬機棧,方法區中類靜態屬性引用的對象,方法區中常量引用的對象,本地方法棧JNI引用的對象。
即使不可達到,對象也并非非死不可。1.首先對象會是否有必要執行finalize()方法。2.如果有必要執行,會把對象放到一個隊列中,jvm會開一個線程去回收它們,這是對象最后一次可以逃脫清理的機會。
2.utf-8編碼中的中文占幾個字節;int型幾個字節?
中文utf是占有3個字節,英文字母占1個字節,int占4個字節
3.談談你對解析與分派的認識?
1.方法在程序真正運行之前就有一個可確定的調用版本,并且這個方法的調用版本在運行期間是不可變的,即“編譯時可知,運行不可以變”,這類目標的方法的調用稱之為解析
2.解析調用一定是個靜態的過程,在編譯期就完全確定,在類加載的解析階段就將涉及的符號引用全部轉變為可以確定的直接引用,不會延遲到運行期再去完成。而分派(Dispatch)調用則可能是靜態的也可能是動的。于是分派方式就有靜態分派和動態分派。
靜態分派的最直接的解釋是在重載的時候是通過參數的靜態類型而不是實際類型作為判斷依據的。因此在編譯階段,Javac編譯器會根據參數的靜態類型決定使用哪個重載版本。
顯然這里不可能根據靜態類型來決定調用那個方法。導致這個現象很明顯的原因是因為這兩個變量的實際類型不一樣,jvm根據實際類型來分派方法執行版本。
4.修改對象A的equals方法的簽名,那么使用HashMap存放這個對象實例的時候,會調用哪個equals方法?
會調用對象對象的equals方法。
“==”如果是基本類型的話就是看他們的數據值是否相等就可以。
如果是引用類型的話,比較的是棧內存局部變量表中指向堆內存中的指針的值是否相等
“equals”如果對象的equals方法沒有重寫的話,equals方法和“==”是同一種。
hashcod是返回對象實例內存地址的hash映射。
理論上所有對象的hash映射都是不相同的。
問題:
1.你用過hashmap么?
答:是的,然后回答HashMap的一些特性,譬如HashMap可以接受null鍵值和值,而Hashtable則不能;HashMap是非synchronized;HashMap很快;以及HashMap儲存的是鍵值對等等。
2.你知道hashmap的工作原理么?
答:HashMap是基于hashing的原理,我們使用put(key, value)存儲對象到HashMap中,使用get(key)從HashMap中獲取對象。當我們給put()方法傳遞鍵和值時,我們先對鍵調用hashCode()方法,返回的hashCode用于找到bucket位置來儲存Entry對象。”這里關鍵點在于指出,HashMap是在bucket中儲存鍵對象和值對象,作為Map.Entry。這一點有助于理解獲取對象的邏輯。如果你沒有意識到這一點,或者錯誤的認為僅僅只在bucket中存儲值的話,你將不會回答如何從HashMap中獲取對象的邏輯。這個答案相當的正確,也顯示出面試者確實知道hashing以及HashMap的工作原理。但是這僅僅是故事的開始,當面試官加入一些Java程序員每天要碰到的實際場景的時候,錯誤的答案頻現。
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
3.當兩個對象的hashcode相同會發生什么?
因為即使hashcode相同,但是equals不同。
因為hashcode相同,所以它們的bucket位置相同,‘碰撞’會發生。因為HashMap使用鏈表存儲對象,這個Entry(包含有鍵值對的Map.Entry對象)會存儲在鏈表中。
4.如果兩個鍵的hashcode相同,你如何獲取值對象?
當我們調用get()方法,HashMap會使用鍵對象的hashcode找到bucket位置,然后獲取值對象。
5.面試官提醒他如果有兩個值對象儲存在同一個bucket?
將會遍歷鏈表直到找到值對象
6.因為你并沒有值對象去比較,你是如何確定確定找到值對象的?
找到bucket位置之后,會調用keys.equals()方法去找到鏈表中正確的節點,最終找到要找的值對象。
一些優秀的開發者會指出使用不可變的、聲明作final的對象,并且采用合適的equals()和hashCode()方法的話,將會減少碰撞的發生,提高效率。不可變性使得能夠緩存不同鍵的hashcode,這將提高整個獲取對象的速度,使用String,Interger這樣的wrapper類作為鍵是非常好的選擇。
7.如果HashMap的大小超過了負載因子(load factor)定義的容量,怎么辦?
默認的負載因子大小為0.75,也就是說,當一個map填滿了75%的bucket時候,和其它集合類(如ArrayList等)一樣,將會創建原來HashMap大小的兩倍的bucket數組,來重新調整map的大小,并將原來的對象放入新的bucket數組中。這個過程叫作rehashing,因為它調用hash方法找到新的bucket位置。
8.使用concurrentHashMap在多線程下的操作
- 一個ConcurrentHashMap由多個segment組成,每一個segment都包含了一個HashEntry數組的hashtable, 每一個segment包含了對自己的HashEntry的操作,比如get,put,replace等操作,這些操作發生的時候,對自己的HashEntry進行鎖定。由于每一個segment寫操作只鎖定自己的HashEntry,所以可能存在多個線程同時寫的情況,性能無疑好于只有一個HashEntry鎖定的情況。
2.Segment繼承了ReentrantLock,所以它就是一種可重入鎖(ReentrantLock)。在ConcurrentHashMap,一個Segment就是一個子哈希表,Segment里維護了一個HashEntry數組,并發環境下,對于不同Segment的數據進行操作是不用考慮鎖競爭的。
3.在ConcurrentHashMap的remove,put操作還是比較簡單的,都是將remove或者put操作交給key所對應的segment去做的,所以當幾個操作不在同一個segment的時候就可以并發的進行。在這里面定義了一個
volatile count,count = c的操作必須在modCount,table等操作的后面,這樣才能保證這些變量操作的可見性。
4.在鎖定了這個segement后,get操作并沒有使用lock,因為他得到了上面的count,所以count != 0之后,我們可以認為對應的hashtable是最新的,當然由于讀取的時候沒有加鎖,在get的過程中,可能會有更新。當發現根據key去找元素的時候,但發現找得的key對應的value為null,這個時候可能會有其他線程正在對這個元素進行寫操作,所以需要在使用鎖的情況下在讀取一下value,以確保最終的值。
5.談一談對String類的理解
1.String類是final類是不可以被繼承的,并且他的成員方法默認是final方法。java中final方法是不可以被繼承的
2.String對象一旦被創建就是固定不變的了,對String對象的任何改變都不影響到原對象,相關的任何change操作都會生成新的對象
3.每當我們創建字符串常量時,JVM會首先檢查字符串常量池,如果該字符串已經存在常量池中,那么就直接返回常量池中的實例引用。如果字符串不存在常量池中,就會實例化該字符串并且將其放到常量池中。由于String字符串的不可變性我們可以十分肯定常量池中一定不存在兩個相同的字符
靜態常量池:即*.class文件中的常量池,class文件中的常量池不僅僅包含字符串(數字)字面量,還包含類、方法的信息,占用class文件絕大部分空間。
運行時常量池:則是jvm虛擬機在完成類裝載操作后,將class文件中的常量池載入到內存中,并保存在方法區中,我們常說的常量池,就是指方法區中的運行時常量池。
4.intern方法使用:一個初始為空的字符串池,它由類String獨自維護。當調用 intern方法時,如果池已經包含一個等于此String對象的字符串(用equals(oject)方法確定),則返回池中的字符串。否則,將此String對象添加到池中,并返回此String對象的引用。
6.說一下泛型原理,并舉例說明
泛型搽除