又到了實習生如濤濤巨浪般的湧入廢品資源回收筒(相對于大多數人),而那些資源回收筒就缺我們這樣的菜鳥,為什麼,因為我們菜啊,因為菜而驕傲,但不能跌了身份啊!!!!
話不多說 ,上實戰經驗
1.站在面試官之上回答問題 ,自我介紹一下 ,不要慫,雖然我不是985 ,我也不是211.但是我是實習生,你缺的那種人,别隐藏了,從我進門起你就想要我 ,因為我是實習生,大膽介紹自己,獲得獎學金 獲得榮譽證書 四六級 大膽說出來,這就是你加薪的好機會,不要太長 三分鐘,最後别忘了介紹你是一名實習生,表明你的目的,你是為了實習而來(誰不是為了錢而來)目的高尚一點。
2.開始問問題了
2.1 又是老生長談的問題 ,可能你看都看膩了
接口和抽象類的差別 。。。。。。從類的單繼承和接口的多實作多繼承,主體說完說方法 抽象類不僅有抽象方法還有普通方法,拜托能不能有點條理性
相同點:
1 接口和抽象類都不能被執行個體化,它們都位于繼承樹的頂端,用于被其他類實作和繼承。
2 接口和抽象類都可以包含抽象方法,實作接口或繼承抽象類的普通子類都必須實作這些抽象方法。
不同點:
1 接口裡隻能包含抽象方法,靜态方法和預設方法,不能為普通方法提供方法實作,抽象類則完全可以包含普通方法。
2 接口裡隻能定義靜态常量,不能定義普通成員變量,抽象類裡則既可以定義普通成員變量,也可以定義靜态常量。
3 接口不能包含構造器,抽象類可以包含構造器,抽象類裡的構造器并不是用于建立對象,而是讓其子類調用這些構造器來完成屬于抽象類的初始化操作。
4 接口裡不能包含初始化塊,但抽象類裡完全可以包含初始化塊。
5 一個類最多隻能有一個直接父類,包括抽象類,但一個類可以直接實作多個接口,通過實作多個接口可以彌補Java單繼承不足。、
這樣回答才稍微符合面試官的心意,為什麼說稍微 ,一看你就是背我的,麻煩你自己組織一下語言,ok!
接下來再問三個S的問題,String ,StringBuffer StringBuilder的差別
先說String ,再說後兩個
因為String用的最多,并且和後面兩個有一緻性的差別
- 首先說運作速度,或者說是執行速度,在這方面運作速度快慢為:StringBuilder > StringBuffer > String
- String最慢的原因:
String為字元串常量,而StringBuilder和StringBuffer均為字元串變量,即String對象一旦建立之後該對象是不可更改的,但後兩者的對象是變量,是可以更改的。
記住String的不斷指派,隻是不斷在建立新的對象,老的對象被GC回收,不要誤認為是一個對象
3.再來說線程安全
StringBuilder線程不安全 ,Buffer線程安全的 ,為什呢 ,StringBuffer中很多方法可以帶有synchronized關鍵字,是以可以保證線程是安全的,那麼你平時是怎麼使用的呢
String:适用于少量的字元串操作的情況
StringBuilder:适用于單線程下在字元緩沖區進行大量操作的情況
StringBuffer:适用多線程下在字元緩沖區進行大量操作的情況
舉個例子吧。
我平時使用常量時會經常使用,會這樣寫定義一個接口
在接口裡在這樣定義常量 interface mmm{
String xx = "xx";
String cc = "cc";}
這樣是為了這個常量可能會被多次調用,也可能被别人調用友善,讓别人很容易讀懂你的代碼,那就說到了為什麼String 是常量呢?
因為他被final修飾 ,是最終類,又說到了final
final關鍵字可以修飾類、方法、字段。修飾類時,這個類不可以被繼承;修飾方法時,這個方法就不可以被覆寫(重寫),在JVM中也就隻有一個版本的方法--實方法;修飾字段時,這個字段就是一個常量。
java.lang.String 這樣説的
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[];
...
}"The String class represents character strings"意思是String類表示字元串;String類被關鍵字final修飾,可以說明它不可被繼承;從"private final char value[]"可知,String本質上是一個char數組。
String類的成員字段value是一個char[]數組,而且也是用final關鍵字修飾,被final關鍵字修飾的字段在建立後其值是不可變的,但也隻是value這個引用位址不可變,可是Array數組的值卻是可變的,Array數組資料結構如下圖所示:

