牛客错题集5
61.下面代碼的輸出是什么?
public class Base {private String baseName = "base";public Base(){callName();}public void callName(){System. out. println(baseName);}static class Sub extends Base{private String baseName = "sub";public void callName(){System. out. println (baseName) ;}}public static void main(String[] args){Base b = new Sub();} }A.null
B.sub
C.base
答案: A
解析:
這道題也是考察類加載順序的題目.
首先,需要明白類的加載順序:
- (1) 父類靜態(tài)代碼塊(包括靜態(tài)初始化塊,靜態(tài)屬性,但不包括靜態(tài)方法)
- (2) 子類靜態(tài)代碼塊(包括靜態(tài)初始化塊,靜態(tài)屬性,但不包括靜態(tài)方法 )
- (3) 父類非靜態(tài)代碼塊( 包括非靜態(tài)初始化塊,非靜態(tài)屬性 )
- (4) 父類構造函數(shù)
- (5) 子類非靜態(tài)代碼塊 ( 包括非靜態(tài)初始化塊,非靜態(tài)屬性 )
- (6) 子類構造函數(shù)
其中:類中靜態(tài)塊按照聲明順序執(zhí)行,并且(1)和(2)不需要調用new類實例的時候就執(zhí)行了(意思就是在類加載到方法區(qū)的時候執(zhí)行的)
其次,需要理解子類覆蓋父類方法的問題,也就是方法重寫實現(xiàn)多態(tài)問題。
Base b = new Sub();它為多態(tài)的一種表現(xiàn)形式,聲明是Base,實現(xiàn)是Sub類,我們可以簡單理解為 b 編譯時表現(xiàn)為Base類特性,運行時表現(xiàn)為Sub類特性
當子類覆蓋了父類的方法后,意思是父類的方法已經(jīng)被重寫,題中 父類初始化調用的方法為子類實現(xiàn)的方法,子類實現(xiàn)的方法中調用的baseName為子類中的私有屬性。
62.關于volatile關鍵字,下列描述不正確的是?
A.用volatile修飾的變量,每次更新對其他線程都是立即可見的。
B.對volatile變量的操作是原子性的。
C.對volatile變量的操作不會造成阻塞。
D.不依賴其他鎖機制,多線程環(huán)境下的計數(shù)器可用volatile實現(xiàn)。
答案: B D
解析:
所謂 volatile的措施,就是
- 每次從內(nèi)存中取值,不從緩存中什么的拿值。這就保證了用 volatile修飾的共享變量,每次的更新對于其他線程都是可見的。
- volatile保證了其他線程的立即可見性,就沒有保證原子性
- 由于有些時候對 volatile的操作,不會被保存,說明不會造成阻塞。不可用與多線程環(huán)境下的計數(shù)器。
63.方法通常存儲在進程中的哪一區(qū)()
A.堆區(qū)
B.棧區(qū)
C.全局區(qū)
D.方法區(qū)
答案:D
解析:
一條進程的棧區(qū)、堆區(qū)、數(shù)據(jù)區(qū)和代碼區(qū)在內(nèi)存中的映射:
- 棧區(qū):主要用來存放局部變量, 傳遞參數(shù), 存放函數(shù)的返回地址。.esp 始終指向棧頂, 棧中的數(shù)據(jù)越多, esp的值越小。
- 堆區(qū):用于存放動態(tài)分配的對象, 當你使用 malloc和new 等進行分配時,所得到的空間就在堆中。動態(tài)分配得到的內(nèi)存區(qū)域附帶有分配信息, 所以能夠 free和delete它們。
- 數(shù)據(jù)區(qū):全局,靜態(tài)和常量是分配在數(shù)據(jù)區(qū)中的,數(shù)據(jù)區(qū)包括bss(未初始化數(shù)據(jù)區(qū))和初始化數(shù)據(jù)區(qū)。
注意:- 1)堆向高內(nèi)存地址生長;
- 2)棧向低內(nèi)存地址生長;
- 3)堆和棧相向而生,堆和棧之間有個臨界點,稱為stkbrk。
64.下列關于Java并發(fā)的說法中正確的是()
A.CopyOnWriteArrayList適用于寫多讀少的并發(fā)場景
B.ReadWriteLock適用于讀多寫少的并發(fā)場景
C.ConcurrentHashMap的寫操作不需要加鎖,讀操作需要加鎖
D.只要在定義int類型的成員變量i的時候加上volatile關鍵字,那么多線程并發(fā)執(zhí)行i++這樣的操作的時候就是線程安全的了
答案:B
解析:
- 1.CopyOnWriteArrayList的實現(xiàn)原理
在使用CopyOnWriteArrayList之前,我們先閱讀其源碼了解下它是如何實現(xiàn)的。以下代碼是向ArrayList里添加元素,可以發(fā)現(xiàn)在添加的時候是需要加鎖的,否則多線程寫的時候會Copy出N個副本出來。 public boolean add(T e) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;// 復制出新數(shù)組Object[] newElements = Arrays.copyOf(elements, len + 1);// 把新元素添加到新數(shù)組里newElements[len] = e;// 把原數(shù)組引用指向新數(shù)組setArray(newElements);return true;} finally {lock.unlock();}}final void setArray(Object[] a) {array = a;} 讀的時候不需要加鎖,如果讀的時候有多個線程正在向ArrayList添加數(shù)據(jù),讀還是會讀到舊的數(shù)據(jù),因為寫的時候不會鎖住舊的ArrayList public E get(int index) {return get(getArray(), index);} CopyOnWriteArrayList適用于讀多寫少的并發(fā)場景 - 2.ConcurrentHashMap
ConcurrentHashMap采用分段鎖技術,寫操作加鎖,讀操作一般不加鎖,除非讀到的鎖是空的,才會加鎖重讀 - 3.volatite
volatite只保證線程在“加載數(shù)據(jù)階段”加載的數(shù)據(jù)是最新的,并不能保證線程安全
一個線程執(zhí)行的過程有三個階段:
加載(復制)主存數(shù)據(jù)到操作棧 --> 對操作棧數(shù)據(jù)進行修改 --> 將操作棧數(shù)據(jù)寫回主存
volatite關鍵字,讓編譯器不去優(yōu)化代碼使用緩存等,以保證線程在“加載數(shù)據(jù)階段”加載的數(shù)據(jù)都是最新的
對于D選項,之所以volatile不能保證i++的線程安全,除了volatile只能保證可見性之外,與 i++ 不是原子操作也有關,如果換個場合,有些人可能就會把 i++ 誤當成原子操作,其實不是的,因為i++做了三次指令操作:- 1.從內(nèi)存中讀取i 變量的值到CPU的寄存器;
- 2.在寄存器中的i自增1;
- 3.將寄存器中的值寫入內(nèi)存;
65.jre 判斷程序是否執(zhí)行結束的標準是()
A.所有的前臺線程執(zhí)行完畢
B.所有的后臺線程執(zhí)行完畢
C.所有的線程執(zhí)行完畢
D.和以上都無關
答案:A
解析:
- 后臺線程:指為其他線程提供服務的線程,也稱為守護線程。JVM的垃圾回收線程就是一個后臺線程。
- 前臺線程:是指接受后臺線程服務的線程
其實前臺后臺線程是聯(lián)系在一起,就像傀儡和幕后操縱者一樣的關系。傀儡是前臺線程、幕后操縱者是后臺線程。由前臺線程創(chuàng)建的線程默認也是前臺線程。可以通過isDaemon()和setDaemon()方法來判斷和設置一個線程是否為后臺線程。
前臺線程和后臺線程的區(qū)別和聯(lián)系:
- 1、后臺線程不會阻止進程的終止。屬于某個進程的所有前臺線程都終止后,該進程就會被終止。所有剩余的后臺線程都會停止且不會完成。
- 2、可以在任何時候將前臺線程修改為后臺線程,方式是設置Thread.IsBackground 屬性。
- 3、不管是前臺線程還是后臺線程,如果線程內(nèi)出現(xiàn)了異常,都會導致進程的終止。
- 4、托管線程池中的線程都是后臺線程,使用new Thread方式創(chuàng)建的線程默認都是前臺線程。
說明:
應用程序的主線程以及使用Thread構造的線程都默認為前臺線程
使用Thread建立的線程默認情況下是前臺線程,在進程中,只要有一個前臺線程未退出,進程就不會終止。主線程就是一個前臺線程。而后臺線程不管線程是否結束,只要所有的前臺線程都退出(包括正常退出和異常退出)后,進程就會自動終止。一般后臺線程用于處理時間較短的任務,如在一個Web服務器中可以利用后臺線程來處理客戶端發(fā)過來的請求信息。而前臺線程一般用于處理需要長時間等待的任務,如在Web服務器中的監(jiān)聽客戶端請求的程序,或是定時對某些系統(tǒng)資源進行掃描的程序
66.下列關于系列化和反序列化描述正確的是:
A.序列化是將數(shù)據(jù)轉為n個 byte序列的過程
B.反序列化是將n個 byte轉換為數(shù)據(jù)的過程
C.將類型int轉換為4 byte是反序列化過程
D.將8個字節(jié)轉換為long類型的數(shù)據(jù)為序列化過程
答案:AB
76.在Java中,關于HashMap類的描述,以下正確的是 ()
A.HashMap使用鍵/值得形式保存數(shù)據(jù)
B.HashMap 能夠保證其中元素的順序
C.HashMap允許將null用作鍵
D.HashMap允許將null用作值
答案:A C D
解析:
67.下面哪些類實現(xiàn)或者繼承了Collection接口?
A.HashMap
B.ArrayList
C.Vector
D.Iterator
答案:B C
解析:
68.關于Java內(nèi)存區(qū)域下列說法不正確的有哪些
A.程序計數(shù)器是一塊較小的內(nèi)存空間,它的作用可以看做是當前線程所執(zhí)行的字節(jié)碼的信號指示器,每個線程都需要一個獨立的程序計數(shù)器.
B.Java虛擬機棧描述的是java方法執(zhí)行的內(nèi)存模型,每個方法被執(zhí)行的時候都會創(chuàng)建一個棧幀,用于存儲局部變量表、類信息、動態(tài)鏈接等信息
C.Java堆是java虛擬機所管理的內(nèi)存中最大的一塊,每個線程都擁有一塊內(nèi)存區(qū)域,所有的對象實例以及數(shù)組都在這里分配內(nèi)存。
D.方法區(qū)是各個線程共享的內(nèi)存區(qū)域,它用于存儲已經(jīng)被虛擬機加載的常量、即時編譯器編譯后的代碼、靜態(tài)變量等數(shù)據(jù)。
答案:B C
解析:
- A.程序計數(shù)器是一塊較小的內(nèi)存空間,它的作用可以看做是當前線程所執(zhí)行的字節(jié)碼的信號指示器(偏移地址),Java編譯過程中產(chǎn)生的字節(jié)碼有點類似編譯原理的指令,程序計數(shù)器的內(nèi)存空間存儲的是當前執(zhí)行的字節(jié)碼的偏移地址,每一個線程都有一個獨立的程序計數(shù)器(程序計數(shù)器的內(nèi)存空間是線程私有的),因為當執(zhí)行語句時,改變的是程序計數(shù)器的內(nèi)存空間,因此它不會發(fā)生內(nèi)存溢出 ,并且程序計數(shù)器是jvm虛擬機規(guī)范中唯一一個沒有規(guī)定 OutOfMemoryError 異常 的區(qū)域;
- B.java虛擬機棧:線程私有,生命周期和線程一致。描述的是 Java 方法執(zhí)行的內(nèi)存模型:每個方法在執(zhí)行時都會床創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等信息。每一個方法從調用直至執(zhí)行結束,就對應著一個棧幀從虛擬機棧中入棧到出棧的過程。 沒有類信息,類信息是在方法區(qū)中
- C.java堆:對于絕大多數(shù)應用來說,這塊區(qū)域是 JVM 所管理的內(nèi)存中最大的一塊。線程共享,主要是存放對象實例和數(shù)組
- D.方法區(qū):屬于共享內(nèi)存區(qū)域,存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)。
69.以下哪個不屬于JVM堆內(nèi)存中的區(qū)域()?
A.survivor區(qū)
B.常量池
C.eden區(qū)
D.old區(qū)
答案:B
解析:
jvm堆分為:新生代(一般是一個Eden區(qū),兩個Survivor區(qū)),老年代(old區(qū))。
常量池屬于 PermGen(方法區(qū))
70.下面有關java hashmap的說法錯誤的是?
A.HashMap 的實例有兩個參數(shù)影響其性能:“初始容量” 和 “加載因子”
B.HashMap 的實現(xiàn)不是同步的,意味著它不是線程安全的
C.HashMap通過開放地址法解決哈希沖突
D.HashMap中的key-value都是存儲在Entry數(shù)組中的
答案:C
解析:
- a) HashMap實際上是一個“鏈表散列”的數(shù)據(jù)結構,即數(shù)組和鏈表的結合體。HashMap的底層結構是一個數(shù)組,數(shù)組中的每一項是一條鏈表。
- b) HashMap的實例有倆個參數(shù)影響其性能: “初始容量” 和 裝填因子。
- c) HashMap實現(xiàn)不同步,線程不安全。 HashTable線程安全
- d) HashMap中的key-value都是存儲在Entry中的。
- e) HashMap可以存null鍵和null值,不保證元素的順序恒久不變,它的底層使用的是數(shù)組和鏈表,通過hashCode()方法和equals方法保證鍵的唯一性
- f) 解決沖突主要有三種方法:定址法,拉鏈法,再散列法。HashMap是采用拉鏈法解決哈希沖突的。
注:
* 鏈表法是將相同hash值的對象組成一個鏈表放在hash值對應的槽位;用開放定址法解決沖突的做法是:當沖突發(fā)生時,使用某種探查(亦稱探測)技術在散列表中形成一個探查(測)序列。 沿此序列逐個單元地查找,直到找到給定 的關鍵字,或者碰到一個開放的地址(即該地址單元為空)為止(若要插入,在探查到開放的地址,則可將待插入的新結點存人該地址單元)。
* 拉鏈法解決沖突的做法是: 將所有關鍵字為同義詞的結點鏈接在同一個單鏈表中 。若選定的散列表長度為m,則可將散列表定義為一個由m個頭指針組成的指針數(shù) 組T[0…m-1]。凡是散列地址為i的結點,均插入到以T[i]為頭指針的單鏈表中。T中各分量的初值均應為空指針。在拉鏈法中,裝填因子α可以大于1,但一般均取α≤1。拉鏈法適合未規(guī)定元素的大小。
- a) 繼承不同。 public class Hashtable extends Dictionary implements Map public class HashMap extends AbstractMap implements Map
- b) Hashtable中的方法是同步的,而HashMap中的方法在缺省情況下是非同步的。在多線程并發(fā)的環(huán)境下,可以直接使用Hashtable,但是要使用HashMap的話就要自己增加同步處理了。
- c) Hashtable 中, key 和 value 都不允許出現(xiàn) null 值。 在 HashMap 中, null 可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值為 null 。當 get() 方法返回 null 值時,即可以表示 HashMap 中沒有該鍵,也可以表示該鍵所對應的值為 null 。因此,在 HashMap 中不能由 get() 方法來判斷 HashMap 中是否存在某個鍵, 而應該用 containsKey() 方法來判斷。
- d) 兩個遍歷方式的內(nèi)部實現(xiàn)上不同。Hashtable、HashMap都使用了Iterator。而由于歷史原因,Hashtable還使用了Enumeration的方式 。
- e) 哈希值的使用不同,HashTable直接使用對象的hashCode。而HashMap重新計算hash值。
- f) Hashtable和HashMap它們兩個內(nèi)部實現(xiàn)方式的數(shù)組的初始大小和擴容的方式。HashTable中hash數(shù)組默認大小是11,增加的方式是old*2+1。HashMap中hash數(shù)組的默認大小是16,而且一定是2的指數(shù)。
注: HashSet子類依靠hashCode()和equal()方法來區(qū)分重復元素。
HashSet內(nèi)部使用Map保存數(shù)據(jù),即將HashSet的數(shù)據(jù)作為Map的key值保存,這也是HashSet中元素不能重復的原因。而Map中保存key值的,會去判斷當前Map中是否含有該Key對象,內(nèi)部是先通過key的hashCode,確定有相同的hashCode之后,再通過equals方法判斷是否相同。
71.Java是一門支持反射的語言,基于反射為Java提供了豐富的動態(tài)性支持,下面關于Java反射的描述,哪些是錯誤的:( )
A.Java反射主要涉及的類如Class, Method, Filed,等,他們都在java.lang.reflet包下
B.通過反射可以動態(tài)的實現(xiàn)一個接口,形成一個新的類,并可以用這個類創(chuàng)建對象,調用對象方法
C.通過反射,可以突破Java語言提供的對象成員、類成員的保護機制,訪問一般方式不能訪問的成員
D.Java反射機制提供了字節(jié)碼修改的技術,可以動態(tài)的修剪一個類
E.Java的反射機制會給內(nèi)存帶來額外的開銷。例如對永生堆的要求比不通過反射要求的更多
F.Java反射機制一般會帶來效率問題,效率問題主要發(fā)生在查找類的方法和字段對象,因此通過緩存需要反射類的字段和方法就能達到與之間調用類的方法和訪問類的字段一樣的效率
答案:A D F
解析:
- A Class類在java.lang包
- B 動態(tài)代理技術可以動態(tài)創(chuàng)建一個代理對象,反射不行
- C 反射訪問私有成員時,Field調用setAccessible可解除訪問符限制
- D CGLIB實現(xiàn)了字節(jié)碼修改,反射不行
- E 反射會動態(tài)創(chuàng)建額外的對象,比如每個成員方法只有一個Method對象作為root,他不胡直接暴露給用戶。調用時會返回一個Method的包裝類
- F 反射帶來的效率問題主要是動態(tài)解析類,JVM沒法對反射代碼優(yōu)化。
72.關于身份證號,以下正確的正則表達式為( )
A.isIDCard=/^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/;
B.isIDCard=/^[1-9]\d{7}((9\d)|(1[0-2]))(([0|1|2]\d)|3[9-1])\d{3}$/;
C.isIDCard=/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$/;
D.isIDCard=/^[1-9]\d{5}[1-9]\d{3}((9\d)|(1[9-2]))(([0|1|2]\d)|3[9-1])\d{4}$/;
答案: A C
解析:
- ^:起始符號,^x表示以x開頭
- $:結束符號,x$表示以x結尾
- [n-m]:表示從n到m的數(shù)字
- \d:表示數(shù)字,等同于[0-9]
- X{m}:表示由m個X字符構成,\d{4}表示4位數(shù)字
15位身份證的構成:六位出生地區(qū)碼+六位出身日期碼+三位順序碼
18位身份證的構成:六位出生地區(qū)碼+八位出生日期碼+三位順序碼+一位校驗碼
73.Java表達式"13 & 17"的結果是什么?()
A.30
B.13
C.17
D.1
答案:D
解析:
此處考察與運算,做這種題只需要2步
1.將數(shù)值轉為二進制:13(01101),17(10001)
2.將二進制數(shù)值進行相與運算,只有都為1的情況下才為1
最終的運算結果為00001即對應的10進制為1
74.關于protected 修飾的成員變量,以下說法正確的是()
A.可以被該類自身、與它在同一個包中的其它類、在其它包中的該類的子類所訪問
B.只能被該類本身和該類的所有的子類訪問
C.只能被該類自身所訪問
D.只能被同一個包中的類訪問
答案:A
解析:
| public | √ | √ | √ | √ |
| protected | √ | √ | √ | × |
| default | √ | √ | × | × |
| private | √ | × | × | × |
75.以下代碼執(zhí)行的結果顯示是多少( )?
A.true,false,true
B.false,true,false
C.true,true,false
D.false,false,true
答案:D
解析:
首先我先解釋一下String的地址引用
- 1.String s = “abc”:通過字面量賦值創(chuàng)建字符串。則將棧中的引用直接指向該字符串,如不存在,則在常量池中生成一個字符串,再將棧中的引用指向該字符串
- 2.String s = “a”+“bc”:編譯階段會直接將“a”和“bc”結合成“abc”,這時如果方法區(qū)已存在“abc”,則將s的引用指向該字符串,如不存在,則在方法區(qū)中生成字符串“abc”對象,然后再將s的引用指向該字符串
- 3.String s = “a” + new String(“bc”):棧中先創(chuàng)建一個"a"字符串常量,再創(chuàng)建一個"bc"字符串常量,編譯階段不會進行拼接,在運行階段拼接成"abc"字符串常量并將s的引用指向它,效果相當于String s = new String(“abc”),只有’+'兩邊都是字符串常量才會在編譯階段優(yōu)化。
我們再回到題目,其中i3和i4分別屬于1,3的情況,i3屬于字符串常量,在棧中(常量池中),i4屬于拼接,只有在編譯階段才能知道,所以在堆中,地址則肯定不同。
接下來我接著解釋一下整型的地址引用
Integer i1=128 表示Integer i1=Integer.valueOf(128)
Interger 賦予的int數(shù)值在-128 - 127的時候,直接從IntegerCache中獲取,這些IntegerCache引用對Integer對象地址是不變的,但是不在這個范圍內(nèi)的數(shù)字,則new Integer(i) 這個地址是新的地址,不可能一樣的。
總結
- 上一篇: Pr:导出设置之多路复用器与常规
- 下一篇: mysql查姓名中既有a也有e的姓_my