摘要:網(wǎng)站的面試專(zhuān)題學(xué)習(xí)筆記非可變性和對(duì)象引用輸出為,前后皆有空格。假定棧空間足夠的話,盡管遞歸調(diào)用比較難以調(diào)試,在語(yǔ)言中實(shí)現(xiàn)遞歸調(diào)用也是完全可行的。棧遵守規(guī)則,因此遞歸調(diào)用方法能夠記住調(diào)用者并且知道此輪執(zhí)行結(jié)束之返回至當(dāng)初的被調(diào)用位置。
ImportNew 網(wǎng)站的Java面試專(zhuān)題學(xué)習(xí)筆記
1. 非可變性和對(duì)象引用String s = " Hello "; s += " World "; s.trim( ); System.out.println(s);
輸出為“ Hello World ”,前后皆有空格。
字符串是不可變對(duì)象。
s.trim()雖然生成了一個(gè)新的字符串對(duì)象,但是卻沒(méi)有變量指向這個(gè)心生成的對(duì)象,s 仍然指向字符串s += " World "。
下圖說(shuō)明了,生成對(duì)象以及垃圾回收過(guò)程。
可用StringBuilder來(lái)構(gòu)造,因?yàn)槠涞讓邮褂玫氖亲址麛?shù)組,所有操作都直接在字符數(shù)組上直接操作,而且他不是一個(gè)線程安全的類(lèi),執(zhí)行速度上,相比于StringBuffer要快。
這一點(diǎn)如果深入理解了String的Interning機(jī)制,就更好理解了。
Java程序在編譯時(shí),會(huì)將所有確定下來(lái)的,存在雙引號(hào)內(nèi)的字符串,都存入常量池中,該常量池是類(lèi)文件(.class)的一部分。常量池中存著許多表,其中 Constant_Utf8_info 表中,記錄著會(huì)被初始化為 String 對(duì)象的字符串的字面值(iteral)。 在JVM 中,相應(yīng)的類(lèi)被加載運(yùn)行后,常量池對(duì)應(yīng)的映射到 JVM 的運(yùn)行時(shí)常量池(run time constant pool)中。
關(guān)于String的intern()方法
當(dāng) intern 方法被調(diào)用,如果字符串池中已經(jīng)擁有一個(gè)與該 String 的字符串值相等(即 equals()調(diào)用后為 true)的 String 對(duì)象時(shí),那么池中的那個(gè) String 對(duì)象會(huì)被返回。否則,池中會(huì)增加這個(gè)對(duì)象,并返回當(dāng)前這個(gè) String 對(duì)象。
現(xiàn)代的 JVM 實(shí)現(xiàn)里,考慮到垃圾回收(Garbage Collection)的方便,將 heap 劃分為三部分: young generation 、 tenured generation(old generation)和 permanent generation( permgen )。字符串池是為了解決字符串重復(fù)的問(wèn)題,生命周期長(zhǎng),它存在于 permgen 中。
因此,對(duì)于
String str = new String("abc");
JVM會(huì)生成兩個(gè)字符串,一個(gè)是在常量池中,另外一個(gè)是new在heap堆中。
2. equals 和 ==Object s1 = new String("Hello"); Object s2 = new String("Hello"); if(s1 == s2) { System.out.println("s1 and s2 are =="); }else if (s1.equals(s2)) { System.out.println("s1 and s2 are equals()"); }
輸出結(jié)果為s1 and s2 are equals()
主要考察對(duì)equals和==的理解,==比較引用的地址是否相同,equeal比較對(duì)象中真正的值。
詳細(xì)的過(guò)程可見(jiàn)下圖
另外,如果不是用 new關(guān)鍵字強(qiáng)制創(chuàng)建字符串對(duì)象的話,而是采用==,那么Java會(huì)默認(rèn)采用字符串池,減少對(duì)象的創(chuàng)建。
String對(duì)象會(huì)創(chuàng)建一個(gè)字符串池(a pool of string),如果當(dāng)前準(zhǔn)備新創(chuàng)建的字符串對(duì)象的值在這個(gè)池子中已經(jīng)存在,那么就不會(huì)生成新對(duì)象,而是復(fù)用池中已有的字符串對(duì)象。flyweight 模式的精髓就是對(duì)象復(fù)用。
重寫(xiě)發(fā)生在子類(lèi)繼承父類(lèi)時(shí),子類(lèi)覆蓋父類(lèi)的方法時(shí)發(fā)生,是在運(yùn)行時(shí)發(fā)生。
重載是在同一個(gè)類(lèi)中,同一個(gè)方法,不同參數(shù)時(shí)發(fā)生,是在編譯期發(fā)生。
在Java 5中使用注解@override,來(lái)標(biāo)示方法重寫(xiě),如果編譯時(shí)發(fā)現(xiàn)沒(méi)有重寫(xiě),則JVM會(huì)拋出編譯異常。
4. 迭代和遞歸可重入方法(re-entrant method)是可以安全進(jìn)入的方法,即使同一個(gè)方法正在被執(zhí)行,深入到同一個(gè)線程的調(diào)用棧里面也不會(huì)影響此次執(zhí)行的安全性。一個(gè)非可重入方法則不是可以安全進(jìn)入的。例如,加入寫(xiě)文件或者向文件中寫(xiě)入日志的方法不是可重入方法時(shí),有可能會(huì)毀壞那個(gè)文件。
如果一個(gè)方法調(diào)用了其自身的話,我們稱(chēng)之為遞歸調(diào)用。假定棧空間足夠的話,盡管遞歸調(diào)用比較難以調(diào)試,在Java語(yǔ)言中實(shí)現(xiàn)遞歸調(diào)用也是完全可行的。遞歸方法是眾多算法中替代循環(huán)的一個(gè)不錯(cuò)選擇。所有的遞歸方法都是可重入的,但是不是所有可重入的方法都是遞歸的。
棧遵守LIFO(Last In First Out)規(guī)則,因此遞歸調(diào)用方法能夠記住“調(diào)用者”并且知道此輪執(zhí)行結(jié)束之返回至當(dāng)初的被調(diào)用位置。遞歸利用系統(tǒng)棧來(lái)存儲(chǔ)方法調(diào)用的返回地址。 Java是一種基于棧設(shè)計(jì)的編程語(yǔ)言。
循環(huán)的方式可以達(dá)到目的,不必采用遞歸。但是在某些情況下采用遞歸方式則代碼會(huì)更加簡(jiǎn)短易讀。遞歸方法在循環(huán)樹(shù)結(jié)構(gòu)以及避免丑陋的嵌套循環(huán)的情況下是非常好用的。
常規(guī)遞歸方法(亦稱(chēng),頭遞歸)在上面演示了,這種方式會(huì)增加調(diào)用棧的大小。每次遞歸,其入口需要被記錄在棧中。方法返回之前需要給countA(input.substring(1)的結(jié)果加一個(gè)count。因此,最后需要做的事其實(shí)是加法運(yùn)算,而非遞歸本身。
在尾遞歸中,最后要做的是遞歸,加法運(yùn)算在之前就已經(jīng)完成了。棧調(diào)用減少帶來(lái)了內(nèi)存消耗減少并且程序的性能更好。如下代碼
public class TailRecursiveCall { public int countA(String input) { // exit condition – recursive calls must have an exit condition if (input == null || input.length() == 0) { return 0; } return countA(input, 0) ; } public int countA(String input, int count) { if (input.length() == 0) { return count; } // check first character of the input if (input.substring(0, 1).equals("A")) { count = count + 1; } // recursive call is the last call as the count is cumulative return countA(input.substring(1), count); } public static void main(String[] args) { System.out.println(new TailRecursiveCall().countA("AAA rating")); } }5. 關(guān)于ArrayList
ArrayList的大小是如何自動(dòng)增加的?你能分享一下你的代碼嗎?
使用ensureCapacity, 在進(jìn)行添加元素時(shí),檢查容量是否足夠,不夠的話,就將容量擴(kuò)大3/2,并將舊數(shù)組中的元素使用Arrays.copyOf拷貝到新數(shù)組中。
什么情況下你會(huì)使用ArrayList?什么時(shí)候你會(huì)選擇LinkedList?
ArrayList是在訪問(wèn)的次數(shù)遠(yuǎn)大于插入和刪除的次數(shù),使用ArrayList,因?yàn)锳rrayList底層使用數(shù)組,訪問(wèn)的復(fù)雜度為O(1), 但是插入和刪除就得頻繁使用System.arraycopy復(fù)制數(shù)組。 LinkList主要在訪問(wèn)次數(shù)遠(yuǎn)小于插入和刪除的次數(shù)時(shí)使用,其刪除和插入的復(fù)雜度,但訪問(wèn)元素時(shí)幾乎為O(n)。
當(dāng)傳遞ArrayList到某個(gè)方法中,或者某個(gè)方法返回ArrayList,什么時(shí)候要考慮安全隱患?如何修復(fù)安全違規(guī)這個(gè)問(wèn)題呢?
當(dāng)array被當(dāng)做參數(shù)傳遞到某個(gè)方法中,如果array在沒(méi)有被復(fù)制的情況下直接被分配給了成員變量,那么就可能發(fā)生這種情況,即當(dāng)原始的數(shù)組被調(diào)用的方法改變的時(shí)候,傳遞到這個(gè)方法中的數(shù)組也會(huì)改變。
將其副本拷貝出來(lái)再進(jìn)行修改。
如何復(fù)制某個(gè)ArrayList到另一個(gè)ArrayList中去?寫(xiě)出你的代碼?
使用clone()方法,比如ArrayList newArray = oldArray.clone();
使用ArrayList構(gòu)造方法,比如:ArrayList myObject = new ArrayList(myTempObject); 使用Collection的copy方法...
注意1和2是淺拷貝(shallow copy),何為淺拷貝?
淺拷貝就比如像引用類(lèi)型,而深拷貝就比如值類(lèi)型。淺拷貝是指源對(duì)象與拷貝對(duì)象共用一份實(shí)體,僅僅是引用的變量不同(名稱(chēng)不同)。對(duì)其中任何一個(gè)對(duì)象的改動(dòng)都會(huì)影響另外一個(gè)對(duì)象。舉個(gè)例子,一個(gè)人一開(kāi)始叫張三,后來(lái)改名叫李四了,可是還是同一個(gè)人,不管是張三缺胳膊少腿還是李四缺胳膊少腿,都是這個(gè)人倒霉。
深拷貝是指源對(duì)象與拷貝對(duì)象互相獨(dú)立,其中任何一個(gè)對(duì)象的改動(dòng)都不會(huì)對(duì)另外一個(gè)對(duì)象造成影響。舉個(gè)例子,一個(gè)人名叫張三,后來(lái)用他克隆(假設(shè)法律允許)了另外一個(gè)人,叫李四,不管是張三缺胳膊少腿還是李四缺胳膊少腿都不會(huì)影響另外一個(gè)人。比較典型的就是Value(值)對(duì)象,如預(yù)定義類(lèi)型Int32,Double,以及結(jié)構(gòu)(struct),枚舉(Enum)等。
還可用序列化技術(shù)來(lái)進(jìn)行深拷貝,對(duì)象實(shí)現(xiàn)序列化接口,然后寫(xiě)入流,并讀出來(lái)
// 將對(duì)象寫(xiě)到流里 ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(this); // 從流里讀出來(lái) ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); return (oi.readObject());
但是串行化卻很耗時(shí),在一些框架中,我們便可以感受到,它們往往將對(duì)象進(jìn)行串行化后進(jìn)行傳遞,耗時(shí)較多。
在索引中ArrayList的增加或者刪除某個(gè)對(duì)象的運(yùn)行過(guò)程?效率很低嗎?解釋一下為什么?
頻繁插入和刪除,會(huì)頻繁調(diào)用System.arrayCopy....效率低
參考地址
-[1] http://www.importnew.com/2228...
-[2] http://www.importnew.com/2223...
-[3] http://www.importnew.com/2217...
-[4] http://www.importnew.com/2329...
-[5] http://www.importnew.com/9928...
-[6] http://www.cnblogs.com/shuaiw...
-[7] http://blog.csdn.net/biaobiao...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/64144.html
摘要:網(wǎng)易跨境電商考拉海購(gòu)在線筆試現(xiàn)場(chǎng)技術(shù)面面。如何看待校招面試招聘,對(duì)公司而言,是尋找勞動(dòng)力對(duì)員工而言,是尋找未來(lái)的同事。 如何準(zhǔn)備校招技術(shù)面試 標(biāo)簽 : 面試 [TOC] 2017 年互聯(lián)網(wǎng)校招已近尾聲,作為一個(gè)非 CS 專(zhuān)業(yè)的應(yīng)屆生,零 ACM 經(jīng)驗(yàn)、零期刊論文發(fā)表,我通過(guò)自己的努力和準(zhǔn)備,從找實(shí)習(xí)到校招一路運(yùn)氣不錯(cuò),面試全部通過(guò),謹(jǐn)以此文記錄我的校招感悟。 寫(xiě)在前面 寫(xiě)作動(dòng)機(jī) ...
摘要:我覺(jué)得了解簡(jiǎn)歷和面試的技巧可以幫助你更好的去學(xué)習(xí)重要的知識(shí)點(diǎn)以及更好地去準(zhǔn)備面試以及面試,說(shuō)實(shí)話,我個(gè)人覺(jué)得這些東西還挺重要的。在本文里,我將介紹我這段時(shí)間里更新簡(jiǎn)歷和面試的相關(guān)經(jīng)歷。 分享一篇很不錯(cuò)的文章!本文作者曾經(jīng)寫(xiě)過(guò)《Java Web輕量級(jí)開(kāi)發(fā)面試教程》和 《Java核心技術(shù)及面試指南》這兩本書(shū)。我覺(jué)得了解簡(jiǎn)歷和面試的技巧可以幫助你更好的去學(xué)習(xí)重要的知識(shí)點(diǎn)以及更好地去準(zhǔn)備面試以...
摘要:第一個(gè)問(wèn)題阿里面試都問(wèn)什么這個(gè)是讓我最頭疼的一個(gè)問(wèn)題,也是群里的猿友們問(wèn)的最多的一個(gè)問(wèn)題。我參加的是阿里的社招面試,而社招不同于校招,問(wèn)題的范圍其實(shí)是很隨機(jī)的。所以,不妨就這兩個(gè)階段,談?wù)勆缯忻嬖嚨臏?zhǔn)備,而不是去把阿里面試的過(guò)程背一遍。 引言其實(shí)本來(lái)真的沒(méi)打算寫(xiě)這篇文章,主要是記憶力不是很好,不像一些記憶力強(qiáng)的人,面試完以后,幾乎能把自己和面試官的對(duì)話都給記下來(lái)。自己當(dāng)初面試完以后,除...
摘要:一基礎(chǔ)接口的意義百度規(guī)范擴(kuò)展回調(diào)抽象類(lèi)的意義想不想通過(guò)一線互聯(lián)網(wǎng)公司面試文檔整理為電子書(shū)掘金簡(jiǎn)介谷歌求職記我花了八個(gè)月準(zhǔn)備谷歌面試掘金原文鏈接翻譯者 【面試寶典】從對(duì)象深入分析 Java 中實(shí)例變量和類(lèi)變量的區(qū)別 - 掘金原創(chuàng)文章,轉(zhuǎn)載請(qǐng)務(wù)必保留原出處為:http://www.54tianzhisheng.cn/... , 歡迎訪問(wèn)我的站點(diǎn),閱讀更多有深度的文章。 實(shí)例變量 和 類(lèi)變量...
閱讀 1761·2021-09-22 15:25
閱讀 1318·2019-08-29 12:34
閱讀 1927·2019-08-26 13:57
閱讀 3202·2019-08-26 10:48
閱讀 1456·2019-08-26 10:45
閱讀 804·2019-08-23 18:23
閱讀 745·2019-08-23 18:01
閱讀 1959·2019-08-23 16:07