1寝姿、基礎(chǔ)類型(Primitives)與封裝類型(Wrappers)的區(qū)別?
1)傳遞方式不同
基本類型都是按值傳遞簇捍;
封裝類型是按引用傳遞的(其實“引用也是按值傳遞的”,傳遞的是對象的地址)俏拱。
2)封裝類可以有方法和屬性
基本數(shù)據(jù)類型都是final修飾的暑塑,不能繼承擴展新的類、新的方法锅必。
封裝類可以有方法和屬性梯投,利用這些方法和屬性來處理數(shù)據(jù)。
3)默認值不同
基本類型跟封裝類型的默認值是不一樣的况毅。如int i,i的預(yù)設(shè)為0分蓖;Integer j,j的預(yù)設(shè)為null,因為封裝類產(chǎn)生的是對象尔许,對象默認值為null么鹤。
4)存儲位置不同
基本類型是存儲在棧中;
引用類型的引用(值的地址)存儲在棧中味廊,而實際的對象(值)是存在堆中蒸甜。
基本數(shù)據(jù)類型的好處是速度快(不涉及到對象的構(gòu)造和回收),封裝類的目的主要是更好的處理數(shù)據(jù)之間的轉(zhuǎn)換余佛。
2柠新、簡述九種基本數(shù)據(jù)類型的大小,以及他們的封裝類
基本類型 大小(字節(jié)) 默認值 封裝類
byte 1 (byte)0 Byte
short 2 (short)0 Short
int 4 0 Integer
long 8 0L Long
float 4 0.0f Float
double 8 0.0d Double
boolean - boolean的大小JVM規(guī)范并沒有指定辉巡, 取決于jvm的實現(xiàn)恨憎。1byte的可能性多。 false Boolean
char 2 \u0000(null) Character
void - - Void
3郊楣、int和Integer哪個會占用更多的內(nèi)存憔恳?int和Integer有什么區(qū)別?
Integer對象會占用更多的內(nèi)存净蚤。Integer是一個對象钥组,需要存儲對象的元數(shù)據(jù)。
int是一個原始類型的數(shù)據(jù)今瀑,所以占用的空間更少程梦。
其他區(qū)別:
Integer變量是對一個Integer對象的引用。當(dāng)new一個Integer時橘荠,實際上是生成一個指針指向此對象屿附,兩次new Integer生成的是兩個對象,其內(nèi)存地址不同砾医,所以兩個new出來的Integer變量不等拿撩。
非new生成的Integer變量指向的是java常量池中的對象衣厘,而new Integer()生成的變量指向堆中新建的對象如蚜,兩者在內(nèi)存中的地址不同压恒。
兩個非new生成的Integer對象進行比較,如果兩個變量的值在區(qū)間[-128,127]之間错邦,比較結(jié)果為true探赫;否則,結(jié)果為false撬呢。
java會將[-128,127]之間的數(shù)進行緩存伦吠。Integer i1 = 127時,會將127緩存魂拦,Integer j2 = 127時毛仪,就直接從緩存中取,不會new芯勘。
Integer變量(無論是否是new生成的)與int變量比較箱靴,只要兩個變量的值是相等的,結(jié)果都為true荷愕。包裝類Integer變量在與基本數(shù)據(jù)類型int變量比較時衡怀,Integer會自動拆包裝為int,然后進行比較安疗,實際上就是兩個int變量進行比較抛杨,值相等,所以為true荐类。
4怖现、如何取小數(shù)四舍五入保留小數(shù)點后兩位?
double f = 3.1415926;
BigDecimal bg = new BigDecimal(f);
double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
或者
Double get_double = (double) (Math.round(d * 100) / 100.0);
5玉罐、char型變量中能否存貯一個中文漢字真竖?
可以,如果某個特殊的漢字沒有被包含在unicode編碼字符集中厌小,那么這個char型變量中就不能存儲這個特殊漢字恢共。
1)char型變量是用來存儲Unicode編碼的字符的,unicode編碼字符集中包含了漢字璧亚。unicode編碼占用兩個字節(jié)讨韭,所以char類型的變量也是占用兩個字節(jié)。
2)在Java中癣蟋,char類型可以存儲一個中文漢字透硝,因為Java中使用的編碼是Unicode(不選擇任何特定的編碼,直接使用字符在字符集中的編號疯搅,這是統(tǒng)一的唯一方法)濒生,一個char類型占2個字節(jié)(16比特),放一個中文是沒問題的幔欧。
6罪治、如何將數(shù)值型字符轉(zhuǎn)換為數(shù)字丽声?
int類型就是 Integer.parseInt(str);
byte類型就是 Byte.parseByte(str)
short類型就是 Short.parseShort(str)
float類型就是 Float.parseFloat(str)
char 類型就是 Character.parseChar(str)
7、能將int強制轉(zhuǎn)換為byte類型嗎觉义?如果值大于byte類型的范圍雁社,將會出現(xiàn)什么現(xiàn)象?
int類型的占4個字節(jié)晒骇,而byte占1個字節(jié)霉撵,所以int類型轉(zhuǎn)化為byte類型時會出現(xiàn)位丟失情況,將int的低8位作為byte類型的值洪囤。
8徒坡、能在不進行強制轉(zhuǎn)換的情況下將一個double值賦值給long類型的變量嗎?
不行瘤缩,double類型的范圍比long類型更廣崭参,必須要進行強制轉(zhuǎn)換。
9款咖、類型向下轉(zhuǎn)換是什么何暮?
子類可以自動向上轉(zhuǎn)換成父類型,只是部分內(nèi)存空間無法訪問铐殃,只能訪問父類型在子類中的方法和變量;
父類型向下轉(zhuǎn)換成子類型海洼,必須滿足父類型變量是子類型實例化對象,就是原本一個子類實例;
10富腊、如何權(quán)衡是使用無序的數(shù)組還是有序的數(shù)組坏逢?
查找的時間復(fù)雜度:有序數(shù)組O(log(n)),無序數(shù)組O(n)。
插入的時間復(fù)雜度:有序數(shù)組O(n)赘被,無序數(shù)組O(1)是整。
11、怎么判斷數(shù)組是null還是為空民假?
數(shù)組為null:是創(chuàng)建了數(shù)組的引用浮入,但在堆中并沒有數(shù)組中的元素
數(shù)組為空:數(shù)組是空其實就是數(shù)組的長度為0,數(shù)組是真正的對象羊异,只是對象中沒有元素.
判斷數(shù)組為空:array.length==0
判斷數(shù)組為null:直接使用變量名==null
12事秀、怎么打印數(shù)組?
1)for循環(huán)方式
2)for each循環(huán)
3)利用Array類中的toString方法
13野舶、Array 和 ArrayList有什么區(qū)別易迹?什么時候應(yīng)該使用Array而不是ArrayList?
Array可以包含基本類型和對象類型平道,ArrayList只能包含對象類型睹欲。
Array大小是固定的,ArrayList的大小是動態(tài)變化的一屋。
ArrayList提供了更多的方法和特性窘疮,比如:addAll()袋哼,removeAll(),iterator()等考余。
適用場景:
Array:保存不變的數(shù)據(jù)先嬉;
ArrayList:只想以數(shù)組的形式保存數(shù)據(jù)轧苫,只是方便查找楚堤,不對數(shù)據(jù)進行增加等操作。
LinkedList:對元素進行頻繁的移動或刪除含懊,或處理量很大身冬。
14、數(shù)組和鏈表數(shù)據(jù)結(jié)構(gòu)描述岔乔,各自的時間復(fù)雜度酥筝?
數(shù)組是將元素在內(nèi)存中連續(xù)存放,由于每個元素占用內(nèi)存相同雏门,可通過下標迅速訪問數(shù)組中任何元素嘿歌。但在數(shù)組中增加一個元素,需要移動大量元素茁影,在內(nèi)存中空出一個元素的空間宙帝,然后將要增加的元素放在其中。同樣如果想刪除一個元素募闲,同樣需要移動大量元素去填掉被移動的元素步脓。如果應(yīng)用需要快速訪問數(shù)據(jù),很少或不插入和刪除元素浩螺,就應(yīng)該用數(shù)組靴患。
鏈表中的元素在內(nèi)存中不是順序存儲的,而是通過元素中的指針聯(lián)到一起要出。比如:上一個元素有個指針指到下一個元素鸳君,以此類推,直到最后一個元素患蹂。如果要訪問鏈表中一個元素相嵌,需要從第一個元素開始,一直找到需要的元素位置况脆。但是增加和刪除一個元素只要修改元素中的指針就可以了饭宾。如果經(jīng)常插入和刪除元素就需要用鏈表數(shù)據(jù)結(jié)構(gòu)。
● (靜態(tài))數(shù)組從棧中分配空間, 對于程序員方便快速,但自由度小格了。
● 鏈表從堆中分配空間, 自由度大但申請管理比較麻煩看铆。
● 數(shù)組利用下標定位,時間復(fù)雜度為O(1)盛末,鏈表定位元素時間復(fù)雜度O(n)弹惦;
● 數(shù)組插入或刪除元素的時間復(fù)雜度O(n)否淤,鏈表的時間復(fù)雜度O(1)。
15棠隐、數(shù)組有沒有l(wèi)ength()這個方法? String有沒有l(wèi)ength()這個方法石抡?
數(shù)組只有l(wèi)ength屬性,array.length返回數(shù)組長度助泽。
String有l(wèi)ength()方法啰扛,str.length()返回字符串長度。
16嗡贺、隊列和棧是什么隐解,它們的區(qū)別?
隊列(Queue):只能在表的一端插入和在另一端進行刪除操作的線性表诫睬;
棧(Stack):是限定只能在表的一端進行插入和刪除操作的線性表煞茫;
隊列先進先出(FIFO),棧先進后出(FILO)摄凡;
17续徽、BlockingQueue是什么?
通過一個共享的隊列亲澡,可以使得數(shù)據(jù)由隊列的一端輸入钦扭,從另外一端輸出;
常用的隊列主要有以下兩種:
先進先出(FIFO):先插入的隊列的元素最先出隊列谷扣,類似于排隊土全。
后進先出(LIFO):后插入隊列的元素最先出隊列。
當(dāng)隊列中沒有數(shù)據(jù)時会涎,消費者端的所有線程都會被自動阻塞(掛起)裹匙,直到有數(shù)據(jù)放入隊列。
當(dāng)隊列中填滿數(shù)據(jù)時末秃,生產(chǎn)者端的所有線程都會被自動阻塞(掛起)概页,直到隊列中有空的位置,線程被自動喚醒练慕。
BlockingQueue的核心方法:
1)放入數(shù)據(jù)
offer(anObject):將anObject加到BlockingQueue里惰匙,如果可以容納,則返回true,否則返回false.(本方法不阻塞當(dāng)前執(zhí)行方法的線程);
offer(E o, long timeout, TimeUnit unit):可以設(shè)定等待的時間铃将,如果不能往隊列中加入项鬼,則返回失敗。
put(anObject):把anObject加到BlockingQueue里劲阎,如果沒有空間绘盟,則調(diào)用此方法的線程被阻斷直到BlockingQueue里面有空間再繼續(xù).
2)獲取數(shù)據(jù)
poll(time):取走BlockingQueue里排在首位的對象,若不能立即取出,則可以等time參數(shù)規(guī)定的時間,取不到時返回null;
poll(long timeout, TimeUnit unit):從BlockingQueue取出一個隊首的對象,如果在指定時間內(nèi),隊列一旦有數(shù)據(jù)可取龄毡,則立即返回隊列中的數(shù)據(jù)吠卷。否則直到時間超時還沒有數(shù)據(jù),返回失敗沦零。
take():取走BlockingQueue里排在首位的對象祭隔,若BlockingQueue為空,阻斷進入等待狀態(tài)直到BlockingQueue有新的數(shù)據(jù)被加入;
drainTo():一次性從BlockingQueue獲取所有可用的數(shù)據(jù)對象(還可以指定獲取數(shù)據(jù)的個數(shù));不需要多次分批加鎖或釋放鎖路操。
18疾渴、簡述 ConcurrentLinkedQueue LinkedBlockingQueue 的用處和不同之處?
線程安全的Queue可以分為阻塞隊列BlockingQueue和非阻塞隊列ConcurrentLinkedQueue寻拂;
LinkedBlockingQueue:是一個線程安全的阻塞隊列程奠,實現(xiàn)了BlockingQueue接口丈牢,增加了take和put方法祭钉;可以指定容量,也可以不指定己沛,不指定的話慌核,默認最大是Integer.MAX_VALUE,其中主要用到put和take方法申尼,put方法在隊列滿的時候會阻塞直到有隊列成員被消費垮卓,take方法在隊列空的時候會阻塞,直到有隊列成員被放進來师幕。
ConcurrentLinkedQueue:是Queue的一個安全實現(xiàn).Queue中元素按FIFO原則進行排序.采用CAS操作粟按,來保證元素的一致性。
19霹粥、ArrayList灭将、Vector、LinkedList的存儲性能和特性后控?
ArrayList和Vector底層的實現(xiàn)都是使用數(shù)組方式存儲數(shù)據(jù)庙曙,此數(shù)組元素數(shù)大于實際存儲的數(shù)據(jù)以便增加和插入元素,都允許直接按序號索引元素浩淘,但插入元素要涉及數(shù)組元素移動等內(nèi)存操作捌朴,所以索引數(shù)據(jù)快而插入慢。
Vector中的方法添加了synchronized修飾张抄,是線程安全的容器砂蔽,性能上較ArrayList差。
LinkedList使用雙向鏈表實現(xiàn)存儲署惯,按序號索引數(shù)據(jù)需要進行前向或后向遍歷左驾,但插入數(shù)據(jù)時只需要記錄本項的前后項,插入速度較快。
20什荣、ByteBuffer與StringBuffer有什么區(qū)別矾缓?
ByteBuffer是NIO中的buffer。
StringBuffer是字符串連接用的buffer類稻爬。
21嗜闻、HashMap的工作原理是什么,內(nèi)部的數(shù)據(jù)結(jié)構(gòu)是什么桅锄?
HashMap和Hashtable的底層都是數(shù)組+鏈表結(jié)構(gòu)實現(xiàn);通過put(key,value)和get(key)方法存儲和獲取對象元素琉雳,將key值傳遞給put()時,會自動調(diào)用對象的hashcode()計算hashcode友瘤,然后根據(jù)hashcode確定對象存儲位置翠肘;獲取對象時,根據(jù)鍵對象的equals()找到具體的鍵值對Entry辫秧,返回值對象束倍;
HashMap使用鏈表方式解決hash沖突,發(fā)生hash沖突時盟戏,會將對象存儲在鏈表的下一個節(jié)點上;
HashMap線程不安全绪妹,CourrentHashMap線程安全(利用分段鎖鎖住map的一部分);
HashMap初始化時會創(chuàng)建默認容量為16的Entry數(shù)組,默認加載因子為0.75柿究,臨界值為16*0.75;
22邮旷、HashMap的table的容量如何確定?loadFactor是什么蝇摸?該容量如何變化婶肩?這種變化會帶來什么問題?
initialCapacity = (需要存儲的元素個數(shù) / 負載因子) + 1貌夕。
HashMap默認的加載因子是0.75律歼,最大容量是16,默認容量是:0.75*16=12蜂嗽; 如果無法確定初始值大小苗膝,請設(shè)置為16(即默認值)。
loadFactor加載因子表示Hsah表中元素的填滿程度植旧。
加載因子越大辱揭,空間利用率越高,沖突機會越大病附;
加載因子越小问窃,空間利用率越少,沖突機會越型昊Α域庇;
23嵌戈、HashMap和HashTable、ConcurrentHashMap的區(qū)別听皿?
HashTable
1)底層數(shù)組+鏈表實現(xiàn)熟呛,無論key還是value都不能為null,線程安全尉姨,實現(xiàn)線程安全的方式是在修改數(shù)據(jù)時鎖住整個HashTable庵朝,效率低
2)初始size為11,擴容:newsize = oldsize*2+1
3)計算index的方法:index = (hash & 0x7FFFFFFF) % tab.length
HashMap
1)底層數(shù)組+鏈表實現(xiàn)又厉,可以存儲null鍵和null值答捕,線程不安全
2)初始size為16败晴,擴容:newsize = oldsize*2杜窄,size一定為2的n次冪
3)擴容針對整個Map望抽,每次擴容時,原數(shù)組中的元素依次重新計算存放位置煌妈,并重新插入
4)插入元素后才判斷該不該擴容儡羔,有可能無效擴容
5)當(dāng)Map中元素總數(shù)超過Entry數(shù)組的75%,觸發(fā)擴容操作声旺,為減少鏈表長度笔链,元素分配更均勻
6)計算index方法:index = hash & (tab.length – 1)
ConcurrentHashMap
1)底層采用分段的數(shù)組+鏈表實現(xiàn)段只,線程安全
2)把整個Map分為N個Segment腮猖,可以提供相同的線程安全,效率默認提升16倍赞枕。(讀操作不加鎖澈缺,由于HashEntry的value變量是volatile的,也能保證讀取到最新的值炕婶。)
3)Hashtable的synchronized是針對整張Hash表的姐赡,即每次鎖住整張表讓線程獨占,ConcurrentHashMap允許多個修改操作并發(fā)進行柠掂,其關(guān)鍵在于使用了鎖分離技術(shù)
4)有些方法需要跨段项滑,比如size()和containsValue(),可能需要鎖定整個表涯贞,這需要按順序鎖定所有段枪狂,操作完畢后,按順序釋放所有段的鎖
5)擴容:段內(nèi)擴容(段內(nèi)元素超過該段對應(yīng)Entry數(shù)組長度的75%觸發(fā)擴容宋渔,不會對整個Map進行擴容)州疾,插入前檢測需不需要擴容,有效避免無效擴容
24皇拣、HashMap的遍歷方式及效率严蓖?
1)顯式調(diào)用map.entrySet()集合迭代器
Iterator iter1 = map.entrySet().iterator();
2)foreach增強for循環(huán)實現(xiàn)entrySet
for (Entry<Integer, String> str : map.entrySet())
3)顯式調(diào)用map.keySet()集合迭代器
Iterator iter2 = map.keySet().iterator();
4)foreach增強for循環(huán)實現(xiàn)keySet
for (Integer str : map.keySet())
效率:
1)當(dāng)需要key也需要value時薄嫡,選擇entrySet
2)當(dāng)只是遍歷key而無需取value的話,使用keySet颗胡。
3)foreach更簡潔毫深,推薦使用。
25毒姨、HashMap费什、LinkedMap、TreeMap的區(qū)別手素?
HashMap:根據(jù)鍵的HashCode值存儲數(shù)據(jù),根據(jù)鍵可以直接獲取它的值鸳址,訪問速度快。最多只允許一條記錄的鍵為Null;允許多條記錄的值為Null;不支持線程同步泉懦。
LinkedHashMap:保存記錄的插入順序稿黍,也可以在構(gòu)造時帶參數(shù),按照應(yīng)用次數(shù)排序崩哩。
當(dāng)HashMap容量很大巡球,實際數(shù)據(jù)較少時,遍歷速度比LinkedHashMap慢邓嘹,因為LinkedHashMap的遍歷速度只和實際數(shù)據(jù)有關(guān)酣栈,和容量無關(guān),而HashMap的遍歷速度和容量有關(guān)汹押。
TreeMap實現(xiàn)SortMap接口矿筝,能夠把保存的記錄根據(jù)鍵排序,默認按鍵的升序棚贾,也可以指定排序的比較器窖维,當(dāng)用Iterator遍歷TreeMap時,得到的記錄是排過序的妙痹。
26铸史、如何決定選用HashMap還是TreeMap?
TreeMap<K,V>的Key值是要求實現(xiàn)java.lang.Comparable怯伊,迭代的時候TreeMap默認是按照Key值升序排序的琳轿;TreeMap的實現(xiàn)也是基于紅黑樹結(jié)構(gòu)。
HashMap<K,V>的Key值實現(xiàn)散列hashCode()耿芹,分布是散列均勻的崭篡,不支持排序;數(shù)據(jù)結(jié)構(gòu)主要是桶(數(shù)組)猩系,鏈表或紅黑樹媚送。
HashMap有更好的性能,不要排序時用HashMap寇甸。
27塘偎、如果HashMap的大小超過了負載因子(load factor)定義的容量疗涉,怎么辦?
默認負載因子大小為0.75吟秩,當(dāng)一個map填滿了75%的bucket時候咱扣,和其它集合類(如ArrayList等)一樣,將會創(chuàng)建原來HashMap大小的兩倍的bucket數(shù)組涵防,來重新調(diào)整map的大小闹伪,并將原來的對象放入新的bucket數(shù)組中。這個過程叫作rehashing壮池,因為它調(diào)用hash方法找到新的bucket位置偏瓤。
28、HashMap是線程安全的嗎椰憋?并發(fā)下使用的Map是什么厅克,它們內(nèi)部原理分別是什么,比如存儲方式橙依、hashcode证舟、擴容、默認容量等窗骑?
HashMap非線程安全
并發(fā)下使用ConcurrentHashMap女责,其工作機制是通過把整個Map分為N個Segment,可以提供相同的線程安全创译,效率提升N倍抵知,默認提升16倍。根據(jù)key.hashCode()來決定把key放到哪個分段中昔榴。
ConcurrentHashMap是一個Segment數(shù)組辛藻,Segment通過繼承ReentrantLock進行加鎖,每次鎖住的是一個segment互订,只要保證每個Segment是線程安全的,也就實現(xiàn)了全局線程安全痘拆。
● Segment數(shù)組長度為16仰禽,不可以擴容
● Segment[i]的默認大小為2,負載因子是0.75纺蛆,得出初始閾值為1.5吐葵,也就是以后插入第一個元素不會觸發(fā)擴容,插入第二個會進行第一次擴容桥氏;
29温峭、HashSet和TreeSet有什么區(qū)別?
1)HashSet數(shù)據(jù)是無序的字支,TreeSet數(shù)據(jù)是有序的凤藏。
2)TreeSet保存自定義類對象時奸忽,自定義所在的類一定要實現(xiàn)Comparable接口,否則無法區(qū)分大小關(guān)系揖庄,而且在TreeSet中如果要進行排序栗菜,就要將所有的字段都進行比較,在TreeSet中是依靠comparato()方法返回結(jié)果是否為0來判斷重復(fù)元素蹄梢。
3)HashSet子類疙筹,其判斷重復(fù)數(shù)據(jù)的方式是Object類之中的兩個方法:(1)取得對象的哈希碼hashCode();(2)對象比較:equals()禁炒;
30而咆、HashSet內(nèi)部是如何工作的?
HashSet內(nèi)部采用HashMap來實現(xiàn)幕袱。由于Map需要key和value翘盖,所以HashSet中所有key的都有一個默認value。HashSet不允許重復(fù)的key凹蜂,只允許有一個null key馍驯。
31、WeakHashMap是怎么工作的玛痊?
WeakHashMap:只有自身有對key的引用汰瘫,那么WeakHashMap會在下次進行增刪改查操作時丟棄該鍵值對,節(jié)約內(nèi)存使用擂煞,此特性使得WeakHashMap非常適合構(gòu)建緩存系統(tǒng)混弥。
WeakHashMap主要通過expungeStaleEntries函數(shù)來實現(xiàn)移除其內(nèi)部不用的entry達到自動釋放內(nèi)存的目的《允。基本上只要對WeakHashMap的內(nèi)容進行訪問就會調(diào)用expungeStaleEntries函數(shù)蝗拿,從而達到清除不再被外部引用的key對應(yīng)的entry鍵值對。
32蒿涎、Set里的元素是不能重復(fù)的哀托,用什么方法來區(qū)分重復(fù)與否呢?用==還是 equals()劳秋, 有何區(qū)別?
Set是Collection容器的一個子接口仓手,不允許出現(xiàn)重復(fù)元素,只允許有一個null對象玻淑。
使用equals()區(qū)分元素是否重復(fù)嗽冒;
33、TreeMap是采用什么樹實現(xiàn)的补履?TreeMap和TreeSet在排序時如何比較元素添坊?Collections工具類中的sort()方法如何比較元素?
TreeMap是紅黑樹算法的實現(xiàn)箫锤;
TreeSet要求存放的對象所屬類必須實現(xiàn)Comparable接口贬蛙,該接口提供了比較元素的compareTo()方法雨女,當(dāng)插入元素時會回調(diào)該方法比較元素的大小。
TreeMap要求存放的鍵值對映射的鍵必須實現(xiàn)Comparable接口從而根據(jù)鍵對元素進行排序速客。
Collections工具類的sort方法有兩種重載的形式戚篙,第一種要求待排序容器中存放的對象必須實現(xiàn)Comparable接口以實現(xiàn)元素的比較;第二種不強制性要求容器中的元素必須可比較溺职,但要求傳入第二個參數(shù)岔擂,參數(shù)是Comparator接口的子類型(需重寫compare()實現(xiàn)元素的比較),相當(dāng)于一個臨時定義的排序規(guī)則浪耘,其實就是通過接口注入比較元素大小的算法乱灵。
34、一個已經(jīng)構(gòu)建好的TreeSet七冲,怎么完成倒排序痛倚?
通過TreeSet構(gòu)造函數(shù)傳入一個比較器,指定比較器進行排序為原排序的倒敘澜躺。
TreeSet自然排序是根據(jù)集合元素的大小蝉稳,以升序排列。如需實現(xiàn)定制排序掘鄙,如降序耘戚,則需在創(chuàng)建TreeSet時,提供一個Comparator對象與該TreeSet關(guān)聯(lián)操漠,由該Comparator對象負責(zé)集合元素的排序收津。Comparator接口包含一個int compare(T o1,T o2)方法浊伙,用于比較o1和o2的大小撞秋。
35、EnumSet是什么嚣鄙?
是與枚舉類型一起使用的專用Set實現(xiàn)吻贿。枚舉set中所有鍵都必須來自單個枚舉類型,該枚舉類型在創(chuàng)建set時顯式或隱式指定拗慨。枚舉set在內(nèi)部表示為位向量廓八,此表示形式非常緊湊且高效。此類的空間和時間性能很好赵抢,具有高品質(zhì)、類型安全的優(yōu)勢声功。
36烦却、Hashcode的作用?
1)用來在散列存儲結(jié)構(gòu)中快速確定對象的存儲地址先巴,如Hashtable其爵,HashMap等冒冬;
2)如果兩個對象相同則hashCode一定相同,適用于equals(java.lang.Object)方法摩渺;
3)如果對象的equals()被重寫简烤,則對象的hashCode()也需重寫;
4)兩個對象的hashCode相同摇幻,兩個對象未必相同横侦,不一定適用于equals(java.lang.Object)方法,只能說明這兩個對象在散列存儲結(jié)構(gòu)中绰姻,如Hashtable枉侧,他們“存放在同一個籃子里”。
37狂芋、簡述一致性Hash算法榨馁?
在分布式緩存系統(tǒng)中,需要將數(shù)據(jù)均勻的分布到緩存服務(wù)器集群的不同機器上帜矾,就需要對緩存數(shù)據(jù)的key做hash計算翼虫, 再將hash值除以服務(wù)器節(jié)點的數(shù)量取模計算出數(shù)據(jù)需要落到哪臺服務(wù)器節(jié)點上。這種算法簡單屡萤,也可以實現(xiàn)數(shù)據(jù)的均勻分布珍剑, 但增加或減少數(shù)據(jù)節(jié)點時會導(dǎo)致所有緩存數(shù)據(jù)失效。
一致性Hash最關(guān)鍵的區(qū)別:對節(jié)點和數(shù)據(jù)灭衷,都做一次哈希運算次慢,然后比較節(jié)點和數(shù)據(jù)的哈希值,數(shù)據(jù)取和節(jié)點最相近的節(jié)點作為存放節(jié)點翔曲。 保證節(jié)點增加或減少時迫像,影響數(shù)據(jù)最少。
38瞳遍、有沒有可能兩個不相等的對象有相同的hashcode闻妓?當(dāng)兩個對象hashcode相同怎么辦?
判斷規(guī)則:
1)如果兩個對象equals掠械,hashcode一定相等由缆。
2)如果兩個對象不equals,hashcode有可能相等猾蒂。
3)如果兩個對象hashcode相等均唉,他們不一定equals。
4)如果兩個對象hashcode不相等肚菠,他們一定不equals舔箭。
hashcode相同,它們的bucket位置相同,碰撞會發(fā)生层扶。HashMap使用鏈表存儲對象箫章,Entry存儲在鏈表中。如果數(shù)組坐標相同镜会,則進入鏈表中檬寂,一般的添加都在最前面,也就是和數(shù)組下標直接相連的地方戳表,鏈表長度到達8的時候桶至,jdk1.8上升為紅黑樹。
39扒袖、為什么在重寫equals方法的時候需要重寫hashCode方法塞茅?
為保證同一個對象,在equals相同時hashcode值也相同季率,如果重寫equals未重寫hashcode方法野瘦,可能會出現(xiàn)兩個沒有關(guān)系的對象equals相同,hashcode不相同飒泻。
40鞭光、a.hashCode()有什么用?與a.equals(b)有什么關(guān)系泞遗?
hashCode()方法是對象整型的hash值惰许。兩個使用equal()方法判斷相等的對象,必須具有相同的hashcode史辙。將對象放入集合中時汹买,首先判斷對象的hashcode在集合中是否存在,不存在則放入聊倔。
如果hashcode相等晦毙,通過equal()方法判斷對象與集合中的任意對象是否相等:如果equal()判斷不相等,直接將該元素放入集合中耙蔑,否則不放入见妒。
41、hashCode()和equals()方法的重要性體現(xiàn)在什么地方甸陌?
同一個對象無論何時調(diào)用hashCode()须揣,返回值必須一樣。
hashCode()返回值相等钱豁,對象不一定相等耻卡,通過hashCode()和equals()必須能唯一確定一個對象。重寫equals()牲尺,必須重寫hashCode()劲赠。hashCode()生成哈希值的依據(jù)應(yīng)是equals()中用來比較是否相等的字段。
42秸谢、Object有哪些公用方法凛澎?Object類hashcode,equals設(shè)計原則?
clone估蹄、getClass塑煎、toString、finalize臭蚁、equals最铁、hashCode、wait垮兑、notify冷尉、notifyAll
如果兩個對象相等equals(),必須有相同的哈希碼hashCode()系枪,即使兩個對象有相同的哈希值雀哨,他們不一定相等。
43私爷、如何在父類中為子類自動完成所有的hashcode和equals實現(xiàn)雾棺?這么做有何優(yōu)劣?
同時復(fù)寫hashcode和equals方法衬浑,優(yōu)勢可以添加自定義邏輯捌浩,且不必調(diào)用超類的實現(xiàn)。
44工秩、可以在hashcode()中使用隨機數(shù)字嗎尸饺?
不行,因為同一對象的hashcode值必須相同助币。
45浪听、LinkedHashMap和PriorityQueue的區(qū)別?
PriorityQueue:保證最高或最低優(yōu)先級的元素總是在隊列頭部奠支,遍歷時沒有任何順序保證馋辈;
LinkedHashMap:維持元素插入的順序,遍歷順序是元素插入的順序倍谜。
46迈螟、List, Set, Map存取元素時各有什么特點?
Set不允許有重復(fù)元素
存元素:add方法有一個boolean返回值尔崔,當(dāng)集合中沒有某個元素答毫,add方法可加入該元素返回true;當(dāng)集合含有與某個元素equals相等的元素時季春,add方法無法加入洗搂,返回false。
取元素:只能以Iterator接口取得所有元素,再遍歷各元素耘拇。
List有順序的集合
存元素:多次調(diào)用add(Object)方法時撵颊,按先來后到排序,也可插隊惫叛,調(diào)用add(int index,Object)倡勇,指定當(dāng)前對象在集合中的存放位置。
取元素:方法1:Iterator接口取得所有嘉涌,遍歷各元素
方法2:調(diào)用get(index i)明確取第幾個妻熊,精確控制元素插入位置。用戶能使用索引來訪問List中的元素仑最,類似于Java的數(shù)組扔役。
Map是雙列的集合
存元素:put(obj key,obj value),每次存儲時警医,要存儲一對key/value亿胸,不能存儲重復(fù)的key,這個重復(fù)的規(guī)則也是按equals比較相等法严。
取元素:用get(Object key)根據(jù)key獲得相應(yīng)的value损敷。可以獲得所有key和value的集合深啤,還可以獲得key和value組合成的Map.Entry對象的集合拗馒。
List以特定次序來持有元素,可有重復(fù)元素溯街。
Set無法擁有重復(fù)元素诱桂,內(nèi)部排序。
Map保存key-value值呈昔,value可多值挥等。
46、List堤尾、Set肝劲、Map是否繼承自Collection接口?
List與Set都是單列元素的集合郭宝,它們有一個共同的父接口Collection辞槐。
Map沒有繼承于Collection接口,從Map集合中檢索元素時粘室,只要給出鍵對象榄檬,就會返回對應(yīng)值對象。
47衔统、遍歷一個List有哪些不同的方式鹿榜?
for each海雪、Iterator、loop with size
48舱殿、LinkedList是單向鏈表還是雙向鏈表奥裸?
Linkedlist是雙向鏈表
優(yōu)點:增刪快;沒有索引怀薛,對索引的操作刺彩,只能循環(huán)遍歷,每次循環(huán)都會先判斷一下枝恋,這個索引位于鏈表的前部分還是后部分,每次都會遍歷鏈表的一半嗡害,而不是全部遍歷焚碌。
雙向鏈表都有一個previous和next,鏈表最開始都有一個first和last指向第一個和最后一個元素霸妹。增刪時十电,只需更改一個previous和next,就可以實現(xiàn)增加和刪除叹螟。
49鹃骂、LinkedList與ArrayList的區(qū)別?
1)ArrayList基于動態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu)罢绽,LinkedList基于鏈表的數(shù)據(jù)結(jié)構(gòu)畏线。
2)隨機訪問get和set,ArrayList優(yōu)于LinkedList良价,LinkedList要移動指針寝殴。
3)增刪操作,LinedList占優(yōu)勢明垢,ArrayList要移動數(shù)據(jù)蚣常。
50、插入數(shù)據(jù)時痊银,ArrayList抵蚊、LinkedList、Vector誰的速度較快溯革?
ArrayList:數(shù)組結(jié)構(gòu)贞绳,查詢快,增刪慢鬓照,線程不同步
LinkdeList:鏈表結(jié)構(gòu)熔酷,查詢慢,增刪快
Vector:數(shù)組結(jié)構(gòu)豺裆,線程同步
插入速度:LinkdeList>ArrayList>Vector
51拒秘、ArrayList和HashMap的默認大泻畔浴?
ArrayList默認大小是10個元素躺酒,HashMap默認大小是16個元素(必須是2的冪)押蚤;
52、ArrayList羹应、LinkedList揽碘、Set、Vector的區(qū)別园匹?
ArrayList
優(yōu)點:基于索引的數(shù)據(jù)結(jié)構(gòu)雳刺,適合隨機讀取數(shù)據(jù),讀取速度快裸违,可一步get(index)掖桦。
缺點:增刪值慢,添加數(shù)據(jù)在array中間時供汛,需要移動后面的數(shù)枪汪;當(dāng)長度大于初始長度時,每添加一個數(shù)都會擴容怔昨。
LinkedList:雙向鏈表
優(yōu)點:增刪值快雀久,不需改變數(shù)組大小,也不需在數(shù)組裝滿時將所有數(shù)據(jù)重新裝入一個新數(shù)組趁舀,添加在list中間也只需更改指針赖捌;長度不固定,優(yōu)勢只存在于數(shù)據(jù)插入表頭赫编,如果一直往后插入巡蘸,就沒有優(yōu)勢了。實現(xiàn)棧和隊列方面擂送,LinkedList要優(yōu)于ArrayList悦荒。
缺點:LinkedList需要更多內(nèi)存,ArrayList每個索引位置是實際的數(shù)據(jù)嘹吨,而LinkedList中每個節(jié)點中存儲的是實際數(shù)據(jù)和前后節(jié)點位置搬味。
Set不允許有重復(fù),ArrayList是動態(tài)數(shù)組實現(xiàn)的列表蟀拷,有序可重復(fù)碰纬。
Vector類似ArrayList,但Vector是同步的问芬。
53悦析、ArrayList如何實現(xiàn)擴容?
arraylist擴充機制:newCapacity=oldCapacity+(oldCapacity>>1)(注:>>1:右移1位此衅,相當(dāng)于除以2强戴,如10>>1=5)亭螟,所以size就是初始最大容量或上一次擴容后達到的最大容量,才會擴容骑歹。擴容后的大小是原來1.5倍+1预烙;
ArrayList在沒指定initialCapacity時會延遲分配對象數(shù)組空間,當(dāng)?shù)谝淮尾迦朐貢r才分配10(默認)個對象空間道媚。假如有20個數(shù)據(jù)需要添加扁掸,在第一次將ArrayList容量變?yōu)?0;之后擴容按照1.5倍增長最域。當(dāng)添加第11個數(shù)據(jù)時谴分,Arraylist擴容為101.5=15;當(dāng)添加第16個數(shù)據(jù)時羡宙,擴容為15 1.5=22個狸剃。
每次擴容都是通過Arrays.copyOf(elementData, newCapacity) 這樣的方式實現(xiàn)的;
如果通過無參構(gòu)造的話狗热,初始數(shù)組容量為0,當(dāng)對數(shù)組進行添加時虑省,才真正分配容量匿刮。每次按1.5倍(位運算)的比率通過copeOf的方式擴容。
54探颈、Array和ArrayList有何區(qū)別熟丸?什么時候更適合用Array?
Array:最高效伪节,容量固定且無法動態(tài)改變光羞;Array實際是個reference,指向heap內(nèi)某個實際對象怀大。
ArrayList:容量可動態(tài)增長纱兑,犧牲效率;
基于效率和類型檢驗化借,盡可能使用Array潜慎,無法確定數(shù)組大小時用ArrayList;
55蓖康、Map, Set, List, Queue, Stack
Map是一種把鍵對象和值對象進行關(guān)聯(lián)的容器铐炫,而一個值對象又可以是一個Map,可形成一個多級映射蒜焊。使用哈希算法倒信,以便快速查找一個鍵,TreeMap則是對鍵按序存放泳梆;Map沒有繼承Collection接口鳖悠,Map提供key到value的映射榜掌。Map中不能包含相同的key,每個key只能映射一個value竞穷。Map有兩種比較常用的實現(xiàn):HashMap和TreeMap唐责。
List是有序的Collection,能夠精確的控制每個元素插入的位置瘾带。使用索引訪問List中的元素鼠哥,允許有相同的元素,查詢快看政,插入慢朴恳;實現(xiàn)List接口的常用類有LinkedList,ArrayList允蚣,Vector和Stack于颖。
Set接口也是Collection的一種擴展,Set中的對象元素不能重復(fù)嚷兔,最多有一個null元素森渐;常用具體實現(xiàn)有HashSet和TreeSet類。
Stack繼承自Vector冒晰,同步的同衣,實現(xiàn)一個后進先出的堆棧古今。Stack剛創(chuàng)建后是空棧邻耕。
Queue是種特殊的線性表饿敲,只允許在表的前端(front)刪除铝耻,在表的后端(rear)插入撬统。進行插入的端稱為隊尾狭归,進行刪除的端稱為隊頭炕泳。隊列中沒有元素時昭殉,稱為空隊列棵癣。在隊列結(jié)構(gòu)中辕翰,最先插入的元素最先被刪除,最后插入的元素最后被刪除浙巫,隊列又稱為“先進先出”(FIFO—first in first out)的線性表金蜀。
56、Map接口提供了哪些不同的集合視圖的畴?
keyset渊抄,entryset和collection
57、為什么Map接口不繼承Collection接口丧裁?
Map不是集合护桦,集合也不是Map。因此Map繼承Collection毫無意義煎娇,Map包含key-value二庵,提供抽取key或value集合的方法贪染,但它不適合“一組對象”規(guī)范。
58催享、介紹Java中的Collection FrameWork杭隙,集合類框架的基本接口有哪些?
collection是java工具包因妙,包含數(shù)據(jù)結(jié)構(gòu):集合痰憎、鏈表、隊列攀涵、棧铣耘、數(shù)組、映射等以故。
Java集合主要分為4個部分:List列表蜗细、Set集合、Map映射怒详、工具類(Iterator炉媒、Arrays和Collections)。Collection有List和Set兩大分支昆烁。
基本接口:Collection和Map
Collection:單列集合的根接口
List:元素有序橱野,可重復(fù)
ArrayList:類似一個長度可變的數(shù)組 。適合查詢善玫,不適合增刪
LinkedList:底層是雙向循環(huán)鏈表。適合增刪密强,不適合查詢茅郎。
Set:元素?zé)o序,不可重復(fù)
HashSet:根據(jù)對象的哈希值確定元素在集合中的位置
TreeSet: 以二叉樹的方式存儲元素或渤,實現(xiàn)了對集合中的元素排序
Map:雙列集合的根接口系冗,用于存儲具有鍵(key)、值(value)映射關(guān)系的元素薪鹦。
HashMap:用于存儲鍵值映射關(guān)系掌敬,不能出現(xiàn)重復(fù)key
TreeMap:用來存儲鍵值映射關(guān)系,不能出現(xiàn)重復(fù)key池磁,鍵按二叉樹方式排列奔害;
具體結(jié)構(gòu)如下所示:
59、Collection和Collections的區(qū)別地熄?
1)Collection是集合接口华临。它提供了對集合對象進行基本操作的通用接口方法。
2)Collections是包裝類端考。包含各種有關(guān)集合操作的靜態(tài)多態(tài)方法雅潭。此類不能實例化揭厚,就像一個工具類,服務(wù)于Java的Collection框架扶供。
60筛圆、為什么Collection不從Cloneable和Serializable接口繼承?
克隆或序列化的含義是跟具體實現(xiàn)相關(guān)的椿浓,應(yīng)該由集合類的具體實現(xiàn)類來決定如何被克隆或序列化太援;
61、Comparator與Comparable接口是干什么的轰绵?它們的區(qū)別粉寞?
Comparable可以認為是內(nèi)比較器,實現(xiàn)了Comparable接口的類可以和自己比較左腔,和另一個實現(xiàn)了Comparable接口的類如何比較唧垦,依賴compareTo方法的實現(xiàn),compareTo方法也稱為自然比較方法液样。如果想要Collections的sort方法自動進行排序振亮,那么這個對象必須實現(xiàn)Comparable接口。
compareTo方法的返回值是int鞭莽,有三種情況:
1)比較者大于被比較者(也就是compareTo方法里面的對象)坊秸,返回正整數(shù)
2)比較者等于被比較者,返回0
3)比較者小于被比較者澎怒,返回負整數(shù)
Comparator可以認為是外比較器褒搔,個人認為有兩種情況可以使用實現(xiàn)Comparator接口的方式:
1)一個對象不支持自己和自己比較(沒有實現(xiàn)Comparable接口),但又想對兩個對象進行比較喷面;
2)一個對象實現(xiàn)了Comparable接口星瘾,但開發(fā)者認為compareTo方法中的比較方式不是想要的方式;
Comparator接口的compare方法惧辈,方法有兩個參數(shù)T o1和T o2琳状,是泛型的表示方式,表示待比較的兩個對象盒齿,方法返回值和Comparable接口一樣是int念逞,有三種情況:
1)o1大于o2,返回正整數(shù)
2)o1等于o2边翁,返回0
3)o1小于o3翎承,返回負整數(shù)
62、什么是B+樹倒彰,B-樹审洞,列出實際的使用場景?
B樹:平衡多叉樹,每個結(jié)點只存儲一個關(guān)鍵字芒澜,等于則命中仰剿,小于走左結(jié)點,大于走右結(jié)點痴晦;
B-樹:即B樹
B+樹:在B-樹基礎(chǔ)上南吮,為葉子結(jié)點增加鏈表指針,所有關(guān)鍵字都在葉子結(jié)點中出現(xiàn)誊酌,非葉子結(jié)點作為葉子結(jié)點的索引部凑;B+樹總是到葉子結(jié)點才命中;
B*樹:在B+樹基礎(chǔ)上碧浊,為非葉子結(jié)點也增加鏈表指針涂邀,將結(jié)點的最低利用率從1/2提高到2/3
使用場景:
紅黑樹: 平衡二叉樹,廣泛用在C++的標準模板庫(STL)中箱锐。如map和set都是用紅黑樹實現(xiàn)的比勉。
B/B+樹: 用在磁盤文件組織、數(shù)據(jù)索引和數(shù)據(jù)庫索引驹止。
63浩聋、fail-fast 與 fail-safe 機制有什么區(qū)別?
Iterator的安全失敗是基于對底層集合做拷貝臊恋,因此它不受源集合上修改的影響衣洁。
java.util包下面所有的集合類都是快速失敗的,而java.util.concurrent包下面所有的類都是安全失敗的抖仅》环颍快速失敗的迭代器會拋出ConcurrentModificationException異常,安全失敗的迭代器不會拋出此異常撤卢。
如何解決:
fail-fast是一種錯誤檢測機制践樱。它只能被用來檢測錯誤,因為JDK并不保證fail-fast機制一定會發(fā)生凸丸。若在多線程環(huán)境下使用fail-fast機制的集合,建議使用“java.util.concurrent包下的類”去取代“java.util包下的類”袱院。