阿里JAVA開發(fā)面試常問問題
阿里JAVA開發(fā)面試常問問題
Java中沒有虛函數(shù)的概念。它的普通函數(shù)就相當(dāng)于c++的虛函數(shù),動(dòng)態(tài)綁定是java的默認(rèn)行為。下面就由學(xué)習(xí)啦小編為大家介紹一下阿里JAVA開發(fā)面試常問問題的文章,歡迎閱讀。
阿里JAVA開發(fā)面試常問問題篇1
棧內(nèi)存、堆內(nèi)存
在函數(shù)中定義的一些基本類型的變量和對(duì)象的引用變量都是在函數(shù)的棧內(nèi)存中分配。當(dāng)在一段代碼塊中定義一個(gè)變量時(shí),java就在棧中為這個(gè)變量分配內(nèi)存空間,當(dāng)超過變量的作用域后,java會(huì)自動(dòng)釋放掉為該變量分配的內(nèi)存空間,該內(nèi)存空間可以立刻被另作他用。
堆內(nèi)存用于存放由new創(chuàng)建的對(duì)象和數(shù)組。在堆中分配的內(nèi)存,由java虛擬機(jī)自動(dòng)垃圾回收器來管理。在數(shù)組和對(duì)象在沒有引用變量指向它的時(shí)候,才變成垃圾,不能再被使用,但是仍然占著內(nèi)存,在隨后的一個(gè)不確定的時(shí)間被垃圾回收器釋放掉。這個(gè)也是java比較占內(nèi)存的主要原因。
引用、值傳遞
值傳遞:方法調(diào)用時(shí),實(shí)際參數(shù)把它的值傳遞給對(duì)應(yīng)的形式參數(shù),方法執(zhí)行中形式參數(shù)值的改變不影響實(shí)際參數(shù)的值。
引用傳遞:也稱為傳地址。方法調(diào)用時(shí),實(shí)際參數(shù)的引用(地址,而不是參數(shù)的值)被傳遞給方法中相對(duì)應(yīng)的形式參數(shù),在方法執(zhí)行中,對(duì)形式參數(shù)的操作實(shí)際上就是對(duì)實(shí)際參數(shù)的操作,方法執(zhí)行中形式參數(shù)值的改變將會(huì)影響實(shí)際參數(shù)的值。
單例模式及好處
構(gòu)造函數(shù)私有化,用一個(gè)靜態(tài)方法來獲取對(duì)象實(shí)例。
特點(diǎn):
1)單例類只能有一個(gè)實(shí)例。
2)單例類必須自己創(chuàng)建自己的唯一實(shí)例。
3)單例類必須給所有其他對(duì)象提供這一實(shí)例。
主要優(yōu)點(diǎn):
1)提供了對(duì)唯一實(shí)例的受控訪問。
2)由于在系統(tǒng)內(nèi)存中只存在一個(gè)對(duì)象,因此可以節(jié)約系統(tǒng)資源,對(duì)于一些需要頻繁創(chuàng)建和銷毀的對(duì)象單例模式無疑可以提高系統(tǒng)的性能。
3)允許可變數(shù)目的實(shí)例。
主要缺點(diǎn):
1)由于單利模式中沒有抽象層,因此單例類的擴(kuò)展有很大的困難。
2)單例類的職責(zé)過重,在一定程度上違背了“單一職責(zé)原則”。
3)濫用單例將帶來一些負(fù)面問題,如為了節(jié)省資源將數(shù)據(jù)庫連接池對(duì)象設(shè)計(jì)為的單例類,可能會(huì)導(dǎo)致共享連接池對(duì)象的程序過多而出現(xiàn)連接池溢出;如果實(shí)例化的對(duì)象長時(shí)間不被利用,系統(tǒng)會(huì)認(rèn)為是垃圾而被回收,這將導(dǎo)致對(duì)象狀態(tài)的丟失。
阿里JAVA開發(fā)面試常問問題篇2
重載和重寫
重載:Overloading
(1) Java的方法重載,就是在類中可以創(chuàng)建多個(gè)方法,它們具有相同的名字,但具有不同的參數(shù)和不同的定義。調(diào)用方法時(shí)通過傳遞給它們的不同參數(shù)個(gè)數(shù)和參數(shù)類型來決定具體使用哪個(gè)方法, 這就是多態(tài)性。
(2) 重載的時(shí)候,方法名要一樣,但是參數(shù)類型和個(gè)數(shù)不一樣,返回值類型可以相同也可以不相同。無法以返回類型作為重載函數(shù)的區(qū)分標(biāo)準(zhǔn)。
重寫:Overriding
注意:當(dāng)要重寫父類方法時(shí),要使用@Override標(biāo)簽提醒編譯器檢查代碼是否是重寫,而不是重載了原來的方法。
(1) 父類與子類之間的多態(tài)性,對(duì)父類的函數(shù)進(jìn)行重新定義。如果在子類中定義某方法與其父類有相同的名稱和參數(shù),我們說該方法被重寫 (Overriding)。在Java中,子類可繼承父類中的方法,而不需要重新編寫相同的方法。但有時(shí)子類并不想原封不動(dòng)地繼承父類的方法,而是想作一定的修改,這就需要采用方法的重寫。方法重寫又稱方法覆蓋。
(2)若子類中的方法與父類中的某一方法具有相同的方法名、返回類型和參數(shù)表,則新方法將覆蓋原有的方法。如需父類中原有的方法,可使用super關(guān)鍵字,該關(guān)鍵字引用了當(dāng)前類的父類。
(3)子類函數(shù)的訪問修飾權(quán)限不能少于父類的。
子類、父類間的轉(zhuǎn)換和構(gòu)造順序
子類、父類間的轉(zhuǎn)換:
子類能夠自動(dòng)轉(zhuǎn)換成父類類型。
當(dāng)創(chuàng)建子類對(duì)象的時(shí)候:
①先調(diào)用了子類的構(gòu)造函數(shù)
?、谡{(diào)用了父類的構(gòu)造函數(shù)
?、蹐?zhí)行了父類的構(gòu)造函數(shù)
?、軋?zhí)行了子類的構(gòu)造函數(shù)
Final、finally、finalize
final 用于聲明屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承。
finally是異常處理語句結(jié)構(gòu)的一部分,表示總是執(zhí)行。
finalize是Object類的一個(gè)方法,在垃圾收集器執(zhí)行的時(shí)候會(huì)調(diào)用被回收對(duì)象的此方法,可以覆蓋此方法提供垃圾收集時(shí)的其他資源回收,例如關(guān)閉文件等
Synchronized和volatile的區(qū)別
volatile只作用于在多個(gè)線程之間能夠被共享的變量。如果一個(gè)字段被聲明成volatile,java線程內(nèi)存模型確保所有線程看到這個(gè)變量的值是一致的。Volatile變量修飾符如果使用恰當(dāng)?shù)脑?,它比synchronized的使用和執(zhí)行成本會(huì)更低,因?yàn)樗粫?huì)引起線程上下文的切換和調(diào)度。
synchronized獲得并釋放監(jiān)視器——如果兩個(gè)線程使用了同一個(gè)對(duì)象鎖,監(jiān)視器能強(qiáng)制保證代碼塊同時(shí)只被一個(gè)線程所執(zhí)行——這是眾所周知的事實(shí)。但是,synchronized也同步內(nèi)存:事實(shí)上,synchronized在“ 主”內(nèi)存區(qū)域同步整個(gè)線程的內(nèi)存。
因此volatile只是在線程內(nèi)存和“主”內(nèi)存間同步某個(gè)變量的值,而synchronized通過鎖定和解鎖某個(gè)監(jiān)視器同步所有變量的值。顯然synchronized要比volatile消耗更多資源。
1)volatile本質(zhì)是在告訴jvm當(dāng)前變量在寄存器(工作內(nèi)存)中的值是不確定的,需要從主存中讀取,沒有互斥鎖;synchronized則是鎖定當(dāng)前變量,只有當(dāng)前線程可以訪問該變量,其他線程被阻塞住。
2)volatile僅能使用在變量級(jí)別;synchronized則可以使用在變量、方法、和類級(jí)別的
3)volatile只是在線程內(nèi)存和“主”內(nèi)存間同步某個(gè)變量的值,而synchronized通過鎖定和解鎖某個(gè)監(jiān)視器同步所有變量的值;顯然synchronized要比volatile消耗更多資源。
4)volatile不會(huì)造成線程的阻塞;synchronized可能會(huì)造成線程的阻塞。
5)volatile標(biāo)記的變量不會(huì)被編譯器優(yōu)化;synchronized標(biāo)記的變量可以被編譯器優(yōu)化 。
阿里JAVA開發(fā)面試常問問題篇3
集合類沒有實(shí)現(xiàn)Cloneable和Serializable接口的原因
Collection接口指定一組對(duì)象,對(duì)象即為它的元素。如何維護(hù)這些元素由Collection的具體實(shí)現(xiàn)決定。例如,一些如List的Collection實(shí)現(xiàn)允許重復(fù)的元素,而其它的如Set就不允許。很多Collection實(shí)現(xiàn)有一個(gè)公有的clone方法。然而,把它放到集合的所有實(shí)現(xiàn)中也是沒有意義的。這是因?yàn)镃ollection是一個(gè)抽象表現(xiàn)。重要的是實(shí)現(xiàn)。
當(dāng)與具體實(shí)現(xiàn)打交道的時(shí)候,克隆或序列化的語義和含義才發(fā)揮作用。所以,具體實(shí)現(xiàn)應(yīng)該決定如何對(duì)它進(jìn)行克隆或序列化,或它是否可以被克隆或序列化。
在所有的實(shí)現(xiàn)中授權(quán)克隆和序列化,最終導(dǎo)致更少的靈活性和更多的限制。特定的實(shí)現(xiàn)應(yīng)該決定它是否可以被克隆和序列化。
hashCode()和equals()方法的重要性體現(xiàn)在什么地方?
HashMap使用Key對(duì)象的hashCode()和equals()方法去決定key-value對(duì)的索引。當(dāng)我們試著從HashMap中獲取值的時(shí)候,這些方法也會(huì)被用到。如果這些方法沒有被正確地實(shí)現(xiàn),在這種情況下,兩個(gè)不同Key也許會(huì)產(chǎn)生相同的hashCode()和equals()輸出,HashMap將會(huì)認(rèn)為它們是相同的,然后覆蓋它們,而非把它們存儲(chǔ)到不同的地方。同樣的,所有不允許存儲(chǔ)重復(fù)數(shù)據(jù)的集合類都使用hashCode()和equals()去查找重復(fù),所以正確實(shí)現(xiàn)它們非常重要。
equals()和hashCode()的實(shí)現(xiàn)應(yīng)該遵循以下規(guī)則:
(1)如果o1.equals(o2),那么o1.hashCode() == o2.hashCode()總是為true的。
(2)如果o1.hashCode() == o2.hashCode(),并不意味著o1.equals(o2)會(huì)為true。
Java中的HashMap使用hashCode()和equals()方法來確定鍵值對(duì)的索引,當(dāng)根據(jù)鍵獲取值的時(shí)候也會(huì)用到這兩個(gè)方法。如果沒有正確的實(shí)現(xiàn)這兩個(gè)方法,兩個(gè)不同的鍵可能會(huì)有相同的hash值,因此,可能會(huì)被集合認(rèn)為是相等的。而且,這兩個(gè)方法也用來發(fā)現(xiàn)重復(fù)元素。所以這兩個(gè)方法的實(shí)現(xiàn)對(duì)HashMap的精確性和正確性是至關(guān)重要的。
HashMap和HashTabel的區(qū)別
HashMap和Hashtable都實(shí)現(xiàn)了Map接口,因此很多特性非常相似。但是,他們有以下不同點(diǎn):
1)HashMap允許鍵和值是null,而Hashtable不允許鍵或者值是null。
2)Hashtable是同步的,而HashMap不是。因此,HashMap更適合于單線程環(huán)境,而Hashtable適合于多線程環(huán)境。
3)HashMap提供了可供應(yīng)用迭代的鍵的集合,因此,HashMap是快速失敗的。另一方面,Hashtable提供了對(duì)鍵的列舉(Enumeration)。
一般認(rèn)為Hashtable是一個(gè)遺留的類。
Comparable和Comparator接口
Comparable和Comparator都是用來實(shí)現(xiàn)集合中的排序的,只是Comparable是在集合內(nèi)部定義的方法實(shí)現(xiàn)的排序,Comparator是在集合外部實(shí)現(xiàn)的排序,所以,如想實(shí)現(xiàn)排序,就需要在集合外定義Comparator接口的方法compare()或在集合內(nèi)實(shí)現(xiàn)Comparable接口的方法compareTo()。
comparable是支持自比較,而后者是支持外部比較;
Comparable是一個(gè)對(duì)象本身就已經(jīng)支持自比較所需要實(shí)現(xiàn)的接口(如String、Integer自己就可以完成比較大小操作)
而Comparator是一個(gè)專用的比較器,當(dāng)這個(gè)對(duì)象不支持自比較或者自比較函數(shù)不能滿足你的要求時(shí),你可以寫一個(gè)比較器來完成兩個(gè)對(duì)象之間大小的比較。
也就是說當(dāng)你需要對(duì)一個(gè)自定義的類的一個(gè)數(shù)組或者集合進(jìn)行比較的時(shí)候可以實(shí)現(xiàn)Comparable接口,當(dāng)你需要對(duì)一個(gè)已有的類的數(shù)組或者集合進(jìn)行比較的時(shí)候就一定要實(shí)現(xiàn)Comparator接口。另外,這兩個(gè)接口是支持泛型的,所以我們應(yīng)該在實(shí)現(xiàn)接口的同時(shí)定義比較類型。
Java中HashMap的工作原理是?
Java中的HashMap是以鍵值對(duì)(key-value)的形式存儲(chǔ)元素的。HashMap需要一個(gè)hash函數(shù),它使用hashCode()和equals()方法來向集合/從集合添加和檢索元素。當(dāng)調(diào)用put()方法的時(shí)候,HashMap會(huì)計(jì)算key的hash值,然后把鍵值對(duì)存儲(chǔ)在集合中合適的索引上。如果key已經(jīng)存在了,value會(huì)被更新成新值。HashMap的一些重要的特性是它的容量(capacity),負(fù)載因子(load factor)和擴(kuò)容極限(threshold resizing)。
1)HashMap有一個(gè)叫做Entry的內(nèi)部類,它用來存儲(chǔ)key-value對(duì)。
2)上面的Entry對(duì)象是存儲(chǔ)在一個(gè)叫做table的Entry數(shù)組中。
3)table的索引在邏輯上叫做“桶”(bucket),它存儲(chǔ)了鏈表的第一個(gè)元素。
4)key的hashcode()方法用來找到Entry對(duì)象所在的桶。
5)如果兩個(gè)key有相同的hash值,他們會(huì)被放在table數(shù)組的同一個(gè)桶里面。
6)key的equals()方法用來確保key的唯一性。
7)value對(duì)象的equals()和hashcode()方法根本一點(diǎn)用也沒有。
重點(diǎn)內(nèi)容
Put:根據(jù)key的hashcode()方法計(jì)算出來的hash值來決定key在Entry數(shù)組的索引。
Get:通過hashcode找到數(shù)組中的某一個(gè)元素Entry
Hashcode的實(shí)現(xiàn)
hashCode 的常規(guī)協(xié)定是:
在 Java 應(yīng)用程序執(zhí)行期間,在同一對(duì)象上多次調(diào)用 hashCode 方法時(shí),必須一致地返回相同的整數(shù),前提是對(duì)象上 equals 比較中所用的信息沒有被修改。從某一應(yīng)用程序的一次執(zhí)行到同一應(yīng)用程序的另一次執(zhí)行,該整數(shù)無需保持一致。
如果根據(jù) equals(Object) 方法,兩個(gè)對(duì)象是相等的,那么在兩個(gè)對(duì)象中的每個(gè)對(duì)象上調(diào)用 hashCode 方法都必須生成相同的整數(shù)結(jié)果。
當(dāng)equals方法被重寫時(shí),通常有必要重寫 hashCode 方法,以維護(hù) hashCode 方法的常規(guī)協(xié)定,該協(xié)定聲明相等對(duì)象必須具有相等的哈希碼。
String、StringBffer、StringBuilder的區(qū)別
1)可變與不可變
String類中使用字符數(shù)組保存字符串,如下就是,因?yàn)橛?ldquo;final”修飾符,所以可以知道string對(duì)象是不可變的。
private final char value[];
StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數(shù)組保存字符串,如下就是,可知這兩種對(duì)象都是可變的。
char[] value;
2)是否多線程安全
String中的對(duì)象是不可變的,也就可以理解為常量,顯然線程安全。
AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。
StringBuffer對(duì)方法加了同步鎖或者對(duì)調(diào)用的方法加了同步鎖,所以是線程安全的