List、Map、Set三個(gè)接口存取元素時(shí),各有什么特點(diǎn)?
List以特定索引來(lái)存取元素,可以有重復(fù)元素。Set不能存放重復(fù)元素(用對(duì)象的equals()方法來(lái)區(qū)分元素是否重復(fù))。Map保存鍵值對(duì)(key-value pair)映射,映射關(guān)系可以是一對(duì)一或多對(duì)一。Set和Map容器都有基于哈希存儲(chǔ)和排序樹的兩種實(shí)現(xiàn)版本,基于哈希存儲(chǔ)的版本理論存取時(shí)間復(fù)雜度為O(1),而基于排序樹版本的實(shí)現(xiàn)在插入或刪除元素時(shí)會(huì)按照元素或元素的鍵(key)構(gòu)成排序樹從而達(dá)到排序和去重的效果。
TreeMap和TreeSet在排序時(shí)如何比較元素?Collections工具類中的sort()方法如何比較元素?
TreeSet要求存放的對(duì)象所屬的類必須實(shí)現(xiàn)Comparable接口,該接口提供了比較元素的compareTo()方法,當(dāng)插入元素時(shí)會(huì)回調(diào)該方法比較元素的大小。TreeMap要求存放的鍵值對(duì)映射的鍵必須實(shí)現(xiàn)Comparable接口從而根據(jù)鍵對(duì)元素進(jìn)行排序。Collections工具類的sort方法有兩種重載的形式,第一種要求傳入的待排序容器中存放的對(duì)象比較實(shí)現(xiàn)Comparable接口以實(shí)現(xiàn)元素的比較;第二種不強(qiáng)制性的要求容器中的元素必須可比較,但是要求傳入第二個(gè)參數(shù),參數(shù)是Comparator接口的子類型(需要重寫compare方法實(shí)現(xiàn)元素的比較),相當(dāng)于一個(gè)臨時(shí)定義的排序規(guī)則,其實(shí)就是通過(guò)接口注入比較元素大小的算法,也是對(duì)回調(diào)模式的應(yīng)用(Java中對(duì)函數(shù)式編程的支持)。
Thread類的sleep()方法和對(duì)象的wait()方法都可以讓線程暫停執(zhí)行,它們有什么區(qū)別?
sleep()方法(休眠)是線程類(Thread)的靜態(tài)方法,調(diào)用此方法會(huì)讓當(dāng)前線程暫停執(zhí)行指定的時(shí)間,將執(zhí)行機(jī)會(huì)(CPU)讓給其他線程,但是對(duì)象的鎖依然保持,因此休眠時(shí)間結(jié)束后會(huì)自動(dòng)恢復(fù)(線程回到就緒狀態(tài),請(qǐng)參考第66題中的線程狀態(tài)轉(zhuǎn)換圖)。wait()是Object類的方法,調(diào)用對(duì)象的wait()方法導(dǎo)致當(dāng)前線程放棄對(duì)象的鎖(線程暫停執(zhí)行),進(jìn)入對(duì)象的等待池(wait pool),只有調(diào)用對(duì)象的notify()方法(或notifyAll()方法)時(shí)才能喚醒等待池中的線程進(jìn)入等鎖池(lock pool),如果線程重新獲得對(duì)象的鎖就可以進(jìn)入就緒狀態(tài)。
線程的sleep()方法和yield()方法有什么區(qū)別?
① sleep()方法給其他線程運(yùn)行機(jī)會(huì)時(shí)不考慮線程的優(yōu)先級(jí),因此會(huì)給低優(yōu)先級(jí)的線程以運(yùn)行的機(jī)會(huì);yield()方法只會(huì)給相同優(yōu)先級(jí)或更高優(yōu)先級(jí)的線程以運(yùn)行的機(jī)會(huì);
② 線程執(zhí)行sleep()方法后轉(zhuǎn)入阻塞(blocked)狀態(tài),而執(zhí)行yield()方法后轉(zhuǎn)入就緒(ready)狀態(tài);
③ sleep()方法聲明拋出InterruptedException,而yield()方法沒(méi)有聲明任何異常;
④ sleep()方法比yield()方法(跟操作系統(tǒng)CPU調(diào)度相關(guān))具有更好的可移植性。
當(dāng)一個(gè)線程進(jìn)入一個(gè)對(duì)象的synchronized方法A之后,其它線程是否可進(jìn)入此對(duì)象的synchronized方法B?
不能。其它線程只能訪問(wèn)該對(duì)象的非同步方法,同步方法則不能進(jìn)入。因?yàn)榉庆o態(tài)方法上的synchronized修飾符要求執(zhí)行方法時(shí)要獲得對(duì)象的鎖,如果已經(jīng)進(jìn)入A方法說(shuō)明對(duì)象鎖已經(jīng)被取走,那么試圖進(jìn)入B方法的線程就只能在等鎖池(注意不是等待池哦)中等待對(duì)象的鎖。
請(qǐng)說(shuō)出與線程同步以及線程調(diào)度相關(guān)的方法。
- wait():使一個(gè)線程處于等待(阻塞)狀態(tài),并且釋放所持有的對(duì)象的鎖;
- sleep():使一個(gè)正在運(yùn)行的線程處于睡眠狀態(tài),是一個(gè)靜態(tài)方法,調(diào)用此方法要處理InterruptedException異常;
- notify():?jiǎn)拘岩粋€(gè)處于等待狀態(tài)的線程,當(dāng)然在調(diào)用此方法的時(shí)候,并不能確切的喚醒某一個(gè)等待狀態(tài)的線程,而是由JVM確定喚醒哪個(gè)線程,而且與優(yōu)先級(jí)無(wú)關(guān);
- notityAll():?jiǎn)拘阉刑幱诘却隣顟B(tài)的線程,該方法并不是將對(duì)象的鎖給所有線程,而是讓它們競(jìng)爭(zhēng),只有獲得鎖的線程才能進(jìn)入就緒狀態(tài);
編寫多線程程序有幾種實(shí)現(xiàn)方式?
Java 5以前實(shí)現(xiàn)多線程有兩種實(shí)現(xiàn)方法:一種是繼承Thread類;另一種是實(shí)現(xiàn)Runnable接口。兩種方式都要通過(guò)重寫run()方法來(lái)定義線程的行為,推薦使用后者,因?yàn)镴ava中的繼承是單繼承,一個(gè)類有一個(gè)父類,如果繼承了Thread類就無(wú)法再繼承其他類了,顯然使用Runnable接口更為靈活。
synchronized關(guān)鍵字的用法?
synchronized關(guān)鍵字可以將對(duì)象或者方法標(biāo)記為同步,以實(shí)現(xiàn)對(duì)對(duì)象和方法的互斥訪問(wèn),可以用synchronized(對(duì)象) { … }定義同步代碼塊,或者在聲明方法時(shí)將synchronized作為方法的修飾符。在第60題的例子中已經(jīng)展示了synchronized關(guān)鍵字的用法。
舉例說(shuō)明同步和異步。
如果系統(tǒng)中存在臨界資源(資源數(shù)量少于競(jìng)爭(zhēng)資源的線程數(shù)量的資源),例如正在寫的數(shù)據(jù)以后可能被另一個(gè)線程讀到,或者正在讀的數(shù)據(jù)可能已經(jīng)被另一個(gè)線程寫過(guò)了,那么這些數(shù)據(jù)就必須進(jìn)行同步存取(數(shù)據(jù)庫(kù)操作中的排他鎖就是最好的例子)。當(dāng)應(yīng)用程序在對(duì)象上調(diào)用了一個(gè)需要花費(fèi)很長(zhǎng)時(shí)間來(lái)執(zhí)行的方法,并且不希望讓程序等待方法的返回時(shí),就應(yīng)該使用異步編程,在很多情況下采用異步途徑往往更有效率。事實(shí)上,所謂的同步就是指阻塞式操作,而異步就是非阻塞式操作。
啟動(dòng)一個(gè)線程是調(diào)用run()還是start()方法?
啟動(dòng)一個(gè)線程是調(diào)用start()方法,使線程所代表的虛擬處理機(jī)處于可運(yùn)行狀態(tài),這意味著它可以由JVM 調(diào)度并執(zhí)行,這并不意味著線程就會(huì)立即運(yùn)行。run()方法是線程啟動(dòng)后要進(jìn)行回調(diào)(callback)的方法。
什么是線程池(thread pool)?
在面向?qū)ο缶幊讨?,?chuàng)建和銷毀對(duì)象是很費(fèi)時(shí)間的,因?yàn)閯?chuàng)建一個(gè)對(duì)象要獲取內(nèi)存資源或者其它更多資源。在Java中更是如此,虛擬機(jī)將試圖跟蹤每一個(gè)對(duì)象,以便能夠在對(duì)象銷毀后進(jìn)行垃圾回收。所以提高服務(wù)程序效率的一個(gè)手段就是盡可能減少創(chuàng)建和銷毀對(duì)象的次數(shù),特別是一些很耗資源的對(duì)象創(chuàng)建和銷毀,這就是”池化資源”技術(shù)產(chǎn)生的原因。線程池顧名思義就是事先創(chuàng)建若干個(gè)可執(zhí)行的線程放入一個(gè)池(容器)中,需要的時(shí)候從池中獲取線程不用自行創(chuàng)建,使用完畢不需要銷毀線程而是放回池中,從而減少創(chuàng)建和銷毀線程對(duì)象的開銷。
Java 5+中的Executor接口定義一個(gè)執(zhí)行線程的工具。它的子類型即線程池接口是ExecutorService。要配置一個(gè)線程池是比較復(fù)雜的,尤其是對(duì)于線程池的原理不是很清楚的情況下,因此在工具類Executors面提供了一些靜態(tài)工廠方法,生成一些常用的線程池,如下所示:
- newSingleThreadExecutor:創(chuàng)建一個(gè)單線程的線程池。這個(gè)線程池只有一個(gè)線程在工作,也就是相當(dāng)于單線程串行執(zhí)行所有任務(wù)。如果這個(gè)唯一的線程因?yàn)楫惓=Y(jié)束,那么會(huì)有一個(gè)新的線程來(lái)替代它。此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。
- newFixedThreadPool:創(chuàng)建固定大小的線程池。每次提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程,直到線程達(dá)到線程池的最大大小。線程池的大小一旦達(dá)到最大值就會(huì)保持不變,如果某個(gè)線程因?yàn)閳?zhí)行異常而結(jié)束,那么線程池會(huì)補(bǔ)充一個(gè)新線程。
- newCachedThreadPool:創(chuàng)建一個(gè)可緩存的線程池。如果線程池的大小超過(guò)了處理任務(wù)所需要的線程,那么就會(huì)回收部分空閑(60秒不執(zhí)行任務(wù))的線程,當(dāng)任務(wù)數(shù)增加時(shí),此線程池又可以智能的添加新線程來(lái)處理任務(wù)。此線程池不會(huì)對(duì)線程池大小做限制,線程池大小完全依賴于操作系統(tǒng)(或者說(shuō)JVM)能夠創(chuàng)建的最大線程大小。
- newScheduledThreadPool:創(chuàng)建一個(gè)大小無(wú)限的線程池。此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。
- newSingleThreadExecutor:創(chuàng)建一個(gè)單線程的線程池。此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。
線程的基本狀態(tài)以及狀態(tài)之間的關(guān)系?
說(shuō)明:其中Running表示運(yùn)行狀態(tài),Runnable表示就緒狀態(tài)(萬(wàn)事俱備,只欠CPU),Blocked表示阻塞狀態(tài),阻塞狀態(tài)又有多種情況,可能是因?yàn)檎{(diào)用wait()方法進(jìn)入等待池,也可能是執(zhí)行同步方法或同步代碼塊進(jìn)入等鎖池,或者是調(diào)用了sleep()方法或join()方法等待休眠或其他線程結(jié)束,或是因?yàn)榘l(fā)生了I/O中斷。
簡(jiǎn)述synchronized 和java.util.concurrent.locks.Lock的異同?
Lock是Java 5以后引入的新的API,和關(guān)鍵字synchronized相比主要相同點(diǎn):Lock 能完成synchronized所實(shí)現(xiàn)的所有功能;主要不同點(diǎn):Lock有比synchronized更精確的線程語(yǔ)義和更好的性能,而且不強(qiáng)制性的要求一定要獲得鎖。synchronized會(huì)自動(dòng)釋放鎖,而Lock一定要求程序員手工釋放,并且最好在finally 塊中釋放(這是釋放外部資源的最好的地方)。
Java中如何實(shí)現(xiàn)序列化,有什么意義?
序列化就是一種用來(lái)處理對(duì)象流的機(jī)制,所謂對(duì)象流也就是將對(duì)象的內(nèi)容進(jìn)行流化??梢詫?duì)流化后的對(duì)象進(jìn)行讀寫操作,也可將流化后的對(duì)象傳輸于網(wǎng)絡(luò)之間。序列化是為了解決對(duì)象流讀寫操作時(shí)可能引發(fā)的問(wèn)題(如果不進(jìn)行序列化可能會(huì)存在數(shù)據(jù)亂序的問(wèn)題)。
要實(shí)現(xiàn)序列化,需要讓一個(gè)類實(shí)現(xiàn)Serializable接口,該接口是一個(gè)標(biāo)識(shí)性接口,標(biāo)注該類對(duì)象是可被序列化的,然后使用一個(gè)輸出流來(lái)構(gòu)造一個(gè)對(duì)象輸出流并通過(guò)writeObject(Object)方法就可以將實(shí)現(xiàn)對(duì)象寫出(即保存其狀態(tài));如果需要反序列化則可以用一個(gè)輸入流建立對(duì)象輸入流,然后通過(guò)readObject方法從流中讀取對(duì)象。序列化除了能夠?qū)崿F(xiàn)對(duì)象的持久化之外,還能夠用于對(duì)象的深度克隆
Java中有幾種類型的流?
字節(jié)流和字符流。字節(jié)流繼承于InputStream、OutputStream,字符流繼承于Reader、Writer。在java.io 包中還有許多其他的流,主要是為了提高性能和使用方便。關(guān)于Java的I/O需要注意的有兩點(diǎn):一是兩種對(duì)稱性(輸入和輸出的對(duì)稱性,字節(jié)和字符的對(duì)稱性);二是兩種設(shè)計(jì)模式(適配器模式和裝潢模式)。另外Java中的流不同于C#的是它只有一個(gè)維度一個(gè)方向。
Statement和PreparedStatement有什么區(qū)別?哪個(gè)性能更好?
與Statement相比,①PreparedStatement接口代表預(yù)編譯的語(yǔ)句,它主要的優(yōu)勢(shì)在于可以減少SQL的編譯錯(cuò)誤并增加SQL的安全性(減少SQL注射攻擊的可能性);②PreparedStatement中的SQL語(yǔ)句是可以帶參數(shù)的,避免了用字符串連接拼接SQL語(yǔ)句的麻煩和不安全;③當(dāng)批量處理SQL或頻繁執(zhí)行相同的查詢時(shí),PreparedStatement有明顯的性能上的優(yōu)勢(shì),由于數(shù)據(jù)庫(kù)可以將編譯優(yōu)化后的SQL語(yǔ)句緩存起來(lái),下次執(zhí)行相同結(jié)構(gòu)的語(yǔ)句時(shí)就會(huì)很快(不用再次編譯和生成執(zhí)行計(jì)劃)。
使用JDBC操作數(shù)據(jù)庫(kù)時(shí),如何提升讀取數(shù)據(jù)的性能?如何提升更新數(shù)據(jù)的性能?
要提升讀取數(shù)據(jù)的性能,可以指定通過(guò)結(jié)果集(ResultSet)對(duì)象的setFetchSize()方法指定每次抓取的記錄數(shù)(典型的空間換時(shí)間策略);要提升更新數(shù)據(jù)的性能可以使用PreparedStatement語(yǔ)句構(gòu)建批處理,將若干SQL語(yǔ)句置于一個(gè)批處理中執(zhí)行。
在進(jìn)行數(shù)據(jù)庫(kù)編程時(shí),連接池有什么作用?
由于創(chuàng)建連接和釋放連接都有很大的開銷(尤其是數(shù)據(jù)庫(kù)服務(wù)器不在本地時(shí),每次建立連接都需要進(jìn)行TCP的三次握手,釋放連接需要進(jìn)行TCP四次握手,造成的開銷是不可忽視的),為了提升系統(tǒng)訪問(wèn)數(shù)據(jù)庫(kù)的性能,可以事先創(chuàng)建若干連接置于連接池中,需要時(shí)直接從連接池獲取,使用結(jié)束時(shí)歸還連接池而不必關(guān)閉連接,從而避免頻繁創(chuàng)建和釋放連接所造成的開銷,這是典型的用空間換取時(shí)間的策略(浪費(fèi)了空間存儲(chǔ)連接,但節(jié)省了創(chuàng)建和釋放連接的時(shí)間)。池化技術(shù)在Java開發(fā)中是很常見(jiàn)的,在使用線程時(shí)創(chuàng)建線程池的道理與此相同?;贘ava的開源數(shù)據(jù)庫(kù)連接池主要有:C3P0、Proxool、DBCP、BoneCP、Druid等
事務(wù)的ACID是指什么?
- 原子性(Atomic):事務(wù)中各項(xiàng)操作,要么全做要么全不做,任何一項(xiàng)操作的失敗都會(huì)導(dǎo)致整個(gè)事務(wù)的失??;
- 一致性(Consistent):事務(wù)結(jié)束后系統(tǒng)狀態(tài)是一致的;
- 隔離性(Isolated):并發(fā)執(zhí)行的事務(wù)彼此無(wú)法看到對(duì)方的中間狀態(tài);
- 持久性(Durable):事務(wù)完成后所做的改動(dòng)都會(huì)被持久化,即使發(fā)生災(zāi)難性的失敗。通過(guò)日志和同步備份可以在故障發(fā)生后重建數(shù)據(jù)。
JDBC中如何進(jìn)行事務(wù)處理?
Connection提供了事務(wù)處理的方法,通過(guò)調(diào)用setAutoCommit(false)可以設(shè)置手動(dòng)提交事務(wù);當(dāng)事務(wù)完成后用commit()顯式提交事務(wù);如果在事務(wù)處理過(guò)程中發(fā)生異常則通過(guò)rollback()進(jìn)行事務(wù)回滾。除此之外,從JDBC 3.0中還引入了Savepoint(保存點(diǎn))的概念,允許通過(guò)代碼設(shè)置保存點(diǎn)并讓事務(wù)回滾到指定的保存點(diǎn)。簡(jiǎn)述正則表達(dá)式及其用途。
在編寫處理字符串的程序時(shí),經(jīng)常會(huì)有查找符合某些復(fù)雜規(guī)則的字符串的需要。正則表達(dá)式就是用于描述這些規(guī)則的工具。換句話說(shuō),正則表達(dá)式就是記錄文本規(guī)則的代碼。
Java中是如何支持正則表達(dá)式操作的?
Java中的String類提供了支持正則表達(dá)式操作的方法,包括:matches()、replaceAll()、replaceFirst()、split()。此外,Java中可以用Pattern類表示正則表達(dá)式對(duì)象,它提供了豐富的API進(jìn)行各種正則表達(dá)式操作,請(qǐng)參考下面面試題的代碼。
獲得一個(gè)類的類對(duì)象有哪些方式?
- 方法1:類型.class,例如:String.class
- 方法2:對(duì)象.getClass(),例如:"hello".getClass()
- 方法3:Class.forName(),例如:Class.forName("java.lang.String")
如何通過(guò)反射創(chuàng)建對(duì)象?
- 方法1:通過(guò)類對(duì)象調(diào)用newInstance()方法,例如:String.class.newInstance()
- 方法2:通過(guò)類對(duì)象的getConstructor()或getDeclaredConstructor()方法獲得構(gòu)造器(Constructor)對(duì)象并調(diào)用其newInstance()方法創(chuàng)建對(duì)象,例如:String.class.getConstructor(String.class).newInstance("Hello");
如何通過(guò)反射獲取和設(shè)置對(duì)象私有字段的值?
可以通過(guò)類對(duì)象的getDeclaredField()方法字段(Field)對(duì)象,然后再通過(guò)字段對(duì)象的setAccessible(true)將其設(shè)置為可以訪問(wèn),接下來(lái)就可以通過(guò)get/set方法來(lái)獲取/設(shè)置字段的值了。下面的代碼實(shí)現(xiàn)了一個(gè)反射的工具類,其中的兩個(gè)靜態(tài)方法分別用于獲取和設(shè)置私有字段的值,字段可以是基本類型也可以是對(duì)象類型且支持多級(jí)對(duì)象操作,例如ReflectionUtil.get(dog, "owner.car.engine.id");可以獲得dog對(duì)象的主人的汽車的引擎的ID號(hào)。
簡(jiǎn)述一下你了解的設(shè)計(jì)模式。
所謂設(shè)計(jì)模式,就是一套被反復(fù)使用的代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)(情境中一個(gè)問(wèn)題經(jīng)過(guò)證實(shí)的一個(gè)解決方案)。使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。設(shè)計(jì)模式使人們可以更加簡(jiǎn)單方便的復(fù)用成功的設(shè)計(jì)和體系結(jié)構(gòu)。將已證實(shí)的技術(shù)表述成設(shè)計(jì)模式也會(huì)使新系統(tǒng)開發(fā)者更加容易理解其設(shè)計(jì)思路。
在GoF的《Design Patterns: Elements of Reusable Object-Oriented Software》中給出了三類(創(chuàng)建型[對(duì)類的實(shí)例化過(guò)程的抽象化]、結(jié)構(gòu)型[描述如何將類或?qū)ο蠼Y(jié)合在一起形成更大的結(jié)構(gòu)]、行為型[對(duì)在不同的對(duì)象之間劃分責(zé)任和算法的抽象化])共23種設(shè)計(jì)模式,包括:Abstract Factory(抽象工廠模式),Builder(建造者模式),F(xiàn)actory Method(工廠方法模式),Prototype(原始模型模式),Singleton(單例模式);Facade(門面模式),Adapter(適配器模式),Bridge(橋梁模式),Composite(合成模式),Decorator(裝飾模式),F(xiàn)lyweight(享元模式),Proxy(代理模式);Command(命令模式),Interpreter(解釋器模式),Visitor(訪問(wèn)者模式),Iterator(迭代子模式),Mediator(調(diào)停者模式),Memento(備忘錄模式),Observer(觀察者模式),State(狀態(tài)模式),Strategy(策略模式),Template Method(模板方法模式), Chain Of Responsibility(責(zé)任鏈模式)。
面試被問(wèn)到關(guān)于設(shè)計(jì)模式的知識(shí)時(shí),可以揀最常用的作答,例如:
- 工廠模式:工廠類可以根據(jù)條件生成不同的子類實(shí)例,這些子類有一個(gè)公共的抽象父類并且實(shí)現(xiàn)了相同的方法,但是這些方法針對(duì)不同的數(shù)據(jù)進(jìn)行了不同的操作(多態(tài)方法)。當(dāng)?shù)玫阶宇惖膶?shí)例后,開發(fā)人員可以調(diào)用基類中的方法而不必考慮到底返回的是哪一個(gè)子類的實(shí)例。
- 代理模式:給一個(gè)對(duì)象提供一個(gè)代理對(duì)象,并由代理對(duì)象控制原對(duì)象的引用。實(shí)際開發(fā)中,按照使用目的的不同,代理可以分為:遠(yuǎn)程代理、虛擬代理、保護(hù)代理、Cache代理、防火墻代理、同步化代理、智能引用代理。
- 適配器模式:把一個(gè)類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無(wú)法在一起使用的類能夠一起工作。
- 模板方法模式:提供一個(gè)抽象類,將部分邏輯以具體方法或構(gòu)造器的形式實(shí)現(xiàn),然后聲明一些抽象方法來(lái)迫使子類實(shí)現(xiàn)剩余的邏輯。不同的子類可以以不同的方式實(shí)現(xiàn)這些抽象方法(多態(tài)實(shí)現(xiàn)),從而實(shí)現(xiàn)不同的業(yè)務(wù)邏輯。
除此之外,還可以講講上面提到的門面模式、橋梁模式、單例模式、裝潢模式(Collections工具類和I/O系統(tǒng)中都使用裝潢模式)等,反正基本原則就是揀自己最熟悉的、用得最多的作答,以免言多必失。
用Java寫一個(gè)單例類。
- 餓漢式單例
public class Singleton {
private Singleton(){}
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static synchronized Singleton getInstance(){
if (instance == null) instance = new Singleton();
return instance;
}
}
類加載機(jī)制
- 啟動(dòng)類加載器( Bootstrap ClassLoader)
啟動(dòng)類加載器無(wú)法被 java 程序員直接引用, 這個(gè)類加載器負(fù)責(zé)把存放在\lib目錄中的, 或者被-Xbootclasspath參數(shù)指定路徑中的, 并且是被虛擬機(jī)識(shí)別的類庫(kù)加載到虛擬機(jī)內(nèi)存中.
- 擴(kuò)展類加載器(Extension ClassLoader)
負(fù)責(zé)加載在\lib\ext目錄中的, 或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫(kù)。
- 應(yīng)用程序類加載器( Application ClassLoader )
這個(gè)類加載器是ClassLoader 中的 getSystemClassLoader()方法的返回值, 一般稱其為系統(tǒng)類加載器, 它負(fù)責(zé)加載用戶類路徑( ClassPath )上所指定的類庫(kù)
從 java 虛擬機(jī)的角度而降, 只存在兩種不同的類加載器:
一個(gè)是啟動(dòng)類加載器( Bootstrap ClassLoader ), 這個(gè)類加載使用 C++ 語(yǔ)言實(shí)現(xiàn), 是虛擬機(jī)自身的一部分;
另一種是其他所有的類加載器, 他們由 java 語(yǔ)言實(shí)現(xiàn), 獨(dú)立于虛擬機(jī)之外, 并且全部繼承自java.lang.ClassLoader
加載類的尋找范圍就是 JVM 默認(rèn)路徑加上Classpath, 類具體是使用哪個(gè)類加載器不確定。
類加載主要步驟
- 加載 把 class 文件的二進(jìn)制字節(jié)流加載到 jvm 里面
- 驗(yàn)證 確保 class 文件的字節(jié)流包含的信息符合當(dāng)前 jvm 的要求 有文件格式驗(yàn)證, -
- 元數(shù)據(jù)驗(yàn)證, 字節(jié)碼驗(yàn)證, 符號(hào)引用驗(yàn)證等
- 準(zhǔn)備 正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段, 初始化為各數(shù)據(jù)類型的零值
- 解析 把常量值內(nèi)的符號(hào)引用替換為直接引用的過(guò)程
- 初始化 執(zhí)行類構(gòu)造器()方法
- 使用 根據(jù)相應(yīng)的業(yè)務(wù)邏輯代碼使用該類
- 卸載 類從方法區(qū)移除
線程 VS 進(jìn)程
關(guān)于線程和進(jìn)程,不正確的描述是__。(選 D 棧是線程私有, 保存其運(yùn)行狀態(tài)和局部變量 )
A. 進(jìn)程的隔離性要好于線程
B. 線程在資源消耗上通常要比進(jìn)程輕量
C. 不同進(jìn)程間不會(huì)共享邏輯地址空間
D. 同一個(gè)進(jìn)程的線程之間共享內(nèi)存,包括堆和棧
E. 進(jìn)程間有途徑共享大量?jī)?nèi)存中的數(shù)據(jù)
F. 線程間通訊可以通過(guò)直接訪問(wèn)全局變量,或者使用進(jìn)程間通訊的機(jī)制(IPC)
歡迎關(guān)注公共號(hào)
關(guān)注公共號(hào)即可獲得最新、最全Android面試題