從圖中可以看出,Array變量隻是棧上(stack)的一個引用,數組中的資料存儲在堆上(heap)。String類裡的value是用final修飾,隻能說在棧上(stack)這個value的引用位址不可變,可沒說堆裡的Array本身資料不可變。看下面這個例子:
final int[] value = {1,2,3,4,5};
int otherValue = {6,7,8,9,10};
value = otherValue;//編譯報錯value是被final關鍵字修飾的,編譯器不允許把value指向堆另外一個位址;但如果直接對數組元素進行指派,就允許;如下面這個例子:
final int[] value = {1,2,3,4,5};
value[0] = 0;
是以說String是不可變,在後面所有的String方法裡沒有去動Array中的元素,也沒有暴露内部成員字段。private final char value[],private的私有通路權限的作用都比final大。是以String是不可變的關鍵都是在底層實作的,而不是一個簡單的final關鍵字。
然後這些問完了,再來集合吧
map list set 懂多少 如實招來 ,其實也不懂啥 就知道用了就new嘛
可是面試 又不是寫代碼改需求 比如說給你一個list給我展成樹結構 我會簡單的告訴你兩層for嵌套循環搞定 或者兩層for循環不嵌套,第一層找根,第二層找兒子,遞歸解決,可是面試官不會問的,他要問三個差別,管你怎麼用 ,那你就吹吧
list和set是實作了collection接口的。
List:1.可以允許重複的對象。
2.可以插入多個null元素。
3.是一個有序容器,保持了每個元素的插入順序,輸出的順序就是插入的順序。
4.常用的實作類有 ArrayList、LinkedList 和 Vector。ArrayList 最為流行,它提供了使用索引的随意通路,而 LinkedList 則對于經常需要從 List 中添加或删除元素的場合更為合适。
Set:1.不允許重複對象
2. 無序容器,你無法保證每個元素的存儲順序,TreeSet通過 Comparator 或者 Comparable 維護了一個排序順序。
3. 隻允許一個 null 元素
4.Set 接口最流行的幾個實作類是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 實作的 HashSet;TreeSet 還實作了 SortedSet 接口,是以 TreeSet 是一個根據其 compare() 和 compareTo() 的定義進行排序的有序容器。、
Map:
1.Map不是collection的子接口或者實作類。Map是一個接口。
2.Map 的 每個 Entry 都持有兩個對象,也就是一個鍵一個值,Map 可能會持有相同的值對象但鍵對象必須是唯一的。
3. TreeMap 也通過 Comparator 或者 Comparable 維護了一個排序順序。
4. Map 裡你可以擁有随意個 null 值但最多隻能有一個 null 鍵。
5.Map 接口最流行的幾個實作類是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)
1.如果你經常會使用索引來對容器中的元素進行通路,那麼 List 是你的正确的選擇。如果你已經知道索引了的話,那麼 List 的實作類比如 ArrayList 可以提供更快速的通路,如果經常添加删除元素的,那麼肯定要選擇LinkedList。
但是注意的是你在末尾增删資料未必這樣選,可以自己嘗試一些兩者的速度
畢竟你要明白
ArrayList是實作了基于動态數組的資料結構,LinkedList基于連結清單的資料結構(雙連結清單)。
ArrayList内部是使用可増長數組實作的,是以是用get和set方法是花費常數時間的,但是如果插入元素和删除元素,除非插入和删除的位置都在表末尾,否則代碼開銷會很大,因為裡面需要數組的移動。
LinkedList是使用雙連結清單實作的,是以get會非常消耗資源,除非位置離頭部很近。但是插入和删除元素花費常數時間。
2.如果你想容器中的元素能夠按照它們插入的次序進行有序存儲,那麼還是 List,因為 List 是一個有序容器,它按照插入順序進行存儲。
3.如果你想保證插入元素的唯一性,也就是你不想有重複值的出現,那麼可以選擇一個 Set 的實作類,比如 HashSet、LinkedHashSet 或者 TreeSet。所有 Set 的實作類都遵循了統一限制比如唯一性,而且還提供了額外的特性比如 TreeSet 還是一個 SortedSet,所有存儲于 TreeSet 中的元素可以使用 Java 裡的 Comparator 或者 Comparable 進行排序。LinkedHashSet 也按照元素的插入順序對它們進行存儲。
4.如果你以鍵和值的形式進行資料存儲那麼 Map 是你正确的選擇。你可以根據你的後續需要從 Hashtable、HashMap、TreeMap 中進行選擇。
再說一下hashTable和hashMap的差別吧
HashTable
- 底層數組+連結清單實作,無論key還是value都不能為null,線程安全,實作線程安全的方式是在修改資料時鎖住整個HashTable,效率低,ConcurrentHashMap做了相關優化
- 初始size為11,擴容:newsize = olesize*2+1
- 計算index的方法:index = (hash & 0x7FFFFFFF) % tab.length
HashMap
- 底層數組+連結清單實作,可以存儲null鍵和null值,線程不安全
- 初始size為16,擴容:newsize = oldsize*2,size一定為2的n次幂
- 擴容針對整個Map,每次擴容時,原來數組中的元素依次重新計算存放位置,并重新插入
- 插入元素後才判斷該不該擴容,有可能無效擴容(插入後如果擴容,如果沒有再次插入,就會産生無效擴容)
- 當Map中元素總數超過Entry數組的75%,觸發擴容操作,為了減少連結清單長度,元素配置設定更均勻
- 計算index方法:index = hash & (tab.length – 1)
HashMap的初始值還要考慮加載因子:
- 哈希沖突:若幹Key的哈希值按數組大小取模後,如果落在同一個數組下标上,将組成一條Entry鍊,對Key的查找需要周遊Entry鍊上的每個元素執行equals()比較。
- 加載因子:為了降低哈希沖突的機率,預設當HashMap中的鍵值對達到數組大小的75%時,即會觸發擴容。是以,如果預估容量是100,即需要設定100/0.75=134的數組大小。
- 空間換時間:如果希望加快Key查找的時間,還可以進一步降低加載因子,加大初始大小,以降低哈希沖突的機率。
HashMap和Hashtable都是用hash算法來決定其元素的存儲,是以HashMap和Hashtable的hash表包含如下屬性:
- 容量(capacity):hash表中桶的數量
- 初始化容量(initial capacity):建立hash表時桶的數量,HashMap允許在構造器中指定初始化容量
- 尺寸(size):目前hash表中記錄的數量
- 負載因子(load factor):負載因子等于“size/capacity”。負載因子為0,表示空的hash表,0.5表示半滿的散清單,依此類推。輕負載的散清單具有沖突少、适宜插入與查詢的特點(但是使用Iterator疊代元素時比較慢)
除此之外,hash表裡還有一個“負載極限”,“負載極限”是一個0~1的數值,“負載極限”決定了hash表的最大填滿程度。當hash表中的負載因子達到指定的“負載極限”時,hash表會自動成倍地增加容量(桶的數量),并将原有的對象重新配置設定,放入新的桶内,這稱為rehashing。
HashMap和Hashtable的構造器允許指定一個負載極限,HashMap和Hashtable預設的“負載極限”為0.75,這表明當該hash表的3/4已經被填滿時,hash表會發生rehashing。
“負載極限”的預設值(0.75)是時間和空間成本上的一種折中:
- 較高的“負載極限”可以降低hash表所占用的記憶體空間,但會增加查詢資料的時間開銷,而查詢是最頻繁的操作(HashMap的get()與put()方法都要用到查詢)
- 較低的“負載極限”會提高查詢資料的性能,但會增加hash表所占用的記憶體開銷
程式猿可以根據實際情況來調整“負載極限”值。
ConcurrentHashMap
- 底層采用分段的數組+連結清單實作,線程安全
- 通過把整個Map分為N個Segment,可以提供相同的線程安全,但是效率提升N倍,預設提升16倍。(讀操作不加鎖,由于HashEntry的value變量是 volatile的,也能保證讀取到最新的值。)
- Hashtable的synchronized是針對整張Hash表的,即每次鎖住整張表讓線程獨占,ConcurrentHashMap允許多個修改操作并發進行,其關鍵在于使用了鎖分離技術
- 有些方法需要跨段,比如size()和containsValue(),它們可能需要鎖定整個表而而不僅僅是某個段,這需要按順序鎖定所有段,操作完畢後,又按順序釋放所有段的鎖
- 擴容:段内擴容(段内元素超過該段對應Entry數組長度的75%觸發擴容,不會對整個Map進行擴容),插入前檢測需不需要擴容,有效避免無效擴容
Hashtable和HashMap都實作了Map接口,但是Hashtable的實作是基于Dictionary抽象類的。Java5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的擴充性更好。
HashMap基于哈希思想,實作對資料的讀寫。當我們将鍵值對傳遞給put()方法時,它調用鍵對象的hashCode()方法來計算hashcode,然後找到bucket位置來存儲值對象。當擷取對象時,通過鍵對象的equals()方法找到正确的鍵值對,然後傳回值對象。HashMap使用連結清單來解決碰撞問題,當發生碰撞時,對象将會儲存在連結清單的下一個節點中。HashMap在每個連結清單節點中儲存鍵值對對象。當兩個不同的鍵對象的hashcode相同時,它們會儲存在同一個bucket位置的連結清單中,可通過鍵對象的equals()方法來找到鍵值對。如果連結清單大小超過門檻值(TREEIFY_THRESHOLD,8),連結清單就會被改造為樹形結構。
在HashMap中,null可以作為鍵,這樣的鍵隻有一個,但可以有一個或多個鍵所對應的值為null。當get()方法傳回null值時,即可以表示HashMap中沒有該key,也可以表示該key所對應的value為null。是以,在HashMap中不能由get()方法來判斷HashMap中是否存在某個key,應該用containsKey()方法來判斷。而在Hashtable中,無論是key還是value都不能為null。
Hashtable是線程安全的,它的方法是同步的,可以直接用在多線程環境中。而HashMap則不是線程安全的,在多線程環境中,需要手動實作同步機制。
Hashtable與HashMap另一個差別是HashMap的疊代器(Iterator)是fail-fast疊代器,而Hashtable的enumerator疊代器不是fail-fast的。是以當有其它線程改變了HashMap的結構(增加或者移除元素),将會抛出ConcurrentModificationException,但疊代器本身的remove()方法移除元素則不會抛出ConcurrentModificationException異常。但這并不是一個一定發生的行為,要看JVM。
先看一下簡單的類圖:
看到别的筆友畫好直接拿來用了
從類圖中可以看出來在存儲結構中ConcurrentHashMap比HashMap多出了一個類Segment,而Segment是一個可重入鎖。
ConcurrentHashMap是使用了鎖分段技術來保證線程安全的。
鎖分段技術:首先将資料分成一段一段的存儲,然後給每一段資料配一把鎖,當一個線程占用鎖通路其中一個段資料的時候,其他段的資料也能被其他線程通路。
ConcurrentHashMap提供了與Hashtable和SynchronizedMap不同的鎖機制。Hashtable中采用的鎖機制是一次鎖住整個hash表,進而在同一時刻隻能由一個線程對其進行操作;而ConcurrentHashMap中則是一次鎖住一個桶。
ConcurrentHashMap預設将hash表分為16個桶,諸如get、put、remove等常用操作隻鎖住目前需要用到的桶。這樣,原來隻能一個線程進入,現在卻能同時有16個寫線程執行,并發性能的提升是顯而易見的。
到此基本問完了
再說說事務啥的 直接跟他說我都是用的Spring注解@Transactional異步方法經常用@Aysnc 最簡單的例子我要執行job 但是執行會需要時間,為了讓頁面繼續能工作 我直接将執行狀态改變 改為我可以工作的狀态,好了下次再說吧 ,面試還早 我要早點休息
大保健開始咯!!!晚安 菜鳥們