版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
Java程序員面試分類真題6(總分:100.00,做題時間:120分鐘)一、單項選擇題(總題數(shù):22,分數(shù):44.00)1.
Java程序的執(zhí)行過程中用到一套JDK工具,其中,java.exe是指______。
(分數(shù):2.00)
A.Java編譯器
B.Java解釋器
√
C.Java文檔生成器
D.Java類分解器解析:對于選項A,JDK中的編譯器為javac.exe,可以用來把Java代碼編譯為中間代碼.class文件。所以,選項A錯誤。
對于選項B,java.exe是Java解釋器,用來解釋執(zhí)行通過javac編譯生成的.class文件。所以,選項B正確。
對于選項C,JDK文檔生成所使用的命令為javadoc.exe,而不是java.exe。所以,選項C錯誤。
對于選項D,JDK也提供了很多類分析工具,例如jstack用來查看線程情況(觀察JVM中當前所有線程的運行情況和線程當前狀態(tài),可以查看堆棧信息和運行的線程的方法調用關系),jmap用來查看內(nèi)存堆情況。所以,選項D錯誤。
所以,本題的答案為B。2.
Java之所以可以實現(xiàn)跨平臺,是因為Java程序在運行時使用了______。
(分數(shù):2.00)
A.JRE(JavaRuntimeEnvironment)
B.JDK(JavaDevelopmentKit)
C.JVM(JavaVirtualMachine)
√
D.OS(OperatingSystem)解析:平臺獨立性指的是可以在一個平臺上編寫和編譯程序,而在其他平臺上運行。保證Java語言具有平臺獨立性的機制為“中間碼”和“JVM”。Java程序被編譯后不是生成能在硬件平臺上可執(zhí)行的代碼,而是生成了一個中間代碼。不同的硬件平臺上會安裝有不同的JVM,由JVM來負責把中間代碼翻譯成硬件平臺能執(zhí)行的代碼。由此可以看出,JVM不具有平臺獨立性,與硬件平臺是相關的,它保證了Java可以實現(xiàn)跨平臺。
本題中,對于選項A,JRE是運行Java程序所必須的環(huán)境的集合,包含JVM標準實現(xiàn)以及Java核心類庫。所以,選項A不正確。
對于選項B,JDK是Java語言開發(fā)的工具包,主要用于移動設備、嵌入式設備上的Java應用程序。包括javac、jar、javadoc、jdb、java、appletviewer、javah、Javap等基本組件。所以,選項B不正確。
對于選項C,JVM是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現(xiàn)的。它是Java語言跨平臺的核心。所以,選項C正確。
對于選項D,OS全稱為OperatingSystem,指的是操作系統(tǒng),與Java跨平臺沒有關系。所以,選項D不正確。3.
釋放掉一個指定占據(jù)的內(nèi)存空間的方法是______。
(分數(shù):2.00)
A.調用system.gc()方法
B.調用free()方法
C.賦值給該項對象的引用為null
D.程序員無法明確強制垃圾回收器運行
√解析:在Java語言中,GC(GarbageCollection,垃圾回收)是一個非常重要的概念,它的主要作用是回收程序中不再使用的內(nèi)存。在使用C/C++語言進行程序開發(fā)的時候,開發(fā)人員必須非常仔細地管理好內(nèi)存的分配與釋放,如果忘記或者錯誤地釋放內(nèi)存往往會導致程序運行不正確甚至是程序的崩潰。為了減輕開發(fā)人員的工作,同時增加系統(tǒng)的安全性與穩(wěn)定性,Java語言提供了垃圾回收器來自動檢測對象的作用域,實現(xiàn)自動地、把不再被使用的存儲空間釋放掉。
在Java語言中,釋放掉占據(jù)的內(nèi)存空間是由GC完成的,程序員無法直接強制釋放存儲空間,當一個對象不被使用的時候,GC會將該對象標記為垃圾,并在后面一個不確定的時間內(nèi)回收垃圾(程序員無法控制這個時間)。
給對象引用賦值為null,并且該對象無其他引用,GC會標記該對象為垃圾,并在后面一個不確定的時間內(nèi)回收垃圾。所謂不確定是指什么時間回收,程序員無法控制。
本題中,對于選項A,開發(fā)人員可以通過調用System.gc()方法來通知垃圾回收器運行,但是JVM也并不能保證垃圾回收器馬上就會運行。因此,選項A錯誤。
對于選項B,Java語言沒有提供free(釋放)方法。因此,選項B錯誤。
對于選項C,當把對象的引用設置為null時,GC會標記該對象為垃圾,并在后面一個不確定的時問內(nèi)回收垃圾。因此,選項C錯誤。
對于選項D,程序員無法明確強制垃圾回收器運行。因此,選項D正確。4.
下面關于垃圾回收的描述中,正確的是______。
(分數(shù):2.00)
A.對象空間被回收掉之后,會執(zhí)行該對象的finalize方法
B.一個對象一旦成為垃圾,就立刻被回收掉
C.finalize方法和C++語言的析構函數(shù)完全是一回事
D.一個對象成為垃圾是因為不再有引用指著它,但是線程并非如此
√解析:在Java語言中,當沒有對象引用指向原先分配給某個對象的內(nèi)存時,該內(nèi)存便成為垃圾。Java虛擬機的一個系統(tǒng)級線程會自動釋放該內(nèi)存塊。當一個對象不再被引用的時候,內(nèi)存回收它占領的空間,以便空間被后來的新對象使用,不僅如此,垃圾回收除了釋放沒用的對象,也可以清除內(nèi)存記錄碎片。
本題中,對于選項A,finalize方法是在對象空間被回收前調用的。所以,選項A錯誤。
對于選項B,成為垃圾的對象,只有在下次垃圾回收器運行的時候才會被回收,而不是馬上被清理。所以,選項B錯誤。
對于選項C,在C++語言中,調用了析構函數(shù)后,對象一定會被銷毀,而Java語言調用了finalize方法,垃圾卻不一定會被回收,因此,finalize方法與C++語言的析構函數(shù)是不同的概念。所以,選項C錯誤。
對于選項D,當一個對象不再被引用后就成為垃圾,而垃圾是可以被回收的,但是線程就算沒有被引用也可以獨立運行,因此,它與對象不同。所以,選項D正確。5.
有如下代碼:
10.publicObjectm(){
11.Objecto=newFloat(3.1f);
12.Object[]oa=new()bject[1];
13.oa[0]=o;
14.o=null;
15.oa[0]=null;
16.print'return0';
17.}
當Float對象在第11行被創(chuàng)建后,______能夠被垃圾回收。
(分數(shù):2.00)
A.14行以后
B.13行以后
C.15行以后
√
D.16行以后解析:具體而言,垃圾回收器主要負責完成3項任務:分配內(nèi)存、確保被引用對象的內(nèi)存不被錯誤地回收以及回收不再被引用的對象的內(nèi)存空間。
垃圾回收器的存在,一方面把開發(fā)人員從釋放內(nèi)存的復雜的工作中解脫出來,提高了開發(fā)人員的生產(chǎn)效率;另外一方面,對開發(fā)人員屏蔽了釋放內(nèi)存的方法,可以避免因為開發(fā)人員錯誤地操作內(nèi)存從而導致應用程序的崩潰,保證了程序的穩(wěn)定性。但是,垃圾回收也帶來了問題,為了實現(xiàn)垃圾回收,垃圾回收器必須跟蹤內(nèi)存的使用情況,釋放沒用的對象,在完成內(nèi)存的釋放后還需要處理堆中的碎片,這些操作必定會增加JVM的負擔,從而降低程序的執(zhí)行效率。
對于對象而言,如果沒有任何變量去引用它,那么該對象將不可能被程序訪問,因此,可以認為它是垃圾信息,可以被回收。只要有一個以上的變量引用該對象,該對象就不會被垃圾回收。
對于本題而言,首先,在第11行定義了一個Float對象o,接著,在第13行把這個對象的引用賦值給數(shù)組oa[0]的第一個元素,此時這個Float對象有兩處被引用的地方,分別為o和oa[0];在第14行中執(zhí)行o=null后,這個Float對象仍然被oa[0]引用,在執(zhí)行完第15行后這個Float對象沒有被任何變量引用了,因此,就具備了被垃圾回收器回收的條件。所以,選項C正確。6.
有下面代碼:
interfaceAnimal{publicvoidtest();}
publicclassHourseimplementsAnimal{
publicvoidtest(){
...}
publicstaticVoidmain(String[]args)
{
Animala1=newHourse();
Animala2=newHourse();
Animala3=newHourse();
a1=a2;a2=null;a3=a1;
}
}
當程序執(zhí)行到a1=a2;a2=null;a3=a1;這行時,將被垃圾回收器回收的對象個數(shù)為______。
(分數(shù):2.00)
A.1
B.2
√
C.3
D.4
E.5
F.6解析:為了便于理解,給下面三個新建的對象起個別名:
Animala1=newHourse();
//對象1
Animala2=newHourse();
//對象2
Animala3=newHourse();
//對象3
在執(zhí)行語句a1=a2后,a1和a2都指向對象2,此時對象1不再被引用,因此,可以被垃圾回收器回收。在執(zhí)行語句a2=null后,由于a1仍然執(zhí)行對象2,因此,對象2不能被回收。在執(zhí)行語句a3=a1后,a3也指向對象2,此時對象3不再被引用,也可以被回收。因此,總共有2個對象被回收。所以,選項B正確。7.
下列關于內(nèi)存回收的描述中,正確的是______。
(分數(shù):2.00)
A.程序員必須創(chuàng)建一個線程來釋放內(nèi)存
B.內(nèi)存回收程序負責釋放無用內(nèi)存
√
C.內(nèi)存回收程序允許程序員直接釋放內(nèi)存
D.內(nèi)存回收程序可以在指定的時間釋放內(nèi)存對象解析:8.
在Java語言中,下面接口以鍵一值對的方式存儲對象的是______。
(分數(shù):2.00)
A.java.util.List
B.java.util.Map
√
C.java.util.Collection
D.java.util.Set解析:對于選項A,List中保存了相同類型的多個元素,元素是按照存入的順序存儲的,元素可以重復。所以,選項A錯誤。
對于選項B,Map是以鍵一值對的方式來存儲對象的,并且鍵不允許重復。所以,選項B正確。
對于選項C,java.util.Collection是一個集合接口,它提供了對集合對象進行基本操作的通用接口方法。而Set與List是它的兩個具體的接口,由于Set與List都不是以鍵一值對的方式來存儲對象的,因此,Collection接口也不是。所以,選項C錯誤。
對于選項D,Set中也保存了相同類型的多個元素,元素是不能重復的。所以,選項D錯誤。
下表是各接口的區(qū)別。各接口的區(qū)別類型是否有序是否允許重復是否線程同步Collection否是
ListArrayList否是否Vector是LinkedList否SetHashSet否否否TreeSet是否MapHashMap否<key,value>,
key不允許重復否TreeMaD是否Hashtable否是
所以,本題的答案為B。9.
list是一個ArrayList的對象,當將選項______的代碼填到//tododelete處時,可以在Iterator遍歷的過程中正確并安全地刪除一個list中保存的對象。
Iteratorit=list.iterator();
imindex=0;
while(it.hasNext())
{
Objectobj=it.next();
if(needDelete(obj))//needDelete返回boolean,決定是否要刪除
{
//tododelete
}
index++;
}
(分數(shù):2.00)
A.it.remove();
√
B.list.remove(index);
C.list.remove(ohj);
D.list.delete(index);解析:Iterator支持從源集合中安全地刪除對象,刪除的方法為在Iterator上調用remove()方法。這樣做的好處是可以避免ConcurrentModifiedException異常發(fā)生,當打開Iterator迭代集合時,同時又在對集合進行修改。有些集合不允許在迭代時刪除或添加元素,但是調用Iterator的remove()方法是個安全的做法。
remove()方法的作用為從迭代器指向的集合中移除迭代器返回的最后一個元素(可選操作),每次調用next()方法只能調用一次此方法。如果在進行迭代時,用調用此方法之外其他方式修改了該迭代器所指向的集合,那么迭代器的行為是不明確的。因此,選項A正確。10.
下面創(chuàng)建Map集合的方式中,正確的是______。
(分數(shù):2.00)
A.Mapm=newMap(newCollection())
B.Mapm=newMap(10,2,40)
C.Mapm=newMap()
D.Map是接口,所以不能實例化
√解析:Java為數(shù)據(jù)結構中的映射定義了一個接口java.util.Map,它有三個實現(xiàn)類:HashMap、Hashtable和TreeMap。由于接口中的方法都沒有實現(xiàn),因此,不能直接使用new來實例化一個接口,原因是new只能用來實例化非抽象的類。所以,選項D正確。
本題中,一種正確的寫法為Map<String,String>m=newHashMap<String,String>(),把實例化HashMap對象的實例賦值給Map接口變量m。11.
以下不是Collection的子接口的是______。
(分數(shù):2.00)
A.List
B.Set
C.SortedSet
D.HashMap
√解析:Collection的框架如圖所示。
由此可見,HashMap不是Collection的子接口,List和set是Collection的子接口,SortedSet繼承了Set接口,因此,也屬于Collection的子接口。所以,選項D正確。
Collection框架12.
在Java語言中,位于集合框架的頂層的接口是______。
(分數(shù):2.00)
A.Collection
√
B.Collections
C.List
D.Iterator解析:Collection是一個集合接口。它提供了對集合對象進行基本操作的通用接口方法。實現(xiàn)該接口的類主要有List和Set,該接口的設計目標是為各種具體的集合提供最大化的統(tǒng)一的操作方式。
由此可見,選項A正確,選項C和選項D錯誤。
Collections是針對集合類的一個包裝類,它提供一系列靜態(tài)方法實現(xiàn)對各種集合的搜索、排序和線程安全化等操作,其中的大多數(shù)方法都是用來處理線性表。Collections類不能實例化,如同一個工具類,服務于Collection框架。因此,Collections不是一個集合框架類,選項D錯誤。
所以,本題的答案為A。13.
欲構造ArrayList類的一個實例,此類繼承了List接口,下列方法中,正確的是______。
(分數(shù):2.00)
A.ArrayListlist=newObject()
B.Listlist=newArrayList()
√
C.Listlist=newList()
D.ArrayListlist=newList()解析:對于選項A,在Java語言中,可以把子類的對象賦值給父類的引用變量,但是不可以把父類的對象賦值給子類的引用,Object是所有類的父類,因此,也是ArrayList的父類,所以,這種寫法是不合法的,如果換成語句Objecto=newArrayList()就合法了。所以,選項A錯誤。
對于選項B,ArrayList實現(xiàn)了List接口。所以,選項B正確。
對于選項C與選項D,由于List是接口,因此,不能被實例化。所以,選項C與選項D錯誤。
所以,本題的答案為B。14.
Java語言的接口java.util.Collection定義了許多方法,以下方法中,不是Collection接口所定義的是______。
(分數(shù):2.00)
A.booleancontainsAll(Collectionc)
B.intsize()
C.compareTo(Objectobj)
√
D.booleanequals(Object0)解析:java.util.Collection是一個集合接口,它提供了對集合對象進行基本操作的通用接口方法。Collection接口在Java類庫中有很多具體的實現(xiàn)。具體而言,Collection主要方法見下表。Collection主要方法方法描述add(Ee)把對象e添加到容器中addAll(Collection<?extendsE>c)把c中的所有對象添加到容器中clear()清空容器contains(Objecto)如果容器中有對象o,那么返回true,否則,返回falsecontainsAll(Collection<?>c)如果容器中包含c中所有的對象,那么返回true,否則,返回falseequals(Objecto)判斷對象o是否和容器相等hashCode()返回容器的hash值isEmpty()如果容器為空,返回trueiterator()返回這個容器的迭代器remove(Objecto)從列表中刪除對象oremoveAll(Collection<?>c)從列表中刪除那些在c中存在的對象retainAll(Collection<?>c)列表中移除未包含在指定Collection中的所有元素size()返回容器中元素的個數(shù)toArray()返回一個數(shù)組,數(shù)組中包含容器中所有的元素toArray(T[]a)與方法toArray類似,不同之處為返回數(shù)組的類型與參數(shù)指定的類型相同
所以,本題的答案為C。15.
ArrayLista1=newArrayList(20)中的list擴充了______次。
(分數(shù):2.00)
A.0
√
B.1
C.2
D.4解析:在Java語言中,創(chuàng)建ArrayList對象的時候可以不指定其空間大小,在這種情況下,列表默認的大小為10,在后面使用的過程中,如果發(fā)現(xiàn)列表的大小不夠用,此時會擴充為原來大小的1.5倍。
對于本題而言,在初始化ArrayList對象的時候,顯式地指定了列表的大小為20,因此,創(chuàng)建出來的列表對象的長度為20,在這個過程中不需要擴展,即擴展次數(shù)為0。所以,選項A正確。
如果把題目改成ArrayListlist=newArrayList(),接著向列表里插入20條記錄,那么這個列表在插入第11條記錄的時候就需要擴展一次。16.
欲構造ArrayList類的一個實例,此類繼承了List接口,下列方法正確的是______。
(分數(shù):2.00)
A.ArrayListmyList=newLinkedList();
B.ListmyList=newArrayList();
√
C.ArrayListmyList=newList();
D.ListmyList=newList();解析:17.
下列屬于容器型構件的是______。
(分數(shù):2.00)
A.JButton
B.JEdit
C.JPanel
√
D.JTextField解析:容器型構件是指可以在這個構件中添加其他的構件來構建復雜的界面應用程序。
本題中,對于選項A,JButton是按鈕控件,用來響應用戶的單擊事件,它不是容器控件。因此,選項A錯誤。
對于選項B,Swing庫中沒有JEdit控件。因此,選項B錯誤。
對于選項C,JPanel是一個容器型構件,可以在JPanel中添加其他的構件。因此,選項C正確。
對于選項D,JTextField是一個輕量級組件,它允許編輯單行文本,也不是一個容器型的構件。因此,選項D錯誤。18.
每個使用Swing構件的程序必須有一個______
(分數(shù):2.00)
A.標簽
B.按鈕
C.菜單
D.容器
√解析:Swing是一個用于開發(fā)Java應用程序用戶界面的開發(fā)工具包,它提供了大量模塊化組件來方便開發(fā)人員構建用戶界面。在使用Swing開發(fā)界面應用程序的時候,圖形界面至少要有一個頂級Swing容器,這個頂級Swing容器主要用來為其他Swing組件在屏幕上的繪制和處理事件提供支持,常見的頂級容器為JFrame、JDialog和JApplet。至于其他的控件,可以根據(jù)實際的需求而定,可以使用,也可以不用。所以,選項D正確。19.
如果希望控件在界面上按表格行分列排列,應使用的布局管理器是______。
(分數(shù):2.00)
A.BoxLayout
B.GridLayout
√
C.FlowLouLayout
D.BorderLayout解析:Swing是一個用于開發(fā)Java應用程序用戶界面的開發(fā)工具包。利用Swing豐富、靈活的功能和模塊化組件,開發(fā)人員可以只用很少的代碼來創(chuàng)建優(yōu)雅的用戶界面。
具體而言,Swing中主要有如下幾種布局容器:
1)FlowLayout:把控件按照由左向右順序水平放置在容器中,如果在一行無法放下,就放到下一行。
2)BorderLayout:將整個容器劃分成東南西北中五個方位來放置控件,放置控件時需要指定控件放置的方位。
3)BoxLayout:可以指定在容器中是否對控件進行水平或者垂直放置,它是比FlowLayout要更為靈活的一個布局容器。
4)GridLayout:將整個容器劃分成一定的行和一定的列,可以指定控件放在某行某列上。
5)GridBagLayout:GridBagLayout是Swing當中最靈活也是最復雜的布局管理器,可對控件在容器中的位置進行比較靈活的調整。
通過上面的分析可知,選項B正確。20.
在Applet子類中,一般需要重載父類的______方法來完成一些畫圖操作。
(分數(shù):2.00)
A.stop()
B.start()
C.init()
D.paint()
√解析:Applet程序的開發(fā)必須繼承Applet類,它有如下5個比較重要的方法:
(1)init()
當ADplet啟動的時候,調用完構造方法后,就會調用init方法做一些初始化的工作。因此,這個方法中一般做一些初始化的工作。所以,選項C錯誤。
(2)start()
Applet第一次啟動后,調用完init方法后,就會調用start方法來啟動需要的一些線程?;蛘弋斢脩綦x開HTML頁面,然后重新返回頁面的時候,start方法也會被調用。所以,選項A錯誤。
(3)paint(Graphicsg)
Applet每次重繪的時候都會調用paint方法進行畫圖。在開發(fā)的時候,需要繼承這個類完成自己的畫圖的工作。所以,選項D正確。
(4)stop()
這個方法與start方法是相對應的,當用戶離開HTML頁面的時候,stop方法會被調用,用來停止start方法中啟動的線程。所以,選項B錯誤。
(5)destory()
當Applet終止運行時,destory方法會被調用,用來釋放所占用的資源。
所以,本題的答案為D。21.
paint()方法使用的參數(shù)類型是______。
(分數(shù):2.00)
A.Graphics
√
B.Graphics2D
C.String
D.Color解析:22.
容器被重新設置大小后,哪種布局管理器的容器中的組件大小不隨容器大小的變化而改變?______
(分數(shù):2.00)
A.CardLayout
B.FlowLayout
√
C.BorderLayout
D.GridLayout解析:二、多項選擇題(總題數(shù):8,分數(shù):16.00)1.
下列關于Java語言的編譯過程的描述中,正確的有______。
(分數(shù):2.00)
A.環(huán)境變量可在編譯sourcecode時指定
√
B.在編譯程序時,所能指定的環(huán)境變量不包括classpath
C.javac一次可同時編譯數(shù)個Java源文件
√
D.javac.exe能指定編譯結果要置于哪個目錄(directory)
√解析:本題中,對于選項A,環(huán)境變量在編譯時可以通過java-classpath來指定,因此,選項A正確,選項B錯誤。對于選項C,javac*.java就可以編譯多個java文件,因此,選項C正確。對于選項D,javac.exe有個-d選項來指定編譯結果存放的目錄,因此,選項D正確。
所以,本題的答案為ACD。2.
以下關于HashMap與Hashtbale的說法中,正確的是______。
(分數(shù):2.00)
A.迭代HashMap采用快速失敗機制,而Hashtable不是
√
B.Hashtable允許null值作為key和value,而HashMap不可以
C.HashMap不是同步的,而Hashtable是同步的
√
D.兩者都是用key-value方式獲取數(shù)據(jù)
√解析:HashMap和Hashtable通過對象來進行索引,用來索引的對象叫作key,其對應的對象叫作value。二者具有許多相似之處,但也有很多不同之處。以下重點介紹二者的不同之處,具體而言,它們的不同之處體現(xiàn)在以下幾個方面:
1)它們都實現(xiàn)了Map接口,HashMap允許空(null)鍵值(key)(但需要注意的是,最多只允許一條記錄的鍵為null,不允許多條記錄的值為null),而Hashtable不允許。
2)HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因為contains方法容易讓人引起誤解。Hashtable繼承自Dictionary類,而HashMap繼承自AbstractMap類。
3)Hashtable的方法是線程安全的,而HashMap不是線程安全的。當多個線程訪問Hashtable時,不需要開發(fā)人員對它進行同步,而對于HashMap,開發(fā)人員必須提供額外的同步機制。所以,效率上HashMap可能高于Hashtable。
4)“快速失敗”也就是fail-fast,它是Java集合的一種錯誤檢測機制。當多個線程對集合進行結構上的改變操作時,就有可能會產(chǎn)生fail-fast事件。例如,假設存在兩個線程,它們分別是線程1與線程2,當線程1通過Iterator(迭代器)在遍歷集合A中的元素時,如果線程2修改了集合A的結構(刪除或增加新的元素),那么,此時程序就會拋出ConcurrentModificationException異常,從而產(chǎn)生fail-fast事件。
由于Hashtable是線程安全的,因此,沒有采用快速失敗機制,而HashMap是非線程安全的,迭代HashMap采用了快速失敗機制。
從以上分析可知,選項A、選項C、選項D的描述都是正確的,只有選項B的描述不正確,因為Hashtable不允許鍵值為null。
所以,本題的答案為ACD。3.
以下關于HashMap和Hashtable的描述中,正確的是______。
(分數(shù):2.00)
A.Hashtable不允許null鍵或值
√
B.Hashtable類不是同步的,而HashMap類是同步的
C.都實現(xiàn)了Map接口
√
D.HashMap不允許null鍵或值解析:4.
Hashtable和HashMap的區(qū)別是______。
(分數(shù):2.00)
A.Hashtable是一個散列表,該類繼承了AbstractMap,實現(xiàn)了Map接口
B.HashMap是內(nèi)部基于散列表實現(xiàn),該類繼承AbstractMap,實現(xiàn)Map接口
√
C.Hashtable線程安全的,而HashMap是線程不安全的
√
D.Hashtable直接使用對象的hashCode,而HashMap重新計算hash值
E.Properties類繼承了Hashtable類,而Hashtable類則繼承Dictionary類
√解析:5.
以下關于Map的用法中,正確的有______。
(分數(shù):2.00)
A.newjava.util.SortedMap().put("keyl","valuel");
B.newjava.util.Map().put("keyl","valuel");
C.newjava.util.HashMap().put(null,null);
√
D.newjava.util.TreeMap().put(0,null);
√解析:對于選項A,SortedMap繼承了Map,使按鍵保持升序排列,它還是個接口,因此,也無法直接實例化。所以,選項A錯誤。
對于選項B,Map是一個接口,因此,它無法直接實例化。所以,選項B錯誤。
對于選項C和D,HashMap和TreeMap都實現(xiàn)了接口Map,它們是兩個具體的實現(xiàn)類,因此,可以實例化。所以,選項C與選項D正確。6.
下列接口中,直接繼承自Collection接口的是______。
(分數(shù):2.00)
A.List
√
B.Map
C.Set
√
D.HashMap解析:7.
下列關于Collection類結構的描述中,正確的是______。
(分數(shù):2.00)
A.HashSet繼承自AbstractSet
√
B.AbstractSet繼承自Set
C.LinkedList繼承自List
√
D.WeakMap繼承自HashMap解析:8.
以下關于JDK中LinkedBlockingQueue和ConcurTentLinkedQueue的描述中,正確的是______。
(分數(shù):2.00)
A.兩個數(shù)據(jù)接口都是線程安全的
√
B.內(nèi)部都是使用鎖來進行同步
√
C.都可以配置最大元素數(shù)量
D.都是基于鏈表實現(xiàn)
√解析:在Java多線程應用中,隊列的使用頻率很高。隊列是一種先進先出的數(shù)據(jù)結構,它有兩個基本操作:在隊列尾部添加一個元素以及從隊列頭部移除一個元素。如果向一個已經(jīng)滿了的阻塞隊列中添加一個元素或者從一個空的阻塞隊列中移除一個元索,都將導致線程阻塞。
在講解后面的知識之前,首先對阻塞與非阻塞進行分析。什么是阻塞?什么是非阻塞?阻塞與非阻塞關注的是程序在等待調用結果(消息、返回值)時的狀態(tài)。阻塞調用指的是在調用結果返回之前,當前線程會被掛起,調用線程只有在得到結果之后才會返回,而非阻塞調用指的是在不能立刻得到結果之前,該調用不會阻塞當前線程。舉個簡單例子加以說明,小王打電話給書店老板老張,詢問書店是否有《Java程序員面試筆試真題與解析》這本書,如果是阻塞式調用,小王會一直把自己“掛起”,直到得到這本書有沒有的結果,如果是非阻塞式調用,小王會不管老張有沒有告訴自己,小王先做自己的事情了,當然,小王也要偶爾過來檢查一下老張有沒有返回結果。
Java語言提供的線程安全的隊列可以分為阻塞隊列和非阻塞隊列,其中,阻塞隊列的典型例子是LinkedBlockingQueue,非阻塞隊列的典型例子是ConcurrentLinkedQueue,在應用中要根據(jù)實際需要選用阻塞隊列或者非阻塞隊列。以下將分別對這兩種隊列進行介紹。
LinkedBlockingQueue是一個線程安全的阻塞隊列,實現(xiàn)了先進先出等特性,一般用在生產(chǎn)者和消費者模型的開發(fā)中。它的底層采用鏈表的方式來實現(xiàn),采用鎖機制來實現(xiàn)多線程同步,提供了一個構造方法來指定隊列的大小,如果不指定隊列的大小,隊列的默認大小為Intege.MAX_VKLUE(它表示int類型能夠表示的最大值,值為2^31-1的常量)。
ConcurrentLinkedQueue是一個基于鏈表實現(xiàn)的、無界的、線程安全的隊列。無界表示它沒有提供一個構造方法來指定隊列的大小。為了能提高并發(fā)量,它通過使用更加細粒度鎖的機制使得在多線程環(huán)境下不需要對所有的數(shù)據(jù)進行鎖定從而提高運行效率。
通過以上分析可知,選項A、選項B與選項D正確。三、論述題(總題數(shù):20,分數(shù):40.00)1.
描述Java類加載器的原理及其組織結構。
(分數(shù):2.00)__________________________________________________________________________________________
正確答案:(Java語言是一種具有動態(tài)性的解釋型語言,類只有被加載到JVM中后才能運行。當運行程序時,JVM會將編譯生成的.class文件按照需求和一定的規(guī)則加載到內(nèi)存中,并組織成為一個完整的Java應用程序。這個加載過程是由加載器來完成的,具體而言,就是由ClassLoader和它的子類來實現(xiàn)的。類加載器本身也是一個類,其實質是把類文件從硬盤讀取到內(nèi)存中。
類的加載方式分為隱式裝載與顯式裝載兩種。隱式裝載指的是程序在使用new等方式創(chuàng)建對象的時候,會隱式地調用類的加載器把對應的類加載到JVM中。顯式裝載指的是通過直接調用class-forName()方法來把所需的類加載到JVM中。
任何一個工程項目都是由許多個類組成的,當程序啟動時,只把需要的類加載到JVM中,其他的類只有被使用到的時候才會被加載,采用這種方法,一方面可以加快加載速度,另一方面可以節(jié)約程序運行過程中對內(nèi)存的開銷。此外,在Java語言中,每個類或接口都對應一個.class文件,這些文件可以被看成是一個個可以被動態(tài)加載的單元,因此,當只有部分類被修改的時候,只需要重新編譯變化的類即可,而不需要重新編譯所有的文件,因此,加快了編譯速度。
在Java語言中,類的加載是動態(tài)的,它并不會一次性將所有類全部加載后再運行,而是保證程序運行的基礎類(例如基類)完全加載到JVM中,至于其他類,則在需要的時候才加載。在Java語言中,可以把類分為三類:系統(tǒng)類、擴展類和自定義類。Java語言針對這三種不同的類提供了三種類型的加載器,這三種加載器的關系如下:
BootstrapLoader-負責加載系統(tǒng)類(jre/lib/rt.jar的類)
|
--ExtClassLoader-負責加載擴展類(jar/lib/ext/*.jar的類)
|
--AppClassLoader-負責加載應用類(classpath指定的目錄或jar中的類)
以上這三個類是怎么協(xié)調工作來完成類的加載呢?其實,它們是通過委托的方式實現(xiàn)的。具體而言,就是當有類需要被加載時,類裝載器會請求父類來完成這個載入工作,父類會使用其自己的搜索路徑來搜索需要被載入的類,如果搜索不到,才會由子類按照其搜索路徑來搜索待加載的類。下例可以充分說明加載器的工作原理。
publicclassTestLoader
{
publicstaticvoidmain(String[]args)throwsException
{
//調用class加載器
ClassLoaderclApp=TestLoader.class.getClassLoader();
System.out.println(clApp);
//調用上一層Class加載器
ClassLoaderclExt=clApp.getParem();
System.out.println(clExt);
//調用根部Class加載器
ClassLoaderclBoot=clExt.getParent();
System.out.println(clBoot);
}
}
程序的運行結果為:
sun.misc.Launcher$AppClassLoader@19821f
sun.misc.Launcher$ExtClassLoader@addbf1
null
從上例可以看出,TestLoader類是由AppClassLoader來加載的。另外需要說明的一點是,由于BootstrapLoader是使用C++語言來實現(xiàn)的,因此,在Java語言中,是看不到它的,此時程序會輸出null。
類加載的主要步驟分為以下三步:
1)裝載:根據(jù)查找路徑找到相對應的class文件,然后導入。
2)鏈接:鏈接又可以分為三個小的步驟,具體如下:
①檢查:檢查待加載的class文件的正確性。
②準備:給類中的靜態(tài)變量分配存儲空間。
③解析:將符號引用轉換成直接引用(這一步是可選的)。
3)初始化:對靜態(tài)變量和靜態(tài)代碼塊執(zhí)行初始化工作。)解析:2.
JVM的工作原理是什么?
(分數(shù):2.00)__________________________________________________________________________________________
正確答案:(為了便于管理,JVM在執(zhí)行Java程序的時候,會把它所管理的內(nèi)存劃分為多個不同區(qū)域,如圖所示。
JVM管理的內(nèi)存區(qū)域
以下將分別對這些區(qū)域進行介紹。
(1)class文件
class文件是Java程序編譯后生成的中間代碼,這些中間代碼將會被JVM解釋執(zhí)行。
(2)類裝載器子系統(tǒng)
類裝載器子系統(tǒng)負責把class文件裝載到內(nèi)存中,供虛擬機執(zhí)行。
JVM有兩種類裝載器,分別是啟動類裝載器和用戶自定義類裝載器。其中,啟動類裝載器是JVM實現(xiàn)的一部分;用戶自定義類裝載器則是Java程序的一部分,必須是ClassLoader類的子類。常見的類加載器主要有如下幾種:
1)BootstrapClassLoader。這是JVM的根ClassLoader,它是用C++語言實現(xiàn)的,當JVM啟動時,初始化此ClassLoader,并由此ClassLoader完成$JAVA_HoME中jre/lib/rt.jar(SunJDK的實現(xiàn))中所有class文件的加載,這個jar中包含了Java規(guī)范定義的所有接口以及實現(xiàn)。
2)ExtensionClassLoader。JVM用此ClassLoader來加載擴展功能的一些jar包。
3)SystemClassLoader。JVM用此ClassLoader來加載啟動參數(shù)中指定的Classpath中的jar包以及目錄,在SunJDK中,ClassLoader對應的類名為AppClassLoader。
4)User-DefinedClassLoader。User-DefinedClassLoader是Java開發(fā)人員繼承ClassLoader抽象類自行實現(xiàn)的ClassLoader,基于自定義的ClassLoader可用于加載非Classpath中的jar以及目錄。
(3)方法區(qū)
方法區(qū)用來存儲被虛擬機加載的類信息、常量、靜態(tài)變量和編譯器編譯后的代碼等數(shù)據(jù)。在類加載器加載class文件時,這些信息將會被提取出來,并存儲到方法區(qū)中。由于這個區(qū)域是所有線程共享的區(qū)域,因此,它被設計為線程安全的。
方法區(qū)中還存放了運行時的常量池,最典型的應用就是字符串常量,例如,定義了如下語句:Strings="Hello";Strings1="Hello";,其中,“Hello”是字符串常量,存儲在常量池中,兩個字符串引用s和s1都指向常量池中的“Hello”。
(4)堆
堆是虛擬機啟動的時候創(chuàng)建的被所有線程共享的區(qū)域。這塊區(qū)域主要用來存放對象的實例,通過new操作創(chuàng)建出來的對象的實例都存儲在堆空間中,因此,堆就成為垃圾回收器管理的重點區(qū)域。
(5)虛擬機棧
棧是線程私有的區(qū)域,每當有新的線程創(chuàng)建時,就會給它分配一個??臻g,當線程結束后,??臻g就被回收,因此,棧與線程擁有相同的生命周期。棧主要用來實現(xiàn)Java語言中方法的調用與執(zhí)行,每個方法在被執(zhí)行的時候,都會創(chuàng)建一個棧幀用來存儲這個方法的局部變量、操作棧、動態(tài)鏈接和方法出口等信息。當進行方法調用時,通過壓棧與彈棧操作進行棧空間的分配與釋放。當一個方法被調用的時候,會壓入一個新的棧幀到這個線程的棧中,當方法調用結束后,就會彈出這個棧幀,從而回收調用這個方法使用的棧空間。
(6)程序計數(shù)器
程序計數(shù)器也是線程私有的資源,JVM會給每個線程創(chuàng)建單獨的程序計數(shù)器。它可以被看作是當前線程執(zhí)行的字節(jié)碼的行號指示器,解釋器的工作原理就是通過改變這個計數(shù)器的值來確定下一條需要被執(zhí)行的字節(jié)碼指令,程序控制的流程(循環(huán)、分支、異常處理、線程恢復)都是通過這個計數(shù)器來完成的。
(7)本地方法棧
本地方法棧與虛擬機棧的作用是相似的,唯一不同的是虛擬機棧為虛擬機執(zhí)行Java方法(也就是字節(jié)碼)服務,而本地方法棧則是為虛擬機使用到的Native(本地)方法服務。Native(本地)方法接口都會使用某種本地方法棧,當線程調用Java方法時,JVM會創(chuàng)建一個新的棧幀并壓入虛擬機棧。然而當它調用的是本地方法時,虛擬機棧保持不變,不會在線程的虛擬機棧中壓入新的幀,而是簡單地動態(tài)鏈接并直接調用指定的本地方法。如果某個虛擬機實現(xiàn)的本地方法接口使用的是C++連接模型,那么,它的本地方法棧就是C++棧。
(8)執(zhí)行引擎
執(zhí)行引擎主要負責執(zhí)行字節(jié)碼。方法的字節(jié)碼是由Java虛擬機的指令序列構成的,每一條指令包含一個單字節(jié)的操作碼,后面跟隨0個或多個操作數(shù)。當執(zhí)行引擎執(zhí)行字節(jié)碼時,首先會取一個操作碼,如果這個操作碼有操作數(shù),會接著取得它的操作數(shù)。然后執(zhí)行這個操作,執(zhí)行完成后會繼續(xù)取得下一個操作碼執(zhí)行。
在執(zhí)行方法時,JVM提供了四種指令來執(zhí)行:
1)invokestatic:調用類的static方法。
2)invokevirtual:調用對象實例的方法。
3)invokeinterface:將屬性定義為接口來進行調用。
4)invokespecial:調用一個初始化方法、私有方法或者父類的方法。
(9)垃圾回收器
垃圾回收器的主要作用是回收程序中不再使用的內(nèi)存。)解析:3.
如何查看Java程序使用內(nèi)存的情況?
(分數(shù):2.00)__________________________________________________________________________________________
正確答案:(在Java語言中,每個Java應用程序都有一個Runtime類實例,Runtime類提供了多個查看內(nèi)存使用情況的方法,如下例所示:
classTest
{
publicstaticvoidmain(String[]args)
{
//得到JVM中的空閑內(nèi)存量(單位是字節(jié))
System.out.println(RuntimegetRuntime().freeMemory());
//得到JVM內(nèi)存總量(單位是字節(jié))
System.out.println(Runtime.getRuntime().totalMemory());
//JVM試圖使用的最大內(nèi)存量(單位是字節(jié))
System.out.println(Runtime.getRuntime().maxMemory());
//可用處理器的數(shù)目
System.out.println(Runtime.getRuntime().availableProcessors());
}
}
程序的運行結果為:
250588512
253231104
3747086336
4)解析:4.
垃圾回收器的原理是什么?垃圾回收器是否可以馬上回收內(nèi)存?如何通知虛擬機進行垃圾回收?
(分數(shù):2.00)__________________________________________________________________________________________
正確答案:(在Java語言中,GC(GarbageCollection,垃圾回收)是一個非常重要的概念,它的主要作用是回收程序中不再使用的內(nèi)存。在使用C/C++語言進行程序開發(fā)的時候,開發(fā)人員必須非常仔細地管理好內(nèi)存的分配與釋放,如果忘記或者錯誤地釋放內(nèi)存往往會導致程序運行不正確甚至是程序的崩潰。為了減輕開發(fā)人員的工作,同時增加系統(tǒng)的安全性與穩(wěn)定性,Java語言提供了垃圾回收器來自動檢測對象的作用域,實現(xiàn)自動地把不再被使用的存儲空間釋放掉。具體而言,垃圾回收器主要負責完成3項任務:分配內(nèi)存、確保被引用對象的內(nèi)存不被錯誤地回收以及回收不再被引用的對象的內(nèi)存空間。
垃圾回收器的存在,一方面把開發(fā)人員從釋放內(nèi)存的復雜的工作中解脫出來,提高了開發(fā)人員的生產(chǎn)效率;另外一方面,對開發(fā)人員屏蔽了釋放內(nèi)存的方法,可以避免因為開發(fā)人員錯誤地操作內(nèi)存從而導致應用程序的崩潰,保證了程序的穩(wěn)定性。但是,垃圾回收也帶來了問題,為了實現(xiàn)垃圾回收,垃圾回收器必須跟蹤內(nèi)存的使用情況,釋放沒用的對象,在完成內(nèi)存的釋放后,還需要處理堆中的碎片,這些操作必定會增加JVM的負擔,從而降低程序的執(zhí)行效率。
對于對象而言,如果沒有任何變量去引用它,那么該對象將不可能被程序訪問,因此,可以認為它是垃圾信息,可以被回收。只要有一個以上的變量引用該對象,該對象就不會被垃圾回收。
對于垃圾回收器來說,它使用有向圖來記錄和管理堆內(nèi)存中的所有對象,通過這個有向圖就可以識別哪些對象是“可達的”(有引用變量引用它就是可達的),哪些對象是“不可達的”(沒有引用變量引用它就是不可達的),所有“不可達”對象都是可被垃圾回收的。如下例所示:
publicclassTest
{
publicstaticvoidmain(String[]a)
{
Integeri1=newInteger(1);
Integeri2=newInteger(2);
i2=i1;
//someothercode
}
}
上述代碼在執(zhí)行到語句i2=i1后,內(nèi)存的引用關系如圖所示。
內(nèi)存的引用關系
此時,如果垃圾回收器正在進行垃圾回收操作,在遍歷上述有向圖的時候,資源2所占的內(nèi)存是不可達的,垃圾回收器就會認為這塊內(nèi)存已經(jīng)不會再被使用了,因此,就會回收該塊內(nèi)存空間。
由于垃圾回收器的存在,Java語言本身沒有給開發(fā)人員提供顯式釋放已分配內(nèi)存的方法,也就是說,開發(fā)人員不能實時地調用垃圾回收器對某個對象或所有對象進行垃圾回收。但開發(fā)人員可以通過調用System.gc()方法來通知垃圾回收器運行,當然,JVM也并不會保證垃圾回收器馬上就會運行。由于gc方法的執(zhí)行會停止所有的響應,去檢查內(nèi)存中是否有可回收的對象,這會對程序的正常運行以及性能造成極大的威脅,所以,在實際編程中,不推薦頻繁使用gc方法。)解析:5.
下面代碼是否可以進行優(yōu)化?如果可以,怎么進行優(yōu)化?
for(inti=0;i<1000;i++){
Objectobject=newObject();
System.out.println("objectnameis"+object);
}
(分數(shù):2.00)__________________________________________________________________________________________
正確答案:(可以進行優(yōu)化,優(yōu)化后的代碼為:
Objectobject;
for(inti=0;i<1000;i++)
{
object=newObject();
System.out.println("objectnameis"+object);
}
題目中的寫法,object的作用范圍為for循環(huán)內(nèi)部,每當執(zhí)行一次循環(huán)的時候,就需要在棧中分配一個存儲空間給object使用,這次循環(huán)結束后,object的作用域就結束了,就需要回收object占用的??臻g。本題中,由于循環(huán)次數(shù)為1000次,所以,需要分配1000次存儲空間,同時回收1000次存儲空間,開銷是非常大的。
如果改用上述寫法后,object在整個for循環(huán)執(zhí)行的過程中都是可見的。因此,就不需要不斷地在棧中給object申請與釋放空間,顯然,此種方法具有更高的效率。)解析:6.
如何能使JVM的堆、棧和持久代(perm)發(fā)生內(nèi)存溢出?
(分數(shù):2.00)__________________________________________________________________________________________
正確答案:(在Java語言中,通過new實例化的對象都存儲在堆空間中,因此,只要不斷地用new實例化對象且一直保持對這些對象的引用(垃圾回收器無法回收),實例化足夠多的實例出來就會導致堆溢出,示例代碼如下:
List<Object>1=newArrayList<Object>();
while(true)
1.add(newObject());
上面這段代碼會一直不停地創(chuàng)建Object的對象,并存儲在List里面。因為創(chuàng)建出來的對象一直被引用,所以垃圾回收器無法進行回收,在創(chuàng)建一定的數(shù)量后,就會出現(xiàn)堆溢出。
2)在方法調用的時候,棧用來保存上下文的一些內(nèi)容。由于棧的大小是有上限的,當出現(xiàn)非常深層次的方法調用的時候,就會把棧的空間用完,最簡單的棧溢出的代碼就是無限遞歸調用,示例代碼如下:
publicclassTest
{
publicstaticvoidf()
{
System.out.println("Hello");
f();
}
publicstaticvoidmain(String[]args)
{
f();
}
}
程序運行的過程中會不斷地輸出“Hello”,輸出一會兒后就會拋出java.lang.StackOverflowError異常。
3)持久代。在Java語言中,當一個類第一次被訪問的時候,JVM需要把類加載進來,而類加載器就會占用持久代的空間來存儲classes信息,持久代中主要包含以下的信息:類方法、類名、常量池和JVM使用的內(nèi)部對象等。當JVM需要加載一個新的類的時候,如果持久代中沒有足夠的空間,此時就會拋出Java.Lang.OutOfMemoryError:PermGenSpace異常。所以,當代碼加載足夠多類的時候就會導致持久代溢出。當然,并不是所有的Java虛擬機都有持久代的概念。)解析:7.
Java堆被劃分成老年代和年輕代,它們有什么區(qū)別?
(分數(shù):2.00)__________________________________________________________________________________________
正確答案:(根據(jù)對象的生命周期的長短把對象分成不同的種類(年輕代、年老代和持久代),并分別進行內(nèi)存回收,也就是分代垃圾回收。
分代垃圾回收算法的主要思路如下:把堆分成兩個或者多個子堆,每一個子堆被視為一代。在運行的過程中,優(yōu)先收集那些年幼的對象,如果一個對象經(jīng)過多次收集仍然存活,那么就可以把這個對象轉移到高一級的堆里,減少對其的掃描次數(shù)。
目前最常用的JVM是SUN公司(現(xiàn)被Oracle公司收購)的HotSport,它采用的算法為分代回收。
HotSport把JVM中堆空間劃分為三個代:年輕代(YoungGeneration)、老年代(OldGeneration)和永久代(PermanentGeneration)。以下將分別對這三個代進行分析。
1)年輕代:被分成3個部分,一個Eden區(qū)和兩個相同的Survivor區(qū)。Eden區(qū)主要用來存儲新建的對象,Survivor區(qū)也被叫作from和to區(qū),Survivor區(qū)是大小相等的兩塊區(qū)域,在使用“復制”回收算法時,作為雙緩存,起內(nèi)存整理的作用,因此,Survivor區(qū)始終都保持一個是空的。
2)老年代:主要存儲生命周期較長的對象、超大的對象(無法在新生代分配的對象)。
3)永久代:存放代碼、字符串常量池和靜態(tài)變量等可以持久化的數(shù)據(jù)。SunJDK把方法區(qū)實現(xiàn)在了永久代。
由于永久代基本不參與垃圾回收,所以,這里重點介紹的是年輕代和老年代的垃圾回收方法。
新建對象優(yōu)先在Eden區(qū)分配內(nèi)存,如果Eden區(qū)已滿,在創(chuàng)建對象的時候,會因為無法申請到空間而觸發(fā)minorGc操作,minorGc主要用來對年輕代垃圾進行回收:把Eden區(qū)中不能被回收的對象放入到空的Survivor區(qū),另一個Survivor區(qū)里不能被垃圾回收器回收的對象也會被放入到這個Survivor區(qū),這樣能保證有一個Survivor區(qū)是空的。如果在這個過程中發(fā)現(xiàn)Survivor區(qū)也滿了,就會把這些對象復制到老年代,或者Survivor區(qū)并沒有滿,但是有些對象已經(jīng)存在非常長的時間,這些對象也將被放到老年代中,如果老年代也被放滿了,就會觸發(fā)fullGC。
引申:什么情況下會觸發(fā)fullGC,如何避免?
fullGC是用來清理整個堆空間,包括年輕代和永久代,所以fullGC會造成很大的系統(tǒng)資源開銷。因此,通常需要盡量避免fullGC操作。
下面介紹幾種常見的fullGC產(chǎn)生的原因以及避免的方法。
1)調用System.gc()方法會觸發(fā)fullGC,因此,在編碼的時候盡量避免調用這個方法。
2)老年代空間不足。由于老年代主要用來存儲從年輕代轉入的對象、大對象和大數(shù)組,因此,為了避免觸發(fā)fullGC,應盡量做到讓對象在MinorGC階段被回收,不要創(chuàng)建過大的對象及數(shù)組。由于在MinorGC時,只有Survivor區(qū)放不下的對象才會被放入老年代,而此時只有老年代也放不下才會觸發(fā)fullGC,因此,另外一種避免fullGC的方法如下:根據(jù)實際情況增大Survivor區(qū)、老年代空間或調低觸發(fā)并發(fā)GC(并發(fā)垃圾回收)的概率。
3)永久代滿。永久代主要存放class相關的信息,當永久代滿的時候,也會觸發(fā)fullGC。為了避免這種情況的發(fā)生,可以增大永久代的空間(例如-XX:MaxPermSize=16m:設置永久代大小為16M)。為了避免永久代滿引起的fullGC,也可以開啟CMS回收永久代選項(開啟的選項為+CMSPermGenSweepingEnabled-XX:+CMSClassUnloadingEnabled。CMS利用和應用程序線程并發(fā)的垃圾回收線程來進行垃圾回收操作。
需要注意的是,Java8中已經(jīng)移除了永久代,新加了一個稱為元數(shù)據(jù)區(qū)的native內(nèi)存區(qū),所以,大部分類的元數(shù)據(jù)都在本地內(nèi)存中分配。)解析:8.
List<?extendsT>和List<?superT>之間有什么區(qū)別?
(分數(shù):2.00)__________________________________________________________________________________________
正確答案:(<?extendsT>表示類型的上界,也就是說參數(shù)化的類型的可能是T或是T的子類。例如,下面的寫法都是合法的賦值語句:
List<?extendsNumber>list=newArrayList<Number>();
List<?ExtendsNumber>list=newArrayList<Integer>();//Integer是Number的子類
List<?ExtendsNumber>list=newArrayList<Float>();//Float也是Number的子類
<?extendsT>被設計為用來讀數(shù)據(jù)的泛型(只能讀取類型為T的元素),原因如下:
1)在上面賦值的示例中,對讀數(shù)據(jù)進行分析:
①不管給list如何賦值,可以保證list里面存放的一定是Number類型或其子類,因此,可以從list列表里面讀取Number類型的值。
②不能從list中讀取Integer,因為list里面可能存放的是Float值,同理,也不可以從list里面讀取Float。
2)對寫數(shù)據(jù)進行分析:
①不能向list中寫Number,因為list中有可能存放的是Float。
②不能向list中寫Integer,因為1ist中有可能存放的是Float。
③不能向list中寫Float,因為list中有可能存放的是Integer。
從上面的分析可以發(fā)現(xiàn),只能從List<?extendsT>讀取T,因為無法確定它實際指向列表的類型,所以無法確定列表里面存放的實際的類型,也就無法向列表里面添加元素。
<?superT>表示類型下界,也就是說,參數(shù)化的類型是此類型的超類型(父類型)。
List<?superFloat>list=newArrayList<Float>()
List<?superFloat>list=newArrayList<Number>();
//Number是Float的父類
List<?superFloat>list=newArrayList<Object>();
//Object是Number的父類
<?superT>被設計為用來寫數(shù)據(jù)的泛型(只能寫入T或T的子類類型),不能用來讀,分析如下:
1)讀數(shù)據(jù)。無法保證list里面一定存放的是Float類型或Number類型,因為有可能存放的是Object類型,唯一能確定的是list里面存放的是Object或其子類,但是無法確定具體子類的類型。正是由于無法確定list里面存放數(shù)據(jù)的類型,因此,無法從list里面讀取數(shù)據(jù)。
2)寫數(shù)據(jù)。
①可以向list里面寫入Float類型的數(shù)據(jù)(不管list里面實際存放的是Float、Number或Object,寫入Float都是允許的);同理,也可以向list里面添加Float子類類型的元素。
②不可以向list里面添加Number或Object類型的數(shù)據(jù),因為list中可能存放的是Float類型的數(shù)據(jù)。
下面給出一個以上兩個泛型使用的場景:
publicclassCollections
{
publicstatic<T>
voidcopy(List<?superT>dest,List<?extendsT>src)
{
for(inti=0;i<src.size();i++)
dest.set(i,src.get(i));
}
})解析:9.
ArrayList、Vector和LinkedList有什么特點?
(分數(shù):2.00)__________________________________________________________________________________________
正確答案:(ArrayList、Vector和LinkedList類均在java.util包中,都是可伸縮的數(shù)組,即可以動態(tài)改變長度的數(shù)組。
ArrayList和Vector都是基于存儲元素的Object[]array來實現(xiàn)的,它們會在內(nèi)存中開辟一塊連續(xù)的空間來存儲。由于數(shù)據(jù)存儲是連續(xù)的,因此,它們支持用序號(下標、索引)來訪問元素,同時,索引數(shù)據(jù)的速度比較快。但是在插入元素的時候需要移動容器中的元素,所以,對數(shù)據(jù)的插入操作執(zhí)行速度比較慢。ArrayList和Vector都有一個初始化的容量的大小,當里面存儲的元素超過這個大小的時候,就需要動態(tài)地擴充它們的存儲空間。為了提高程序的效率,每次擴充容量的時候,不是簡單地擴充一個存儲單元,而是一次就會增加多個存儲單元。Vector默認擴充為原來的兩倍(每次擴充空間的大小是可以設置的),而ArrayList默認擴充為原來的1.5倍(沒有提供方法來設置空間擴充的方法)。
ArrayList與Vector最大的區(qū)別就是Synchronization(同步)的使用,沒有一個ArrayList的方法是同步的,而Vector的絕大多數(shù)方法(例如add、insert、remove、set、equals、hashCode等)都是直接或者間接同步的,所以,Vector是線程安全的,ArrayList不是線程安全的。正是由于Vector提供了線程安全的機制,使其性能上也要略遜于ArrayList。
LinkedList是采用雙向列表來實現(xiàn)的,對數(shù)據(jù)的索引需要從列表頭開始遍歷,因此,隨機訪問的效率比較低,但是插入元素的時候不需要對數(shù)據(jù)進行移動,插入效率較高。同時,LinkedList不是線程安全的。
那么,在實際使用時,如何從這幾種容器中選擇合適的使用呢?當對數(shù)據(jù)的主要操作為索引或只在集合的末端增加、刪除元素,使用ArrayList或Vector效率比較高。當對數(shù)據(jù)的操作主要為指定位置的插入或刪除操作,使用LinkedList效率比較高。當在多線程中使用容器時(即多個線程會同時訪問該容器),選用Vector較為安全。)解析:10.
HashMap和Hashtable有什么區(qū)別?
(分數(shù):2.00)__________________________________________________________________________________________
正確答案:(Java為數(shù)據(jù)結構中的映射定義了一個接口java.util.Map,它有三個實現(xiàn)類:HashMap、Hashtable和TreeMap。Map是用來存儲鍵一值對的數(shù)據(jù)結構,在數(shù)組中通過數(shù)組下標來對其內(nèi)容進行索引,而在Map中,則是通過對象來進行索引,用來索引的對象叫作key,其對應的對象叫作value。
HashMap是一個最常用的Map,它根據(jù)鍵的HashCode值存儲數(shù)據(jù),根據(jù)鍵可以直接獲取它的值,具有很快的訪問速度。由于HashMap與Hashtable都采用了hash方法進行索引,因此,二者具有許多相似之處,它們主要有如下的一些區(qū)別:
1)HashMap是Hashtable的輕量級實現(xiàn)(非線程安全的實現(xiàn)),它們都實現(xiàn)了Map接口,主要區(qū)別在于HashMap允許空(null)鍵值(key)(但需要注意,HashMap最多只允許一條記錄的鍵為null,不允許多條記錄的值為null),而Hashtable不允許空(null)鍵值(key)。
2)HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因為contains方法容易讓人引起誤解。Hashtable繼承自Dictionary類,而HashMap是Java1.2引進的Mapinterface的一個實現(xiàn)。
3)Hashtable的方法是線程安全的,而HashMap由于不支持線程的同步,所以,它不是線程安全的。在多個線程訪問Hashtable時,不需要開發(fā)人員對它進行同步,而對于HashMap,開發(fā)人員必須提供額外的同步機制。所以,效率上HashMap可能高于Hashtable。
4)Hashtable使用Enumeration進行遍歷,HashMap使用Iterator進行遍歷。
5)Hashtable和HashMap采用的hash/rehash算法都幾乎一樣,所以,性能不會有很大的差異。
6)Hashtable中hash數(shù)組默認大小是11,增加的方式是old*2+1。在HashMap中,hash數(shù)組的默認大小是16,而且一定是2的指數(shù)。
7)hash值的使用不同,Hashtable直接使用對象的hashC
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 《血友病的護理》課件
- 《行政許可法培訓》課件
- 合肥市房屋租賃合同示范文本
- 工程施工合同約束條款的執(zhí)行力度
- 《氮氣處理的危險》課件
- 《蔬菜腌漬》課件
- 2025年吉林市考貨運上崗證試答題
- 2025年酒泉b2從業(yè)資格證模擬考試題目
- 2025年曲靖貨運從業(yè)資格證試題及答案
- 2025年天津從業(yè)資格貨運資格考試題庫答案解析
- 高三數(shù)學《專題十五數(shù)學建?!氛n件
- 新中國外交復習課
- 精益生產(chǎn)工廠調研報告及改善方案案例解析課件
- 繃縫系列使用說明書V10
- 影視理論基礎知識
- 中考復習-初中英語單詞表大全(2182個帶音標)
- 腹主動脈瘤護理查房課件(PPT 55頁)
- 農(nóng)業(yè)比較效益低的成因及應對
- 生產(chǎn)部績效手冊ppt課件
- 藍色唯美創(chuàng)意潑水節(jié)主題宣傳PPT模板課件
- 小學一年級上冊數(shù)學20以內(nèi)進位加法單元測試卷1
評論
0/150
提交評論