第一篇:Java軟件開發(fā)工程師面試題寶典
這套面試題主要目的是幫助那些還沒有java軟件開發(fā)實(shí)際工作經(jīng)驗(yàn),而正在努力尋找java軟件開發(fā)工作的朋友在筆試時(shí)更好地贏得筆試和面試。由于這套面試題涉及的范圍很泛,很廣,很雜,大家不可能一天兩天就看完和學(xué)完這套面試寶典,即使你已經(jīng)學(xué)過了有關(guān)的技術(shù),那么至少也需要一個(gè)月的時(shí)間才能消化和掌握這套面試寶典,所以,大家應(yīng)該早作準(zhǔn)備,從拿到這套面試寶典之日起,就要堅(jiān)持在每天閑暇之余學(xué)習(xí)其中幾道題目,日積月累,等到出去面試時(shí),一切都水到渠成,面試時(shí)就自然會游刃有余了。
答題時(shí),先答是什么,再答有什么作用和要注意什么(這部分最重要,展現(xiàn)自己的心得)
答案的段落分別,層次分明,條理清晰都非常重要,從這些表面的東西也可以看出一個(gè)人的習(xí)慣、辦事風(fēng)格、條理等。
要講你做出答案的思路過程,或者說你記住答案的思想都寫下來。把答題想著是辯論賽。答題就是給別人講道理、擺事實(shí)。答題不局限于什么格式和形式,就是要將自己的學(xué)識展現(xiàn)出來!
別因?yàn)槿思翌}目本來就模棱兩可,你就心里膽怯和沒底氣了,不敢回答了。你要大膽地指出對方題目很模糊和你的觀點(diǎn),不要把面試官想得有多高,其實(shí)他和你就是差不多的,你想想,如果他把你招進(jìn)去了,你們以后就是同事了,可不是差不多的嗎?
關(guān)于就業(yè)薪水,如果你是應(yīng)屆生,那不能要高工資,好比大餅的故事,沒有文憑還想拿高工資,就去中關(guān)村缺什么補(bǔ)什么吧!少數(shù)人基礎(chǔ)確實(shí)很好,在校期間確實(shí)又做過一些項(xiàng)目,那仍然是可以要到相對高的工資的。
1.Java基礎(chǔ)部分
基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語法,集合的語法,io 的語法,虛擬機(jī)方面的語法。
1、一個(gè)“.java”源文件中是否可以包括多個(gè)類(不是內(nèi)部類)?有什么限制?
可以有多個(gè)類,但只能有一個(gè)public的類,并且public的類名必須與文件名相一致。
2、Java有沒有g(shù)oto?
java中的保留字,現(xiàn)在沒有在java中使用。
3、說說&和&&的區(qū)別。
&和&&都可以用作邏輯與的運(yùn)算符,表示邏輯與(and),當(dāng)運(yùn)算符兩邊的表達(dá)式的結(jié)果都為true時(shí),整個(gè)運(yùn)算結(jié)果才為true,否則,只要有一方為false,則結(jié)果為false。
&&還具有短路的功能,即如果第一個(gè)表達(dá)式為false,則不再計(jì)算第二個(gè)表達(dá)式,例如,對于if(str!= null &&!str.equals(“”))表達(dá)式,當(dāng)str為null時(shí),后面的表達(dá)式不會執(zhí)行,所以不會出現(xiàn)NullPointerException如果將&&改為&,則會拋出NullPointerException異常。If(x==33 & ++y>0)y會增長,If(x==33 && ++y>0)不會增長
&還可以用作位運(yùn)算符,當(dāng)&操作符兩邊的表達(dá)式不是boolean類型時(shí),&表示按位與操作,我們通常使用0x0f來與一個(gè)整數(shù)進(jìn)行&運(yùn)算,來獲取該整數(shù)的最低4個(gè)bit位,例如,0x31 & 0x0f的結(jié)果為0x01。
備注:這道題先說兩者的共同點(diǎn),再說出&&和&的特殊之處,并列舉一些經(jīng)典的例子來表明自己理解透徹深入、實(shí)際經(jīng)驗(yàn)豐富。
4、在JAVA中如何跳出當(dāng)前的多重嵌套循環(huán)?
在Java中,要想跳出多重循環(huán),可以在外面的循環(huán)語句前定義一個(gè)標(biāo)號,然后在里層循環(huán)體的代碼中使用帶有標(biāo)號的break 語句,即可跳出外層循環(huán)。例如,ok: for(int i=0;i<10;i++){
}
另外,我個(gè)人通常并不使用標(biāo)號這種方式,而是讓外層的循環(huán)條件表達(dá)式的結(jié)果可以受到里層循環(huán)體代碼的控制,例如,要在二維數(shù)組中查找到某個(gè)數(shù)字。
int arr[][] = {{1,2,3},{4,5,6,7},{9}};boolean found = false;for(int i=0;i } for(int j=0;j } System.out.println(“i=” + i + “,j=” + j);if(arr[i][j] == 5){ } found = true;break;for(int j=0;j<10;j++) } if(j == 5)break ok; { System.out.println(“i=” + i + “,j=” + j); 5、switch語句能否作用在byte上,能否作用在long上,能否作用在String上? 在switch(expr1)中,expr1只能是一個(gè)整數(shù)表達(dá)式或者枚舉常量(更大字體),整數(shù)表達(dá)式可以是int基本類型或Integer包裝類型,由于,byte,short,char都可以隱含轉(zhuǎn)換為int,所以,這些類型以及這些類型的包裝類型也是可以的。顯然,long和String類型都不符合switch的語法規(guī)定,并且不能被隱式轉(zhuǎn)換成int類型,所以,它們不能作用于swtich語句中。 6、short s1 = 1;s1 = s1 + 1;有什么錯(cuò)? short s1 = 1;s1 += 1;有什么錯(cuò)? 對于short s1 = 1;s1 = s1 + 1;由于s1+1運(yùn)算時(shí)會自動(dòng)提升表達(dá)式的類型,所以結(jié)果是int型,再賦值給short類型s1時(shí),編譯器將報(bào)告需要強(qiáng)制轉(zhuǎn)換類型的錯(cuò)誤。 對于short s1 = 1;s1 += 1;由于 += 是java語言規(guī)定的運(yùn)算符,java編譯器會對它進(jìn)行特殊處理,因此可以正確編譯。 7、char型變量中能不能存貯一個(gè)中文漢字?為什么? char型變量是用來存儲Unicode編碼的字符的,unicode編碼字符集中包含了漢字,所以,char型變量中當(dāng)然可以存儲漢字啦。不過,如果某個(gè)特殊的漢字沒有被包含在unicode編碼字符集中,那么,這個(gè)char型變量中就不能存儲這個(gè)特殊漢字。補(bǔ)充說明:unicode編碼占用兩個(gè)字節(jié),所以,char類型的變量也是占用兩個(gè)字節(jié)。 備注:后面一部分回答雖然不是在正面回答題目,但是,為了展現(xiàn)自己的學(xué)識和表現(xiàn)自己對問題理解的透徹深入,可以回答一些相關(guān)的知識,做到知無不言,言無不盡。 8、用最有效率的方法算出2乘以8等於幾? << 3,因?yàn)閷⒁粋€(gè)數(shù)左移n位,就相當(dāng)于乘以了2的n次方,那么,一個(gè)數(shù)乘以8只要將其左移3位即可,而位運(yùn)算cpu直接支持的,效率最高,所以,2乘以8等於幾的最效率的方法是2 << 3。 9、請?jiān)O(shè)計(jì)一個(gè)一百億的計(jì)算器 首先要明白這道題目的考查點(diǎn)是什么,一是大家首先要對計(jì)算機(jī)原理的底層細(xì)節(jié)要清楚、要知道加減法的位運(yùn)算原理和知道計(jì)算機(jī)中的算術(shù)運(yùn)算會發(fā)生越界的情況,二是要具備一定的面向?qū)ο蟮脑O(shè)計(jì)思想。 首先,計(jì)算機(jī)中用固定數(shù)量的幾個(gè)字節(jié)來存儲的數(shù)值,所以計(jì)算機(jī)中能夠表示的數(shù)值是有一定的范圍的,為了便于講解和理解,我們先以byte 類型的整數(shù)為例,它用1個(gè)字節(jié)進(jìn)行存儲,表示的最大數(shù)值范圍為-128到+127。-1在內(nèi)存中對應(yīng)的二進(jìn)制數(shù)據(jù)為11111111,如果兩個(gè)-1相加,不考慮Java運(yùn)算時(shí)的類型提升,運(yùn)算后會產(chǎn)生進(jìn)位,二進(jìn)制結(jié)果為1,11111110,由于進(jìn)位后超過了byte類型的存儲空間,所以進(jìn)位部分被舍棄,即最終的結(jié)果為11111110,也就是-2,這正好利用溢位的方式實(shí)現(xiàn)了負(fù)數(shù)的運(yùn)算。-128在內(nèi)存中對應(yīng)的二進(jìn)制數(shù)據(jù)為10000000,如果兩個(gè)-128相加,不考慮Java運(yùn)算時(shí)的類型提升,運(yùn)算后會產(chǎn)生進(jìn)位,二進(jìn)制結(jié)果為1,00000000,由于進(jìn)位后超過了byte類型的存儲空間,所以進(jìn)位部分被舍棄,即最終的結(jié)果為00000000,也就是0,這樣的結(jié)果顯然不是我們期望的,這說明計(jì)算機(jī)中的算術(shù)運(yùn)算是會發(fā)生越界情況的,兩個(gè)數(shù)值的運(yùn)算結(jié)果不能超過計(jì)算機(jī)中的該類型的數(shù)值范圍。由于Java中涉及表達(dá)式運(yùn)算時(shí)的類型自動(dòng)提升,我們無法用byte類型來做演示這種問題和現(xiàn)象的實(shí)驗(yàn),大家可以用下面一個(gè)使用整數(shù)做實(shí)驗(yàn)的例子程序體驗(yàn)一下: int a = Integer.MAX_VALUE;int b = Integer.MAX_VALUE;int sum = a + b;System.out.println(“a=”+a+”,b=”+b+”,sum=”+sum);先不考慮long類型,由于int的正數(shù)范圍為2的31次方,表示的最大數(shù)值約等于2*1000*1000*1000,也就是20億的大小,所以,要實(shí)現(xiàn)一個(gè)一百億的計(jì)算器,我們得自己設(shè)計(jì)一個(gè)類可以用于表示很大的整數(shù),并且提供了與另外一個(gè)整數(shù)進(jìn)行加減乘除的功能,大概功能如下: ()這個(gè)類內(nèi)部有兩個(gè)成員變量,一個(gè)表示符號,另一個(gè)用字節(jié)數(shù)組表示數(shù)值的二進(jìn)制數(shù)()有一個(gè)構(gòu)造方法,把一個(gè)包含有多位數(shù)值的字符串轉(zhuǎn)換到內(nèi)部的符號和字節(jié)數(shù)組中()提供加減乘除的功能 public class BigInteger{ } 備注:要想寫出這個(gè)類的完整代碼,是非常復(fù)雜的,如果有興趣的話,可以參看jdk中自帶的java.math.BigInteger類的源碼。面試的人也知道誰都不可能在短時(shí)間內(nèi)寫出這個(gè)類的完整代碼的,他要的是你是否有這方面的概念和意識,他最重要的還是考查你的能力,所以,你不要因?yàn)樽约簾o法寫出完整的最終結(jié)果就放棄答這道題,你要做的就是你比別人寫得多,證明你比別人強(qiáng),你有這方面的思想意識就可以了,畢竟別人可能連題目的意思都看不懂,什么都沒寫,你要敢于答這道題,即使只答了一部分,那也與那些什么都不懂的人區(qū)別出來,拉開了距離,算是矮子中的高個(gè),機(jī)會當(dāng)然就屬于你了。另外,答案中的框架代碼也很重要,體現(xiàn)了一些面向?qū)ο笤O(shè)計(jì)的功底,特別是其中的方法命名很專業(yè),用的英文單詞很精準(zhǔn),這也是能力、經(jīng)驗(yàn)、專業(yè)性、英語水平等多個(gè)方面的體現(xiàn),會給人留下很好的印象,在編程能力和其他方面條件差不多的情況下,英語好除了可以使你獲得更多機(jī)會外,薪水可以高出一千元。 int sign;byte[] val;public Biginteger(String val){ } public BigInteger add(BigInteger other){ } public BigInteger subtract(BigInteger other){ } public BigInteger multiply(BigInteger other){ } public BigInteger divide(BigInteger other){ } sign =;val =; 10、使用final關(guān)鍵字修飾一個(gè)變量時(shí),是引用不能變,還是引用的對象不能變? 使用final關(guān)鍵字修飾一個(gè)變量時(shí),是指引用變量不能變,引用變量所指向的對象中的內(nèi)容還是可以改變的。例如,對于如下語句: final StringBuffer a=new StringBuffer(“immutable”);執(zhí)行如下語句將報(bào)告編譯期錯(cuò)誤: a=new StringBuffer(“");但是,執(zhí)行如下語句則可以通過編譯: a.append(” broken!“); 有人在定義方法的參數(shù)時(shí),可能想采用如下形式來阻止方法內(nèi)部修改傳進(jìn)來的參數(shù)對象: public void method(final StringBuffer param){ } 實(shí)際上,這是辦不到的,在該方法內(nèi)部仍然可以增加如下代碼來修改參數(shù)對象: param.append(”a“); 11、”==“和equals方法究竟有什么區(qū)別? (單獨(dú)把一個(gè)東西說清楚,然后再說清楚另一個(gè),這樣,它們的區(qū)別自然就出來了,混在一起說,則很難說清楚) ==操作符專門用來比較兩個(gè)變量的值是否相等,也就是用于比較變量所對應(yīng)的內(nèi)存中所存儲的數(shù)值是否相同,要比較兩個(gè)基本類型的數(shù)據(jù)或兩個(gè)引用變量是否相等,只能用==操作符。 如果一個(gè)變量指向的數(shù)據(jù)是對象類型的,那么,這時(shí)候涉及了兩塊內(nèi)存,對象本身占用一塊內(nèi)存(堆內(nèi)存),變量也占用一塊內(nèi)存,例如Objet obj = new Object();變量obj是一個(gè)內(nèi)存,new Object()是另一個(gè)內(nèi)存,此時(shí),變量obj所對應(yīng)的內(nèi)存中存儲的數(shù)值就是對象占用的那塊內(nèi)存的首地址。對于指向?qū)ο箢愋偷淖兞?,如果要比較兩個(gè)變量是否指向同一個(gè)對象,即要看這兩個(gè)變量所對應(yīng)的內(nèi)存中的數(shù)值是否相等,這時(shí)候就需要用==操作符進(jìn)行比較。 equals方法是用于比較兩個(gè)獨(dú)立對象的內(nèi)容是否相同,就好比去比較兩個(gè)人的長相是否相同,它比較的兩個(gè)對象是獨(dú)立的。例如,對于下面的代碼: String a=new String(”foo“);String b=new String(”foo“);兩條new語句創(chuàng)建了兩個(gè)對象,然后用a,b這兩個(gè)變量分別指向了其中一個(gè)對象,這是兩個(gè)不同的對象,它們的首地址是不同的,即a和b中存儲的數(shù)值是不相同的,所以,表達(dá)式a==b將返回false,而這兩個(gè)對象中的內(nèi)容是相同的,所以,表達(dá)式a.equals(b)將返回true。 在實(shí)際開發(fā)中,我們經(jīng)常要比較傳遞進(jìn)行來的字符串內(nèi)容是否等,例如,String input = …;input.equals(“quit”),許多人稍不注意就使用==進(jìn)行比較了,這是錯(cuò)誤的,隨便從網(wǎng)上找?guī)讉€(gè)項(xiàng)目實(shí)戰(zhàn)的教學(xué)視頻看看,里面就有大量這樣的錯(cuò)誤。記住,字符串的比較基本上都是使用equals方法。 如果一個(gè)類沒有自己定義equals方法,那么它將繼承Object類的equals方法,Object類的equals方法的實(shí)現(xiàn)代碼如下: boolean equals(Object o){ return this==o;} 這說明,如果一個(gè)類沒有自己定義equals方法,它默認(rèn)的equals方法(從Object 類繼承的)就是使用==操作符,也是在比較兩個(gè)變量指向的對象是否是同一對象,這時(shí)候使用equals和使用==會得到同樣的結(jié)果,如果比較的是兩個(gè)獨(dú)立的對象則總返回false。如果你編寫的類希望能夠比較該類創(chuàng)建的兩個(gè)實(shí)例對象的內(nèi)容是否相同,那么你必須覆蓋equals方法,由你自己寫代碼來決定在什么情況即可認(rèn)為兩個(gè)對象的內(nèi)容是相同的。 12、靜態(tài)變量和實(shí)例變量的區(qū)別? 在語法定義上的區(qū)別:靜態(tài)變量前要加static關(guān)鍵字,而實(shí)例變量前則不加。 在程序運(yùn)行時(shí)的區(qū)別:實(shí)例變量屬于某個(gè)對象的屬性,必須創(chuàng)建了實(shí)例對象,其中的實(shí)例變量才會被分配空間,才能使用這個(gè)實(shí)例變量。靜態(tài)變量不屬于某個(gè)實(shí)例對象,而是屬于類,所以也稱為類變量,只要程序加載了類的字節(jié)碼,不用創(chuàng)建任何實(shí)例對象,靜態(tài)變量就會被分配空間,靜態(tài)變量就可以被使用了??傊?,實(shí)例變量必須創(chuàng)建對象后才可以通過這個(gè)對象來使用,靜態(tài)變量則可以直接使用類名來引用。 例如,對于下面的程序,無論創(chuàng)建多少個(gè)實(shí)例對象,永遠(yuǎn)都只分配了一個(gè)staticVar變量,并且每創(chuàng)建一個(gè)實(shí)例對象,這個(gè)staticVar就會加1;但是,每創(chuàng)建一個(gè)實(shí)例對象,就會分配一個(gè)instanceVar,即可能分配多個(gè)instanceVar,并且每個(gè)instanceVar的值都只自加了1次。 public class VariantTest{ } 備注:這個(gè)解答除了說清楚兩者的區(qū)別外,最后還用一個(gè)具體的應(yīng)用例子來說明兩者的差異,體現(xiàn)了自己有很好的解說問題和設(shè)計(jì)案例的能力,思維敏捷,超過一般程序員,有寫作能力!public static int staticVar = 0;public int instanceVar = 0;public VariantTest(){ } staticVar++;instanceVar++;System.out.println(“staticVar=” + staticVar + ”,instanceVar=” + instanceVar); 13、是否可以從一個(gè)static方法內(nèi)部發(fā)出對非static方法的調(diào)用? 不可以。因?yàn)榉莝tatic方法是要與對象關(guān)聯(lián)在一起的,必須創(chuàng)建一個(gè)對象后,才可以在該對象上進(jìn)行方法調(diào)用,而static方法調(diào)用時(shí)不需要?jiǎng)?chuàng)建對象,可以直接調(diào)用。也就是說,當(dāng)一個(gè)static方法被調(diào)用時(shí),可能還沒有創(chuàng)建任何實(shí)例對象,如果從一個(gè)static方法中發(fā)出對非static方法的調(diào)用,那個(gè)非static方法是關(guān)聯(lián)到哪個(gè)對象上的呢?這個(gè)邏輯無法成立,所以,一個(gè)static方法內(nèi)部發(fā)出對非static方法的調(diào)用。 14、Integer與int的區(qū)別 int是java提供的8種原始數(shù)據(jù)類型之一。Java為每個(gè)原始類型提供了封裝類,Integer是java為int提供的封裝類。int的默認(rèn)值為0,而Integer的默認(rèn)值為null,即Integer可以區(qū)分出未賦值和值為0的區(qū)別,int則無法表達(dá)出未賦值的情況,例如,要想表達(dá)出沒有參加考試和考試成績?yōu)?的區(qū)別,則只能使用Integer。在JSP開發(fā)中,Integer的默認(rèn)為null,所以用el表達(dá)式在文本框中顯示時(shí),值為空白字符串,而int默認(rèn)的默認(rèn)值為0,所以用el表達(dá)式在文本框中顯示時(shí),結(jié)果為0,所以,int不適合作為web層的表單數(shù)據(jù)的類型。 在Hibernate中,如果將OID定義為Integer類型,那么Hibernate就可以根據(jù)其值是否為null而判斷一個(gè)對象是否是臨時(shí)的,如果將OID定義為了int類型,還需要在hbm映射文件中設(shè)置其unsaved-value屬性為0。 另外,Integer提供了多個(gè)與整數(shù)相關(guān)的操作方法,例如,將一個(gè)字符串轉(zhuǎn)換成整數(shù),Integer中還定義了表示整數(shù)的最大值和最小值的常量。 15、Math.round(11.5)等於多少? Math.round(-11.5)等於多少? Math類中提供了三個(gè)與取整有關(guān)的方法:ceil、floor、round,這些方法的作用與它們的英文名稱的含義相對應(yīng),例如,ceil的英文意義是天花板,該方法就表示向上取整,Math.ceil(11.3)的結(jié)果為12,Math.ceil(-11.3)的結(jié)果是-11;floor的英文意義是地板,該方法就表示向下取整,Math.ceil(11.6)的結(jié)果為11,Math.ceil(-11.6)的結(jié)果是-12;最難掌握的是round方法,它表示“四舍五入”,算法為Math.floor(x+0.5),即將原來的數(shù)字加上0.5后再向下取整,所以,Math.round(11.5)的結(jié)果為12,Math.round(-11.5)的結(jié)果為-11。 16、下面的代碼有什么不妥之處? 1.if(username.equals(“zxx”){} 2.int x = 1; return x==1?true:false; 17、請說出作用域public,private,protected,以及不寫時(shí)的區(qū)別 這四個(gè)作用域的可見范圍如下表所示。 說明:如果在修飾的元素上面沒有寫任何訪問修飾符,則表示friendly。 作用域 當(dāng)前類 同一package 子孫類 其他package public √ √ √ √ protected √ √ √ × friendly √ √ × × private √ × × × 備注:只要記住了有4種訪問權(quán)限,4個(gè)訪問范圍,然后將全選和范圍在水平和垂直方向上分別按排從小到大或從大到小的順序排列,就很容易畫出上面的圖了。 18、Overload和Override的區(qū)別。Overloaded的方法是否可以改變返回值的類型? Overload是重載的意思,Override是覆蓋的意思,也就是重寫。 重載Overload表示同一個(gè)類中可以有多個(gè)名稱相同的方法,但這些方法的參數(shù)列表各不相同(即參數(shù)個(gè)數(shù)或類型不同)。 重寫Override表示子類中的方法可以與父類中的某個(gè)方法的名稱和參數(shù)完全相同,通過子類創(chuàng)建的實(shí)例對象調(diào)用這個(gè)方法時(shí),將調(diào)用子類中的定義方法,這相當(dāng)于把父類中定義的那個(gè)完全相同的方法給覆蓋了,這也是面向?qū)ο缶幊痰亩鄳B(tài)性的一種表現(xiàn)。子類覆蓋父類的方法時(shí),只能比父類拋出更少的異常,或者是拋出父類拋出的異常的子異常,因?yàn)樽宇惪梢越鉀Q父類的一些問題,不能比父類有更多的問題。子類方法的訪問權(quán)限只能比父類的更大,不能更小。如果父類的方法是private類型,那么,子類則不存在覆蓋的限制,相當(dāng)于子類中增加了一個(gè)全新的方法。 至于Overloaded的方法是否可以改變返回值的類型這個(gè)問題,要看你倒底想問什么呢?這個(gè)題目很模糊。如果幾個(gè)Overloaded的方法的參數(shù)列表不一樣,它們的返回者類型當(dāng)然也可以不一樣。但我估計(jì)你想問的問題是:如果兩個(gè)方法的參數(shù)列表完全一樣,是否可以讓它們的返回值不同來實(shí)現(xiàn)重載Overload。這是不行的,我們可以用反證法來說明這個(gè)問題,因?yàn)槲覀冇袝r(shí)候調(diào)用一個(gè)方法時(shí)也可以不定義返回結(jié)果變量,即不要關(guān)心其返回結(jié)果,例如,我們調(diào)用map.remove(key)方法時(shí),雖然remove方法有返回值,但是我們通常都不會定義接收返回結(jié)果的變量,這時(shí)候假設(shè)該類中有兩個(gè)名稱和參數(shù)列表完全相同的方法,僅僅是返回類型不同,java就無法確定編程者倒底是想調(diào)用哪個(gè)方法了,因?yàn)樗鼰o法通過返回結(jié)果類型來判斷。 override可以翻譯為覆蓋,從字面就可以知道,它是覆蓋了一個(gè)方法并且對其重寫,以求達(dá)到不同的作用。對我們來說最熟悉的覆蓋就是對接口方法的實(shí)現(xiàn),在接口中一般只是對方法進(jìn)行了聲明,而我們在實(shí)現(xiàn)時(shí),就需要實(shí)現(xiàn)接口聲明的所有方法。除了這個(gè)典型的用法以外,我們在繼承中也可能會在子類覆蓋父類中的方法。在覆蓋要注意以下的幾點(diǎn): 1、覆蓋的方法的標(biāo)志必須要和被覆蓋的方法的標(biāo)志完全匹配,才能達(dá)到覆蓋的效果; 2、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致; 3、覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類; 4、被覆蓋的方法不能為private,否則在其子類中只是新定義了一個(gè)方法,并沒有對其進(jìn)行覆蓋。 overload對我們來說可能比較熟悉,可以翻譯為重載,它是指我們可以定義一些名稱相同的方法,通過定義不同的輸入?yún)?shù)來區(qū)分這些方法,然后再調(diào)用時(shí),VM就會根據(jù)不同的參數(shù)樣式,來選擇合適的方法執(zhí)行。在使用重載要注意以下的幾點(diǎn): 1、在使用重載時(shí)只能通過不同的參數(shù)樣式。例如,不同的參數(shù)類型,不同的參數(shù)個(gè)數(shù),不同的參數(shù)順序(當(dāng)然,同一方法內(nèi)的幾個(gè)參數(shù)類型必須不一樣,例如可以是fun(int,float),但是不能為fun(int,int)); 2、不能通過訪問權(quán)限、返回類型、拋出的異常進(jìn)行重載; 3、方法的異常類型和數(shù)目不會對重載造成影響; 4、對于繼承來說,如果某一方法在父類中是訪問權(quán)限是priavte,那么就不能在子類對其進(jìn)行重載,如果定義的話,也只是定義了一個(gè)新方法,而不會達(dá)到重載的效果。 19、構(gòu)造器Constructor是否可被override? 構(gòu)造器Constructor不能被繼承,因此不能重寫Override,但可以被重載Overload。 20、接口是否可繼承接口? 抽象類是否可實(shí)現(xiàn)(implements)接口? 抽象類是否可繼承具體類(concrete class)? 抽象類中是否可以有靜態(tài)的main方法? 接口可以繼承接口。抽象類可以實(shí)現(xiàn)(implements)接口,抽象類是否可繼承具體類。抽象類中可以有靜態(tài)的main方法。 備注:只要明白了接口和抽象類的本質(zhì)和作用,這些問題都很好回答,你想想,如果你是java語言的設(shè)計(jì)者,你是否會提供這樣的支持,如果不提供的話,有什么理由嗎?如果你沒有道理不提供,那答案就是肯定的了。 只有記住抽象類與普通類的唯一區(qū)別就是不能創(chuàng)建實(shí)例對象和允許有abstract方法。 21、寫clone()方法時(shí),通常都有一行代碼,是什么? clone 有缺省行為,super.clone();因?yàn)槭紫纫迅割愔械某蓡T復(fù)制到位,然后才是復(fù)制自己的成員。 22、面向?qū)ο蟮奶卣饔心男┓矫?/p> 計(jì)算機(jī)軟件系統(tǒng)是現(xiàn)實(shí)生活中的業(yè)務(wù)在計(jì)算機(jī)中的映射,而現(xiàn)實(shí)生活中的業(yè)務(wù)其實(shí)就是一個(gè)個(gè)對象協(xié)作的過程。面向?qū)ο缶幊叹褪前船F(xiàn)實(shí)業(yè)務(wù)一樣的方式將程序代碼按一個(gè)個(gè)對象進(jìn)行組織和編寫,讓計(jì)算機(jī)系統(tǒng)能夠識別和理解用對象方式組織和編寫的程序代碼,這樣就可以把現(xiàn)實(shí)生活中的業(yè)務(wù)對象映射到計(jì)算機(jī)系統(tǒng)中。 面向?qū)ο蟮木幊陶Z言有封裝、繼承、抽象、多態(tài)等4個(gè)主要的特征。1封裝: 封裝是保證軟件部件具有優(yōu)良的模塊性的基礎(chǔ),封裝的目標(biāo)就是要實(shí)現(xiàn)軟件部件的“高內(nèi)聚、低耦合”,防止程序相互依賴性而帶來的變動(dòng)影響。在面向?qū)ο蟮木幊陶Z言中,對象是封裝的最基本單位,面向?qū)ο蟮姆庋b比傳統(tǒng)語言的封裝更為清晰、更為有力。面向?qū)ο蟮姆庋b就是把描述一個(gè)對象的屬性和行為的代碼封裝在一個(gè)“模塊”中,也就是一個(gè)類中,屬性用變量定義,行為用方法進(jìn)行定義,方法可以直接訪問同一個(gè)對象中的屬性。通常情況下,只要記住讓變量和訪問這個(gè)變量的方法放在一起,將一個(gè)類中的成員變量全部定義成私有的,只有這個(gè)類自己的方法才可以訪問到這些成員變量,這就基本上實(shí)現(xiàn)對象的封裝,就很容易找出要分配到這個(gè)類上的方法了,就基本上算是會面向?qū)ο蟮木幊塘?。把握一個(gè)原則:把對同一事物進(jìn)行操作的方法和相關(guān)的方法放在同一個(gè)類中,把方法和它操作的數(shù)據(jù)放在同一個(gè)類中。 例如,人要在黑板上畫圓,這一共涉及三個(gè)對象:人、黑板、圓,畫圓的方法要分配給哪個(gè)對象呢?由于畫圓需要使用到圓心和半徑,圓心和半徑顯然是圓的屬性,如果將它們在類中定義成了私有的成員變量,那么,畫圓的方法必須分配給圓,它才能訪問到圓心和半徑這兩個(gè)屬性,人以后只是調(diào)用圓的畫圓方法、表示給圓發(fā)給消息而已,畫圓這個(gè)方法不應(yīng)該分配在人這個(gè)對象上,這就是面向?qū)ο蟮姆庋b性,即將對象封裝成一個(gè)高度自治和相對封閉的個(gè)體,對象狀態(tài)(屬性)由這個(gè)對象自己的行為(方法)來讀取和改變。一個(gè)更便于理解的例子就是,司機(jī)將火車剎住了,剎車的動(dòng)作是分配給司機(jī),還是分配給火車,顯然,應(yīng)該分配給火車,因?yàn)樗緳C(jī)自身是不可能有那么大的力氣將一個(gè)火車給停下來的,只有火車自己才能完成這一動(dòng)作,火車需要調(diào)用內(nèi)部的離合器和剎車片等多個(gè)器件協(xié)作才能完成剎車這個(gè)動(dòng)作,司機(jī)剎車的過程只是給火車發(fā)了一個(gè)消息,通知火車要執(zhí)行剎車動(dòng)作而已。 抽象: 抽象就是找出一些事物的相似和共性之處,然后將這些事物歸為一個(gè)類,這個(gè)類只考慮這些事物的相似和共性之處,并且會忽略與當(dāng)前主題和目標(biāo)無關(guān)的那些方面,將注意力集中在與當(dāng)前目標(biāo)有關(guān)的方面。例如,看到一只螞蟻和大象,你能夠想象出它們的相同之處,那就是抽象。抽象包括行為抽象和狀態(tài)抽象兩個(gè)方面。例如,定義一個(gè)Person類,如下: class Person{ } 人本來是很復(fù)雜的事物,有很多方面,但因?yàn)楫?dāng)前系統(tǒng)只需要了解人的姓名和年齡,所以上面定義的類中只包含姓名和年齡這兩個(gè)屬性,這就是一種抽像,使用抽象可以避免考慮一些與目標(biāo)無關(guān)的細(xì)節(jié)。我對抽象的理解就是不要用顯微鏡去看一個(gè)事物的所有方面,這樣涉及的內(nèi)容就太多了,而是要善于劃分問題的邊界,當(dāng)前系統(tǒng)需要什么,就只考慮什么。 String name;int age;繼承: 在定義和實(shí)現(xiàn)一個(gè)類的時(shí)候,可以在一個(gè)已經(jīng)存在的類的基礎(chǔ)之上來進(jìn)行,把這個(gè)已經(jīng)存在的類所定義的內(nèi)容作為自己的內(nèi)容,并可以加入若干新的內(nèi)容,或修改原來的方法使之更適合特殊的需要,這就是繼承。繼承是子類自動(dòng)共享父類數(shù)據(jù)和方法的機(jī)制,這是類之間的一種關(guān)系,提高了軟件的可重用性和可擴(kuò)展性。 多態(tài): 多態(tài)是指程序中定義的引用變量所指向的具體類型和通過該引用變量發(fā)出的方法調(diào)用在編程時(shí)并不確定,而是在程序運(yùn)行期間才確定,即一個(gè)引用變量倒底會指向哪個(gè)類的實(shí)例對象,該引用變量發(fā)出的方法調(diào)用到底是哪個(gè)類中實(shí)現(xiàn)的方法,必須在由程序運(yùn)行期間才能決定。因?yàn)樵诔绦蜻\(yùn)行時(shí)才確定具體的類,這樣,不用修改源程序代碼,就可以讓引用變量綁定到各種不同的類實(shí)現(xiàn)上,從而導(dǎo)致該引用調(diào)用的具體方法隨之改變,即不修改程序代碼就可以改變程序運(yùn)行時(shí)所綁定的具體代碼,讓程序可以選擇多個(gè)運(yùn)行狀態(tài),這就是多態(tài)性。多態(tài)性增強(qiáng)了軟件的靈活性和擴(kuò)展性。例如,下面代碼中的UserDao是一個(gè)接口,它定義引用變量userDao指向的實(shí)例對象由daofactory.getDao()在執(zhí)行的時(shí)候返回,有時(shí)候指向的是UserJdbcDao這個(gè)實(shí)現(xiàn),有時(shí)候指向的是UserHibernateDao這個(gè)實(shí)現(xiàn),這樣,不用修改源代碼,就可以改變userDao指向的具體類實(shí)現(xiàn),從而導(dǎo)致userDao.insertUser()方法調(diào)用的具體代碼也隨之改變,即有時(shí)候調(diào)用的是UserJdbcDao的insertUser方法,有時(shí)候調(diào)用的是UserHibernateDao的insertUser方法: UserDao userDao = daofactory.getDao(); userDao.insertUser(user); 比喻:人吃飯,你看到的是左手,還是右手? 23、java中實(shí)現(xiàn)多態(tài)的機(jī)制是什么? 靠的是父類或接口定義的引用變量可以指向子類或具體實(shí)現(xiàn)類的實(shí)例對象,而程序調(diào)用的方法在運(yùn)行期才動(dòng)態(tài)綁定,就是引用變量所指向的具體實(shí)例對象的方法,也就是內(nèi)存里正在運(yùn)行的那個(gè)對象的方法,而不是引用變量的類型中定義的方法。 24、abstract class和interface有什么區(qū)別? 含有abstract修飾符的class即為抽象類,abstract 類不能創(chuàng)建的實(shí)例對象。含有abstract方法的類必須定義為abstract class,abstract class類中的方法不必是抽象的。abstract class類中定義抽象方法必須在具體(Concrete)子類中實(shí)現(xiàn),所以,不能有抽象構(gòu)造方法或抽象靜態(tài)方法。如果的子類沒有實(shí)現(xiàn)抽象父類中的所有抽象方法,那么子類也必須定義為abstract類型。 接口(interface)可以說成是抽象類的一種特例,接口中的所有方法都必須是抽象的。接口中的方法定義默認(rèn)為public abstract類型,接口中的成員變量類型默認(rèn)為public static final。 下面比較一下兩者的語法區(qū)別: 1.抽象類可以有構(gòu)造方法,接口中不能有構(gòu)造方法。2.抽象類中可以有普通成員變量,接口中沒有普通成員變量 3.抽象類中可以包含非抽象的普通方法,接口中的所有方法必須都是抽象的,不能有非抽象的普通方法。 4.抽象類中的抽象方法的訪問類型可以是public,protected和(默認(rèn)類型,雖然 eclipse下不報(bào)錯(cuò),但應(yīng)該也不行),但接口中的抽象方法只能是public類型的,并且默認(rèn)即為public abstract類型。 5.抽象類中可以包含靜態(tài)方法,接口中不能包含靜態(tài)方法 6.抽象類和接口中都可以包含靜態(tài)成員變量,抽象類中的靜態(tài)成員變量的訪問類型可以任意,但接口中定義的變量只能是public static final類型,并且默認(rèn)即為public static final類型。7.一個(gè)類可以實(shí)現(xiàn)多個(gè)接口,但只能繼承一個(gè)抽象類。下面接著再說說兩者在應(yīng)用上的區(qū)別: 接口更多的是在系統(tǒng)架構(gòu)設(shè)計(jì)方法發(fā)揮作用,主要用于定義模塊之間的通信契約。而抽象類在代碼實(shí)現(xiàn)方面發(fā)揮作用,可以實(shí)現(xiàn)代碼的重用,例如,模板方法設(shè)計(jì)模式是抽象類的一個(gè)典型應(yīng)用,假設(shè)某個(gè)項(xiàng)目的所有Servlet類都要用相同的方式進(jìn)行權(quán)限判斷、記錄訪問日志和處理異常,那么就可以定義一個(gè)抽象的基類,讓所有的Servlet都繼承這個(gè)抽象基類,在抽象基類的service方法中完成權(quán)限判斷、記錄訪問日志和處理異常的代碼,在各個(gè)子類中只是完成各自的業(yè)務(wù)邏輯代碼,偽代碼如下: public abstract class BaseServlet extends HttpServlet{ public final void service(HttpServletRequest request, HttpServletResponse response)throws { 記錄訪問日志 進(jìn)行權(quán)限判斷 if(具有權(quán)限){ try{ } catch(Excetpion e) { 記錄異常信息 doService(request,response);IOExcetion,ServletException } } } protected abstract void doService(HttpServletRequest request, HttpServletResponse response)throws IOExcetion,ServletException; //注意訪問權(quán)限定義成protected,顯得既專業(yè),又嚴(yán)謹(jǐn),因?yàn)樗菍iT給子類用的 } public class MyServlet1 extends BaseServlet { protected void doService(HttpServletRequest request, HttpServletResponse response)throws IOExcetion,ServletException } 父類方法中間的某段代碼不確定,留給子類干,就用模板方法設(shè)計(jì)模式。 備注:這道題的思路是先從總體解釋抽象類和接口的基本概念,然后再比較兩者的語法細(xì)節(jié),最后再說兩者的應(yīng)用區(qū)別。比較兩者語法細(xì)節(jié)區(qū)別的條理是:先從一個(gè)類中的構(gòu)造方法、普通成員變量和方法(包括抽象方法),靜態(tài)變量和方法,繼承性等6個(gè)方面逐一去比較回答,接著從第三者繼承的角度的回答,特別是最后用了一個(gè)典型的例子來展現(xiàn)自己深厚的技術(shù)功底。{ } 本Servlet只處理的具體業(yè)務(wù)邏輯代碼 25、abstract的method是否可同時(shí)是static,是否可同時(shí)是native,是否可同時(shí)是synchronized? abstract的method 不可以是static的,因?yàn)槌橄蟮姆椒ㄊ且蛔宇悓?shí)現(xiàn)的,而static與子類扯不上關(guān)系!native方法表示該方法要用另外一種依賴平臺的編程語言實(shí)現(xiàn)的,不存在著被子類實(shí)現(xiàn)的問題,所以,它也不能是抽象的,不能與abstract混用。例如,F(xiàn)ileOutputSteam類要硬件打交道,底層的實(shí)現(xiàn)用的是操作系統(tǒng)相關(guān)的api實(shí)現(xiàn),例如,在windows用c語言實(shí)現(xiàn)的,所以,查看jdk 的源代碼,可以發(fā)現(xiàn)FileOutputStream的open方法的定義如下: private native void open(String name)throws FileNotFoundException;如果我們要用java調(diào)用別人寫的c語言函數(shù),我們是無法直接調(diào)用的,我們需要按照java的要求寫一個(gè)c語言的函數(shù),又我們的這個(gè)c語言函數(shù)去調(diào)用別人的c語言函數(shù)。由于我們的c語言函數(shù)是按java的要求來寫的,我們這個(gè)c語言函數(shù)就可以與java對接上,java那邊的對接方式就是定義出與我們這個(gè)c函數(shù)相對應(yīng)的方法,java中對應(yīng)的方法不需要寫具體的代碼,但需要在前面聲明native。 關(guān)于synchronized與abstract合用的問題,我覺得也不行,因?yàn)樵谖規(guī)啄甑膶W(xué)習(xí)和開發(fā)中,從來沒見到過這種情況,并且我覺得synchronized應(yīng)該是作用在一個(gè)具體的方法上才有意義。而且,方法上的synchronized同步所使用的同步鎖對象是this,而抽象方法上無法確定this是什么。 26、什么是內(nèi)部類?Static Nested Class 和 Inner Class的不同。 內(nèi)部類就是在一個(gè)類的內(nèi)部定義的類,內(nèi)部類中不能定義靜態(tài)成員(靜態(tài)成員不是對象的特性,只是為了找一個(gè)容身之處,所以需要放到一個(gè)類中而已,這么一點(diǎn)小事,你還要把它放到類內(nèi)部的一個(gè)類中,過分了啊!提供內(nèi)部類,不是為讓你干這種事情,無聊,不讓你干。我想可能是既然靜態(tài)成員類似c語言的全局變量,而內(nèi)部類通常是用于創(chuàng)建內(nèi)部對象用的,所以,把“全局變量”放在內(nèi)部類中就是毫無意義的事情,既然是毫無意義的事情,就應(yīng)該被禁止),內(nèi)部類可以直接訪問外部類中的成員變量,內(nèi)部類可以定義在外部類的方法外面,也可以定義在外部類的方法體中,如下所示: public class Outer { } 在方法體外面定義的內(nèi)部類的訪問類型可以是public,protecte,默認(rèn)的,private等4種類型,這就好像類中定義的成員變量有4種訪問類型一樣,它們決定這個(gè)內(nèi)部類的定義對其他類是否可見;對于這種情況,我們也可以在外面創(chuàng)建內(nèi)部類的實(shí)例對象,創(chuàng)建內(nèi)部類的實(shí)例對象時(shí),一定要先創(chuàng)建外部類的實(shí)例對象,然后用這個(gè)外部類的實(shí)例對象去創(chuàng)建內(nèi)部類的實(shí)例對象,代碼如下: Outer outer = new Outer();Outer.Inner1 inner1 = outer.new Innner1(); 在方法內(nèi)部定義的內(nèi)部類前面不能有訪問類型修飾符,就好像方法中定義的局部變量一樣,但這種內(nèi)部類的前面可以使用final或abstract修飾符。這種內(nèi)部類對其他類是不可見的其他類無法引用這種內(nèi)部類,但是這種內(nèi)部類創(chuàng)建的實(shí)例對象可以傳遞給其他類訪問。這種內(nèi)部類必須是先定義,后使用,即內(nèi)部類的定義代碼必須出現(xiàn)在使用該類之前,這與方法中的局部變量必須先定義后使用的道理也是一樣的。這種內(nèi)部類可以訪問方法體中的局部變量,但是,該局部變量前必須加final修飾符。 對于這些細(xì)節(jié),只要在eclipse寫代碼試試,根據(jù)開發(fā)工具提示的各類錯(cuò)誤信息就可以馬上了解到。public class Inner1 //在方法體外面定義的內(nèi)部類 { } int out_x = 0;public void method(){ } Inner1 inner1 = new Inner1();public class Inner2 //在方法體內(nèi)部定義的內(nèi)部類 { } Inner2 inner2 = new Inner2();public method(){ } out_x = 3; 在方法體內(nèi)部還可以采用如下語法來創(chuàng)建一種匿名內(nèi)部類,即定義某一接口或類的子類的同時(shí),還創(chuàng)建了該子類的實(shí)例對象,無需為該子類定義名稱: public class Outer { public void start(){ new Thread(new Runable(){ }).start();} 最后,在方法外部定義的內(nèi)部類前面可以加上static關(guān)鍵字,從而成為Static Nested Class,它不再具有內(nèi)部類的特性,所有,從狹義上講,它不是內(nèi)部類。Static Nested Class與普通類在運(yùn)行時(shí)的行為和功能上沒有什么區(qū)別,只是在編程引用時(shí)的語法上有一些差別,它可以定義成public、protected、默認(rèn)的、private等多種類型,而普通類只能定義成public和默認(rèn)的這兩種類型。在外面引用Static Nested Class類的名稱為“外部類名.內(nèi)部類名”。在外面不需要?jiǎng)?chuàng)建外部類的實(shí)例對象,就可以直接創(chuàng)建Static Nested Class,例如,假設(shè)Inner是定義在Outer類中的Static Nested Class,那么可以使用如下語句創(chuàng)建Inner類: Outer.Inner inner = new Outer.Inner();由于static Nested Class不依賴于外部類的實(shí)例對象,所以,static Nested Class能訪問外部類的非static成員變量。當(dāng)在外部類中訪問Static Nested Class時(shí),可以直接使用Static Nested Class的名字,而不需要加上外部類的名字了,在Static Nested Class中也可以直接引用外部類的static的成員變量,不需要加上外部類的名字。 在靜態(tài)方法中定義的內(nèi)部類也是Static Nested Class,這時(shí)候不能在類前面加static關(guān)鍵字,靜態(tài)方法中的Static Nested Class與普通方法中的內(nèi)部類的應(yīng)用方式很相似,它除了可以直接訪問外部類中的static的成員變量,還可以訪問靜態(tài)方法中的局部變量,但是,該局部變量前必須加final修飾符。 備注:首先根據(jù)你的印象說出你對內(nèi)部類的總體方面的特點(diǎn):例如,在兩個(gè)地方可以定義,可以訪問外部類的成員變量,不能定義靜態(tài)成員,這是大的特點(diǎn)。然后再說一些細(xì)節(jié)方面的知識,例如,幾種定義方式的語法區(qū)別,靜態(tài)內(nèi)部類,以及匿名內(nèi)部類。} public void run(){}; 27、內(nèi)部類可以引用它的包含類的成員嗎?有沒有什么限制? 完全可以。如果不是靜態(tài)內(nèi)部類,那沒有什么限制! 如果你把靜態(tài)嵌套類當(dāng)作內(nèi)部類的一種特例,那在這種情況下不可以訪問外部類的普通成員變量,而只能訪問外部類中的靜態(tài)成員,例如,下面的代碼: class Outer { static int x;static class Inner { } } void test(){ } syso(x);答題時(shí),也要能察言觀色,揣摩提問者的心思,顯然人家希望你說的是靜態(tài)內(nèi)部類不能訪問外部類的成員,但你一上來就頂牛,這不好,要先順著人家,讓人家滿意,然后再說特殊情況,讓人家吃驚。 28、Anonymous Inner Class(匿名內(nèi)部類)是否可以extends(繼承)其它類,是否可以implements(實(shí)現(xiàn))interface(接口)? 可以繼承其他類或?qū)崿F(xiàn)其他接口。不僅是可以,而是必須! 29、super.getClass()方法調(diào)用 下面程序的輸出結(jié)果是多少? import java.util.Date;public class Test extends Date{ } 很奇怪,結(jié)果是Test 這屬于腦筋急轉(zhuǎn)彎的題目,在一個(gè)qq群有個(gè)網(wǎng)友正好問過這個(gè)問題,我覺得挺有趣,就研究了一下,沒想到今天還被你面到了,哈哈。 在test方法中,直接調(diào)用getClass().getName()方法,返回的是Test類名 由于getClass()在Object類中定義成了final,子類不能覆蓋該方法,所以,在 test方法中調(diào)用getClass().getName()方法,其實(shí)就是在調(diào)用從父類繼承的getClass()方法,等效于調(diào)用 super.getClass().getName()方法,所以,public static void main(String[] args){ } public void test(){ } System.out.println(super.getClass().getName());new Test().test();super.getClass().getName()方法返回的也應(yīng)該是Test。如果想得到父類的名稱,應(yīng)該用如下代碼: getClass().getSuperClass().getName(); 30、String是最基本的數(shù)據(jù)類型嗎? 基本數(shù)據(jù)類型包括byte、int、char、long、float、double、boolean和short。 java.lang.String類是final類型的,因此不可以繼承這個(gè)類、不能修改這個(gè)類。為了提高效率節(jié)省空間,我們應(yīng)該用StringBuffer類 31、String s = ”Hello“;s = s + ” world!“;這兩行代碼執(zhí)行后,原始的String對象中的內(nèi)容到底變了沒有? 沒有。因?yàn)镾tring被設(shè)計(jì)成不可變(immutable)類,所以它的所有對象都是不可變對象。在這段代碼中,s原先指向一個(gè)String對象,內(nèi)容是 ”Hello“,然后我們對s進(jìn)行了+操作,那么s所指向的那個(gè)對象是否發(fā)生了改變呢?答案是沒有。這時(shí),s不指向原來那個(gè)對象了,而指向了另一個(gè) String對象,內(nèi)容為”Hello world!“,原來那個(gè)對象還存在于內(nèi)存之中,只是s這個(gè)引用變量不再指向它了。 通過上面的說明,我們很容易導(dǎo)出另一個(gè)結(jié)論,如果經(jīng)常對字符串進(jìn)行各種各樣的修改,或者說,不可預(yù)見的修改,那么使用String來代表字符串的話會引起很大的內(nèi)存開銷。因?yàn)?String對象建立之后不能再改變,所以對于每一個(gè)不同的字符串,都需要一個(gè)String對象來表示。這時(shí),應(yīng)該考慮使用StringBuffer類,它允許修改,而不是每個(gè)不同的字符串都要生成一個(gè)新的對象。并且,這兩種類的對象轉(zhuǎn)換十分容易。 同時(shí),我們還可以知道,如果要使用內(nèi)容相同的字符串,不必每次都new一個(gè)String。例如我們要在構(gòu)造器中對一個(gè)名叫s的String引用變量進(jìn)行初始化,把它設(shè)置為初始值,應(yīng)當(dāng)這樣做: public class Demo { private String s;...public Demo { s = ”Initial Value“;}...} 而非 s = new String(”Initial Value“);后者每次都會調(diào)用構(gòu)造器,生成新對象,性能低下且內(nèi)存開銷大,并且沒有意義,因?yàn)镾tring對象不可改變,所以對于內(nèi)容相同的字符串,只要一個(gè)String對象來表示就可以了。也就說,多次調(diào)用上面的構(gòu)造器創(chuàng)建多個(gè)對象,他們的String類型屬性s都指向同一個(gè)對象。 上面的結(jié)論還基于這樣一個(gè)事實(shí):對于字符串常量,如果內(nèi)容相同,Java認(rèn)為它們代表同一個(gè)String對象。而用關(guān)鍵字new調(diào)用構(gòu)造器,總是會創(chuàng)建一個(gè)新的對象,無論內(nèi)容是否相同。至于為什么要把String類設(shè)計(jì)成不可變類,是它的用途決定的。其實(shí)不只String,很多Java標(biāo)準(zhǔn)類庫中的類都是不可變的。在開發(fā)一個(gè)系統(tǒng)的時(shí)候,我們有時(shí)候也需要設(shè)計(jì)不可變類,來傳遞一組相關(guān)的值,這也是面向?qū)ο笏枷氲捏w現(xiàn)。不可變類有一些優(yōu)點(diǎn),比如因?yàn)樗膶ο笫侵蛔x的,所以多線程并發(fā)訪問也不會有任何問題。當(dāng)然也有一些缺點(diǎn),比如每個(gè)不同的狀態(tài)都要一個(gè)對象來代表,可能會造成性能上的問題。所以Java標(biāo)準(zhǔn)類庫還提供了一個(gè)可變版本,即 StringBuffer。 32、是否可以繼承String類? String類是final類故不可以繼承。 33、String s = new String(”xyz“);創(chuàng)建了幾個(gè)String Object? 二者之間有什么區(qū)別? 兩個(gè)或一個(gè),”xyz”對應(yīng)一個(gè)對象,這個(gè)對象放在字符串常量緩沖區(qū),常量”xyz”不管出現(xiàn)多少遍,都是緩沖區(qū)中的那一個(gè)。New String每寫一遍,就創(chuàng)建一個(gè)新的對象,它一句那個(gè)常量”xyz”對象的內(nèi)容來創(chuàng)建出一個(gè)新String對象。如果以前就用過’xyz’,這句代表就不會創(chuàng)建”xyz”自己了,直接從緩沖區(qū)拿。 34、String 和StringBuffer的區(qū)別 JAVA平臺提供了兩個(gè)類:String和StringBuffer,它們可以儲存和操作字符串,即包含多個(gè)字符的字符數(shù)據(jù)。這個(gè)String類提供了數(shù)值不可改變的字符串。而這個(gè)StringBuffer類提供的字符串進(jìn)行修改。當(dāng)你知道字符數(shù)據(jù)要改變的時(shí)候你就可以使用StringBuffer。典型地,你可以使用StringBuffers來動(dòng)態(tài)構(gòu)造字符數(shù)據(jù)。另外,String實(shí)現(xiàn)了equals方法,new String(“abc”).equals(new String(“abc”)的結(jié)果為true,而StringBuffer沒有實(shí)現(xiàn)equals方法,所以,new StringBuffer(“abc”).equals(new StringBuffer(“abc”)的結(jié)果為false。 接著要舉一個(gè)具體的例子來說明,我們要把1到100的所有數(shù)字拼起來,組成一個(gè)串。StringBuffer sbf = new StringBuffer(); for(int i=0;i<100;i++){ sbf.append(i);} 上面的代碼效率很高,因?yàn)橹粍?chuàng)建了一個(gè)StringBuffer對象,而下面的代碼效率很低,因?yàn)閯?chuàng)建了101個(gè)對象。 String str = new String(); for(int i=0;i<100;i++){ str = str + i;} 在講兩者區(qū)別時(shí),應(yīng)把循環(huán)的次數(shù)搞成10000,然后用endTime-beginTime來比較兩者執(zhí)行的時(shí)間差異,最后還要講講StringBuilder與StringBuffer的區(qū)別。 String覆蓋了equals方法和hashCode方法,而StringBuffer沒有覆蓋equals方法和hashCode方法,所以,將StringBuffer對象存儲進(jìn)Java集合類中時(shí)會出現(xiàn)問題。 35、如何把一段逗號分割的字符串轉(zhuǎn)換成一個(gè)數(shù)組? 如果不查jdk api,我很難寫出來!我可以說說我的思路: 1.用正則表達(dá)式,代碼大概為:String [] result = orgStr.split(“,”);2.用 StingTokenizer ,代碼為:StringTokenizer tokener = StringTokenizer(orgStr,”,”);String [] result = new String[tokener.countTokens()];Int i=0;while(tokener.hasNext(){result[i++]=toker.nextToken();} 36、數(shù)組有沒有l(wèi)ength()這個(gè)方法? String有沒有l(wèi)ength()這個(gè)方法? 數(shù)組沒有l(wèi)ength()這個(gè)方法,有l(wèi)ength的屬性。String有有l(wèi)ength()這個(gè)方法。 37、下面這條語句一共創(chuàng)建了多少個(gè)對象:String s=”a“+”b“+”c“+”d“;答:對于如下代碼: String s1 = ”a“;String s2 = s1 + ”b“;String s3 = ”a“ + ”b“;System.out.println(s2 == ”ab“);System.out.println(s3 == ”ab“);第一條語句打印的結(jié)果為false,第二條語句打印的結(jié)果為true,這說明javac編譯可以對字符串常量直接相加的表達(dá)式進(jìn)行優(yōu)化,不必要等到運(yùn)行期去進(jìn)行加法運(yùn)算處理,而是在編譯時(shí)去掉其中的加號,直接將其編譯成一個(gè)這些常量相連的結(jié)果。 題目中的第一行代碼被編譯器在編譯時(shí)優(yōu)化后,相當(dāng)于直接定義了一個(gè)”abcd”的字符串,所以,上面的代碼應(yīng)該只創(chuàng)建了一個(gè)String對象。寫如下兩行代碼,String s = ”a“ + ”b“ + ”c“ + ”d“; System.out.println(s == ”abcd“);最終打印的結(jié)果應(yīng)該為true。 38、try {}里有一個(gè)return語句,那么緊跟在這個(gè)try后的finally {}里的code會不會被執(zhí)行,什么時(shí)候被執(zhí)行,在return前還是后? 也許你的答案是在return之前,但往更細(xì)地說,我的答案是在return中間執(zhí)行,請看下面程序代碼的運(yùn)行結(jié)果: public class Test { static int test(){ } } ---------執(zhí)行結(jié)果---------int x = 1;try { } finally { } ++x;return x;/** * @param args add by zxx ,Dec 9, 2008 */ public static void main(String[] args){ } // TODO Auto-generated method stub System.out.println(new Test().test());;1 運(yùn)行結(jié)果是1,為什么呢?主函數(shù)調(diào)用子函數(shù)并得到結(jié)果的過程,好比主函數(shù)準(zhǔn)備一個(gè)空罐子,當(dāng)子函數(shù)要返回結(jié)果時(shí),先把結(jié)果放在罐子里,然后再將程序邏輯返回到主函數(shù)。所謂返回,就是子函數(shù)說,我不運(yùn)行了,你主函數(shù)繼續(xù)運(yùn)行吧,這沒什么結(jié)果可言,結(jié)果是在說這話之前放進(jìn)罐子里的。 39、下面的程序代碼輸出的結(jié)果是多少? public class smallT { } public static void main(String args[]){ smallT t = new smallT();int b = t.get();System.out.println(b);} public int get(){ try { return 1;} finally { return 2;} } 返回的結(jié)果是2。 我可以通過下面一個(gè)例子程序來幫助我解釋這個(gè)答案,從下面例子的運(yùn)行結(jié)果中可以發(fā)現(xiàn),try中的return語句調(diào)用的函數(shù)先于finally中調(diào)用的函數(shù)執(zhí)行,也就是說return語句先執(zhí)行,finally語句后執(zhí)行,所以,返回的結(jié)果是2。Return并不是讓函數(shù)馬上返回,而是return語句執(zhí)行后,將把返回結(jié)果放置進(jìn)函數(shù)棧中,此時(shí)函數(shù)并不是馬上返回,它要執(zhí)行finally語句后才真正開始返回。 在講解答案時(shí)可以用下面的程序來幫助分析: public class Test { int test(){ try { } return func1();/** * @param args add by zxx ,Dec 9, 2008 */ public static void main(String[] args){ } // TODO Auto-generated method stub System.out.println(new Test().test());; } } finally { } return func2();int func1(){ } int func2(){ System.out.println(”func2“);return 2;System.out.println(”func1“);return 1;} -----------執(zhí)行結(jié)果----------------- func1 func2 2 結(jié)論:finally中的代碼比return 和break語句后執(zhí)行 40、final, finally, finalize的區(qū)別。 final 用于聲明屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承。 內(nèi)部類要訪問局部變量,局部變量必須定義成final類型,例如,一段代碼…… finally是異常處理語句結(jié)構(gòu)的一部分,表示總是執(zhí)行。 finalize是Object類的一個(gè)方法,在垃圾收集器執(zhí)行的時(shí)候會調(diào)用被回收對象的此方法,可以覆蓋此方法提供垃圾收集時(shí)的其他資源回收,例如關(guān)閉文件等。JVM不保證此方法總被調(diào)用 41、運(yùn)行時(shí)異常與一般異常有何異同? 異常表示程序運(yùn)行過程中可能出現(xiàn)的非正常狀態(tài),運(yùn)行時(shí)異常表示虛擬機(jī)的通常操作中可能遇到的異常,是一種常見運(yùn)行錯(cuò)誤。java編譯器要求方法必須聲明拋出可能發(fā)生的非運(yùn)行時(shí)異常,但是并不要求必須聲明拋出未被捕獲的運(yùn)行時(shí)異常。 42、error和exception有什么區(qū)別? error 表示恢復(fù)不是不可能但很困難的情況下的一種嚴(yán)重問題。比如說內(nèi)存溢出。不可能指望程序能處理這樣的情況。exception 表示一種設(shè)計(jì)或?qū)崿F(xiàn)問題。也就是說,它表示如果程序運(yùn)行正常,從不會發(fā)生的情況。 43、Java中的異常處理機(jī)制的簡單原理和應(yīng)用。 異常是指java程序運(yùn)行時(shí)(非編譯)所發(fā)生的非正常情況或錯(cuò)誤,與現(xiàn)實(shí)生活中的事件很相似,現(xiàn)實(shí)生活中的事件可以包含事件發(fā)生的時(shí)間、地點(diǎn)、人物、情節(jié)等信息,可以用一個(gè)對象來表示,Java使用面向?qū)ο蟮姆绞絹硖幚懋惓?,它把程序中發(fā)生的每個(gè)異常也都分別封裝到一個(gè)對象來表示的,該對象中包含有異常的信息。 Java對異常進(jìn)行了分類,不同類型的異常分別用不同的Java類表示,所有異常的根類為java.lang.Throwable,Throwable下面又派生了兩個(gè)子類:Error和Exception,Error 表示應(yīng)用程序本身無法克服和恢復(fù)的一種嚴(yán)重問題,程序只有死的份了,例如,說內(nèi)存溢出和線程死鎖等系統(tǒng)問題。Exception表示程序還能夠克服和恢復(fù)的問題,其中又分為系統(tǒng)異常和普通異常,系統(tǒng)異常是軟件本身缺陷所導(dǎo)致的問題,也就是軟件開發(fā)人員考慮不周所導(dǎo)致的問題,軟件使用者無法克服和恢復(fù)這種問題,但在這種問題下還可以讓軟件系統(tǒng)繼續(xù)運(yùn)行或者讓軟件死掉,例如,數(shù)組腳本越界(ArrayIndexOutOfBoundsException),空指針異常(NullPointerException)、類轉(zhuǎn)換異常(ClassCastException);普通異常是運(yùn)行環(huán)境的變化或異常所導(dǎo)致的問題,是用戶能夠克服的問題,例如,網(wǎng)絡(luò)斷線,硬盤空間不夠,發(fā)生這樣的異常后,程序不應(yīng)該死掉。 java為系統(tǒng)異常和普通異常提供了不同的解決方案,編譯器強(qiáng)制普通異常必須try..catch處理或用throws聲明繼續(xù)拋給上層調(diào)用方法處理,所以普通異常也稱為checked異常,而系統(tǒng)異常可以處理也可以不處理,所以,編譯器不強(qiáng)制用try..catch處理或用throws聲明,所以系統(tǒng)異常也稱為unchecked異常。 提示答題者:就按照三個(gè)級別去思考:虛擬機(jī)必須宕機(jī)的錯(cuò)誤,程序可以死掉也可以不死掉的錯(cuò)誤,程序不應(yīng)該死掉的錯(cuò)誤; 44、請寫出你最常見到的5個(gè)runtime exception。 這道題主要考你的代碼量到底多大,如果你長期寫代碼的,應(yīng)該經(jīng)常都看到過一些系統(tǒng)方面的異常,你不一定真要回答出5個(gè)具體的系統(tǒng)異常,但你要能夠說出什么是系統(tǒng)異常,以及幾個(gè)系統(tǒng)異常就可以了,當(dāng)然,這些異常完全用其英文名稱來寫是最好的,如果實(shí)在寫不出,那就用中文吧,有總比沒有強(qiáng)! 所謂系統(tǒng)異常,就是…..,它們都是RuntimeException的子類,在jdk doc中查RuntimeException類,就可以看到其所有的子類列表,也就是看到了所有的系統(tǒng)異常。我比較有印象的系統(tǒng)異常有:NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException。 45、JAVA語言如何進(jìn)行異常處理,關(guān)鍵字:throws,throw,try,catch,finally分別代表什么意義?在try塊中可以拋出異常嗎? 46、java中有幾種方法可以實(shí)現(xiàn)一個(gè)線程?用什么關(guān)鍵字修飾同步方法? stop()和suspend()方法為何不推薦使用? java5以前,有如下兩種: 第一種: new Thread(){}.start();這表示調(diào)用Thread子類對象的run方法,new Thread(){}表示一個(gè)Thread的匿名子類的實(shí)例對象,子類加上run方法后的代碼如下: new Thread(){ public void run(){ } }.start(); 第二種: new Thread(new Runnable(){}).start();這表示調(diào)用Thread對象接受的Runnable對象的run方法,new Runnable(){}表示一個(gè)Runnable的匿名子類的實(shí)例對象,runnable的子類加上run方法后的代碼如下: new Thread(new Runnable(){ public void run(){ } }).start(); 從java5開始,還有如下一些線程池創(chuàng)建多線程的方式: ExecutorService pool = Executors.newFixedThreadPool(3)for(int i=0;i<10;i++){ pool.execute(new Runable(){public void run(){}});} Executors.newCachedThreadPool().execute(new Runable(){public void run(){}});Executors.newSingleThreadExecutor().execute(new Runable(){public void run(){}}); 有兩種實(shí)現(xiàn)方法,分別使用new Thread()和new Thread(runnable)形式,第一種直接調(diào)用thread的run方法,所以,我們往往使用Thread子類,即new SubThread()。第二種調(diào)用runnable的run方法。 有兩種實(shí)現(xiàn)方法,分別是繼承Thread類與實(shí)現(xiàn)Runnable接口 用synchronized關(guān)鍵字修飾同步方法 反對使用stop(),是因?yàn)樗话踩?。它會解除由線程獲取的所有鎖定,而且如果對象處于一種不連貫狀態(tài),那么其他線程能在那種狀態(tài)下檢查和修改它們。結(jié)果很難檢查出真正的問題所在。suspend()方法容易發(fā)生死鎖。調(diào)用suspend()的時(shí)候,目標(biāo)線程會停下來,但卻仍然持有在這之前獲得的鎖定。此時(shí),其他任何線程都不能訪問鎖定的資源,除非被”掛起“的線程恢復(fù)運(yùn)行。對任何線程來說,如果它們想恢復(fù)目標(biāo)線程,同時(shí)又試圖使用任何一個(gè)鎖定的資源,就會造成死鎖。所以不應(yīng)該使用suspend(),而應(yīng)在自己的Thread類中置入一個(gè)標(biāo)志,指出線程應(yīng)該活動(dòng)還是掛起。若標(biāo)志指出線程應(yīng)該掛起,便用wait()命其進(jìn)入等待狀態(tài)。若標(biāo)志指出線程應(yīng)當(dāng)恢復(fù),則用一個(gè)notify()重新啟動(dòng)線程。 47、sleep()和 wait()有什么區(qū)別? (網(wǎng)上的答案:sleep是線程類(Thread)的方法,導(dǎo)致此線程暫停執(zhí)行指定時(shí)間,給執(zhí)行機(jī)會給其他線程,但是監(jiān)控狀態(tài)依然保持,到時(shí)后會自動(dòng)恢復(fù)。調(diào)用sleep不會釋放對象鎖。wait是Object類的方法,對此對象調(diào)用wait方法導(dǎo)致本線程放棄對象鎖,進(jìn)入等待此對象的等待鎖定池,只有針對此對象發(fā)出notify方法(或notifyAll)后本線程才進(jìn)入對象鎖定池準(zhǔn)備獲得對象鎖進(jìn)入運(yùn)行狀態(tài)。) sleep就是正在執(zhí)行的線程主動(dòng)讓出cpu,cpu去執(zhí)行其他線程,在sleep指定的時(shí)間過后,cpu才會回到這個(gè)線程上繼續(xù)往下執(zhí)行,如果當(dāng)前線程進(jìn)入了同步鎖,sleep方法并不會釋放鎖,即使當(dāng)前線程使用sleep方法讓出了cpu,但其他被同步鎖擋住了的線程也無法得到執(zhí)行。wait是指在一個(gè)已經(jīng)進(jìn)入了同步鎖的線程內(nèi),讓自己暫時(shí)讓出同步鎖,以便其他正在等待此鎖的線程可以得到同步鎖并運(yùn)行,只有其他線程調(diào)用了notify方法(notify并不釋放鎖,只是告訴調(diào)用過wait方法的線程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因?yàn)殒i還在別人手里,別人還沒釋放。如果notify方法后面的代碼還有很多,需要這些代碼執(zhí)行完后才會釋放鎖,可以在notfiy方法后增加一個(gè)等待和一些代碼,看看效果),調(diào)用wait方法的線程就會解除wait狀態(tài)和程序可以再次得到鎖后繼續(xù)向下運(yùn)行。對于wait的講解一定要配合例子代碼來說明,才顯得自己真明白。 package com.huawei.interview; public class MultiThread { /** * @param args */ public static void main(String[] args){ // TODO Auto-generated method stub new Thread(new Thread1()).start();try { } } Thread.sleep(10);// TODO Auto-generated catch block e.printStackTrace(); } catch(InterruptedException e){ new Thread(new Thread2()).start();private static class Thread1 implements Runnable { @Override public void run(){ // TODO Auto-generated method stub //由于這里的Thread1和下面的Thread2內(nèi)部run方法要用同一對象作為監(jiān)視器,我們這里不能用this,因?yàn)樵赥hread2里面的this和這個(gè)Thread1的this不是同一個(gè)對象。我們用MultiThread.class這個(gè)字節(jié)碼對象,當(dāng)前虛擬機(jī)里引用這個(gè)變量時(shí),指向的都是同一個(gè)對象。 System.out.println(”enter thread1...“); System.out.println(”thread1 is waiting“);try { synchronized(MultiThread.class){ //釋放鎖有兩種方式,第一種方式是程序自然離開監(jiān)視器的范圍,也就是離開了synchronized關(guān)鍵字管轄的代碼范圍,另一種方式就是在synchronized關(guān)鍵字管轄的代碼內(nèi)部調(diào)用監(jiān)視器對象的wait方法。這里,使用wait方法釋放鎖。 MultiThread.class.wait(); } private static class Thread2 implements Runnable { } } } catch(InterruptedException e){ } System.out.println(”thread1 is going on...“);System.out.println(”thread1 is being over!“); // TODO Auto-generated catch block e.printStackTrace(); @Override public void run(){ // TODO Auto-generated method stub synchronized(MultiThread.class){ System.out.println(”enter thread2...“); System.out.println(”thread2 notify other thread can release wait status..“);//由于notify方法并不釋放鎖,即使thread2調(diào)用下面的sleep方法休息了10毫秒,但thread1仍然不會執(zhí)行,因?yàn)閠hread2沒有釋放鎖,所以Thread1無法得不到鎖。 } } } MultiThread.class.notify(); System.out.println(”thread2 is sleeping ten try { } System.out.println(“thread2 is going on...”);System.out.println(“thread2 is being over!”);Thread.sleep(10);// TODO Auto-generated catch block e.printStackTrace();} catch(InterruptedException e){ millisecond...“);} 48、同步和異步有何異同,在什么情況下分別使用他們?舉例說明。 如果數(shù)據(jù)將在線程間共享。例如正在寫的數(shù)據(jù)以后可能被另一個(gè)線程讀到,或者正在讀的數(shù)據(jù)可能已經(jīng)被另一個(gè)線程寫過了,那么這些數(shù)據(jù)就是共享數(shù)據(jù),必須進(jìn)行同步存取。 當(dāng)應(yīng)用程序在對象上調(diào)用了一個(gè)需要花費(fèi)很長時(shí)間來執(zhí)行的方法,并且不希望讓程序等待方法的返回時(shí),就應(yīng)該使用異步編程,在很多情況下采用異步途徑往往更有效率。 49.下面兩個(gè)方法同步嗎?(自己發(fā)明) class Test { synchronized static void sayHello3() } synchronized void getX(){} { } 50、多線程有幾種實(shí)現(xiàn)方法?同步有幾種實(shí)現(xiàn)方法? 多線程有兩種實(shí)現(xiàn)方法,分別是繼承Thread類與實(shí)現(xiàn)Runnable接口 同步的實(shí)現(xiàn)方面有兩種,分別是synchronized,wait與notify wait():使一個(gè)線程處于等待狀態(tài),并且釋放所持有的對象的lock。 sleep():使一個(gè)正在運(yùn)行的線程處于睡眠狀態(tài),是一個(gè)靜態(tài)方法,調(diào)用此方法要捕捉InterruptedException異常。 notify():喚醒一個(gè)處于等待狀態(tài)的線程,注意的是在調(diào)用此方法的時(shí)候,并不能確切的喚醒某一個(gè)等待狀態(tài)的線程,而是由JVM確定喚醒哪個(gè)線程,而且不是按優(yōu)先級。 Allnotity():喚醒所有處入等待狀態(tài)的線程,注意并不是給所有喚醒線程一個(gè)對象的鎖,而是讓它們競爭。 51、啟動(dòng)一個(gè)線程是用run()還是start()?.啟動(dòng)一個(gè)線程是調(diào)用start()方法,使線程就緒狀態(tài),以后可以被調(diào)度為運(yùn)行狀態(tài),一個(gè)線程必須關(guān)聯(lián)一些具體的執(zhí)行代碼,run()方法是該線程所關(guān)聯(lián)的執(zhí)行代碼。 52、當(dāng)一個(gè)線程進(jìn)入一個(gè)對象的一個(gè)synchronized方法后,其它線程是否可進(jìn)入此對象的其它方法? 分幾種情況: 1.其他方法前是否加了synchronized關(guān)鍵字,如果沒加,則能。 2.如果這個(gè)方法內(nèi)部調(diào)用了wait,則可以進(jìn)入其他synchronized方法。 3.如果其他個(gè)方法都加了synchronized關(guān)鍵字,并且內(nèi)部沒有調(diào)用wait,則不能。 4.如果其他方法是static,它用的同步鎖是當(dāng)前類的字節(jié)碼,與非靜態(tài)的方法不能同步,因?yàn)榉庆o態(tài)的方法用的是this。 53、線程的基本概念、線程的基本狀態(tài)以及狀態(tài)之間的關(guān)系 一個(gè)程序中可以有多條執(zhí)行線索同時(shí)執(zhí)行,一個(gè)線程就是程序中的一條執(zhí)行線索,每個(gè)線程上都關(guān)聯(lián)有要執(zhí)行的代碼,即可以有多段程序代碼同時(shí)運(yùn)行,每個(gè)程序至少都有一個(gè)線程,即main方法執(zhí)行的那個(gè)線程。如果只是一個(gè)cpu,它怎么能夠同時(shí)執(zhí)行多段程序呢?這是從宏觀上來看的,cpu一會執(zhí)行a線索,一會執(zhí)行b線索,切換時(shí)間很快,給人的感覺是a,b在同時(shí)執(zhí)行,好比大家在同一個(gè)辦公室上網(wǎng),只有一條鏈接到外部網(wǎng)線,其實(shí),這條網(wǎng)線一會為a傳數(shù)據(jù),一會為b傳數(shù)據(jù),由于切換時(shí)間很短暫,所以,大家感覺都在同時(shí)上網(wǎng)。 狀態(tài):就緒,運(yùn)行,synchronize阻塞,wait和sleep掛起,結(jié)束。wait必須在synchronized內(nèi)部調(diào)用。 調(diào)用線程的start方法后線程進(jìn)入就緒狀態(tài),線程調(diào)度系統(tǒng)將就緒狀態(tài)的線程轉(zhuǎn)為運(yùn)行狀態(tài),遇到synchronized語句時(shí),由運(yùn)行狀態(tài)轉(zhuǎn)為阻塞,當(dāng)synchronized獲得鎖后,由阻塞轉(zhuǎn)為運(yùn)行,在這種情況可以調(diào)用wait方法轉(zhuǎn)為掛起狀態(tài),當(dāng)線程關(guān)聯(lián)的代碼執(zhí)行完后,線程變?yōu)榻Y(jié)束狀態(tài)。 54、簡述synchronized和java.util.concurrent.locks.Lock的異同 ? 主要相同點(diǎn):Lock能完成synchronized所實(shí)現(xiàn)的所有功能 主要不同點(diǎn):Lock有比synchronized更精確的線程語義和更好的性能。synchronized會自動(dòng)釋放鎖,而Lock一定要求程序員手工釋放,并且必須在finally從句中釋放。Lock還有更強(qiáng)大的功能,例如,它的tryLock方法可以非阻塞方式去拿鎖。 舉例說明(對下面的題用lock進(jìn)行了改寫): package com.huawei.interview; import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock; public class ThreadTest { /** * @param args */ private int j; private Lock lock = new ReentrantLock();public static void main(String[] args){ } private class Subtractor implements Runnable { } private class Adder implements Runnable { @Override public void run(){ // TODO Auto-generated method stub while(true){ @Override public void run(){ } // TODO Auto-generated method stub while(true){ } /*synchronized(ThreadTest.this){ System.out.println(”j--=“ + j--);//這里拋異常了,鎖能釋放嗎? }*/ lock.lock();try { { } lock.unlock();System.out.println(”j--=“ + j--);}finally // TODO Auto-generated method stub ThreadTest tt = new ThreadTest();for(int i=0;i<2;i++){ } new Thread(tt.new Adder()).start();new Thread(tt.new Subtractor()).start(); /*synchronized(ThreadTest.this){ System.out.println(”j++=“ + j++); }*/ lock.lock(); try { System.out.println(”j++=“ + j++); }finally { lock.unlock(); } } } } } 55、設(shè)計(jì)4個(gè)線程,其中兩個(gè)線程每次對j增加1,另外兩個(gè)線程對j每次減少1。寫出程序。 以下程序使用內(nèi)部類實(shí)現(xiàn)線程,對j增減的時(shí)候沒有考慮順序問題。 public class ThreadTest1 { private int j; public static void main(String args[]){ ThreadTest1 tt=new ThreadTest1(); Inc inc=tt.new Inc(); Dec dec=tt.new Dec(); for(int i=0;i<2;i++){ Thread t=new Thread(inc); t.start(); t=new Thread(dec); t.start(); } } private synchronized void inc(){ j++; System.out.println(Thread.currentThread().getName()+”-inc:“+j); } private synchronized void dec(){ j--; System.out.println(Thread.currentThread().getName()+”-dec:“+j); } class Inc implements Runnable{ public void run(){ for(int i=0;i<100;i++){ inc(); } } } class Dec implements Runnable{ public void run(){ for(int i=0;i<100;i++){ dec(); } } } } ----------隨手再寫的一個(gè)-------------class A { JManger j =new JManager();main(){ new A().call();} void call { for(int i=0;i<2;i++){ new Thread(new Runnable(){ public void run(){while(true){j.accumulate()}}}).start(); new Thread(new Runnable(){ public void run(){while(true){j.sub()}}}).start();} } } class JManager { private j = 0; public synchronized void subtract(){ j--} public synchronized void accumulate(){ j++;} } 56、子線程循環(huán)10次,接著主線程循環(huán)100,接著又回到子線程循環(huán)10次,接著再回到主線程又循環(huán)100,如此循環(huán)50次,請寫出程序。 最終的程序代碼如下: public class ThreadTest { } public void run(){ } for(int i=0;i<50;i++){ business.SubThread(i); } public void init(){ final Business business = new Business();new Thread(new Runnable(){ } /** * @param args */ public static void main(String[] args){ // TODO Auto-generated method stub new ThreadTest().init(); }).start(); for(int i=0;i<50;i++){ business.MainThread(i);} private class Business { boolean bShouldSub = true;//這里相當(dāng)于定義了控制該誰執(zhí)行的一個(gè)信號燈 public synchronized void MainThread(int i){ } public synchronized void SubThread(int i){ if(!bShouldSub) try { this.wait();// TODO Auto-generated catch block e.printStackTrace();} catch(InterruptedException e){ if(bShouldSub) { } bShouldSub = true;this.notify();System.out.println(Thread.currentThread().getName()+ try { this.wait();// TODO Auto-generated catch block e.printStackTrace(); } catch(InterruptedException e){ } for(int j=0;j<5;j++)”:i=“ + i +”,j=“ + j);} for(int j=0;j<10;j++) } } } { } bShouldSub = false;this.notify(); System.out.println(Thread.currentThread().getName()+ ”:i=“ + i +”,j=“ + j);備注:不可能一上來就寫出上面的完整代碼,最初寫出來的代碼如下,問題在于兩個(gè)線程的代碼要參照同一個(gè)變量,即這兩個(gè)線程的代碼要共享數(shù)據(jù),所以,把這兩個(gè)線程的執(zhí)行代碼搬到同一個(gè)類中去: package com.huawei.interview.lym; public class ThreadTest { new Thread(new Runnable(){ public void run(){ private static boolean bShouldMain = false; public static void main(String[] args){ // TODO Auto-generated method stub /*new Thread(){ public void run(){ } //final String str = new String(”“);for(int i=0;i<50;i++){ for(int j=0;j<10;j++){ } System.out.println(”i=“ + i + ”,j=“ + j);} }.start();*/ } } for(int i=0;i<50;i++){ synchronized(ThreadTest.class){ if(bShouldMain){ } for(int j=0;j<10;j++){ } bShouldMain = true; ThreadTest.class.notify(); System.out.println(”i=“ + i + ”,j=“ + j); try { } ThreadTest.class.wait();} e.printStackTrace(); catch(InterruptedException e){ Thread.currentThread().getName()+ } }).start();for(int i=0;i<50;i++){ synchronized(ThreadTest.class){ } ”i=“ + i + ”,j=“ + j);if(!bShouldMain){ try { } ThreadTest.class.wait();} e.printStackTrace();catch(InterruptedException e){ } { for(int j=0;j<5;j++)System.out.println(Thread.currentThread().getName()+ } } } bShouldMain = false;ThreadTest.class.notify(); } 下面使用jdk5中的并發(fā)庫來實(shí)現(xiàn)的: import java.util.concurrent.Executors;import java.util.concurrent.ExecutorService;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;import java.util.concurrent.locks.Condition; public class ThreadTest { private static Lock lock = new ReentrantLock();private static Condition subThreadCondition = lock.newCondition();private static boolean bBhouldSubThread = false;public static void main(String [] args){ ExecutorService threadPool = Executors.newFixedThreadPool(3); threadPool.execute(new Runnable(){ public void run() { for(int i=0;i<50;i++) { lock.lock(); try { if(!bBhouldSubThread) subThreadCondition.await(); for(int j=0;j<10;j++) { System.out.println(Thread.currentThread().getName()+ ”,j=“ + j); } bBhouldSubThread = false; subThreadCondition.signal(); }catch(Exception e) { } finally { } } lock.unlock(); } } } });threadPool.shutdown();for(int i=0;i<50;i++){ lock.lock(); try { if(bBhouldSubThread) subThreadCondition.await(); } for(int j=0;j<10;j++){ System.out.println(Thread.currentThread().getName()+ ”,j=“ + j);} bBhouldSubThread = true;subThreadCondition.signal(); }catch(Exception e){ } finally { lock.unlock();} 57、介紹Collection框架的結(jié)構(gòu) 答:隨意發(fā)揮題,天南海北誰便談,只要讓別覺得你知識淵博,理解透徹即可。 58、Collection框架中實(shí)現(xiàn)比較要實(shí)現(xiàn)什么接口 comparable/comparator 59、ArrayList和Vector的區(qū)別 答: 這兩個(gè)類都實(shí)現(xiàn)了List接口(List接口繼承了Collection接口),他們都是有序集合,即存儲在這兩個(gè)集合中的元素的位置都是有順序的,相當(dāng)于一種動(dòng)態(tài)的數(shù)組,我們以后可以按位置索引號取出某個(gè)元素,并且其中的數(shù)據(jù)是允許重復(fù)的,這是HashSet之類的集合的最大不同處,HashSet之類的集合不可以按索引號去檢索其中的元素,也不允許有重復(fù)的元素(本來題目問的與hashset沒有任何關(guān)系,但為了說清楚ArrayList與Vector的功能,我們使用對比方式,更有利于說明問題)。 接著才說ArrayList與Vector的區(qū)別,這主要包括兩個(gè)方面:.(1)同步性: Vector是線程安全的,也就是說是它的方法之間是線程同步的,而ArrayList是線程序不安全的,它的方法之間是線程不同步的。如果只有一個(gè)線程會訪問到集合,那最好是使用ArrayList,因?yàn)樗豢紤]線程安全,效率會高些;如果有多個(gè)線程會訪問到集合,那最好是使用Vector,因?yàn)椴恍枰覀冏约涸偃タ紤]和編寫線程安全的代碼。 備注:對于Vector&ArrayList、Hashtable&HashMap,要記住線程安全的問題,記住Vector與Hashtable是舊的,是java一誕生就提供了的,它們是線程安全的,ArrayList與HashMap是java2時(shí)才提供的,它們是線程不安全的。所以,我們講課時(shí)先講老的。(2)數(shù)據(jù)增長: ArrayList與Vector都有一個(gè)初始的容量大小,當(dāng)存儲進(jìn)它們里面的元素的個(gè)數(shù)超過了容量時(shí),就需要增加ArrayList與Vector的存儲空間,每次要增加存儲空間時(shí),不是只增加一個(gè)存儲單元,而是增加多個(gè)存儲單元,每次增加的存儲單元的個(gè)數(shù)在內(nèi)存空間利用與程序效率之間要取得一定的平衡。Vector默認(rèn)增長為原來兩倍,而ArrayList的增長策略在文檔中沒有明確規(guī)定(從源代碼看到的是增長為原來的1.5倍)。ArrayList與Vector都可以設(shè)置初始的空間大小,Vector還可以設(shè)置增長的空間大小,而ArrayList沒有提供設(shè)置增長空間的方法。 總結(jié):即Vector增長原來的一倍,ArrayList增加原來的0.5倍。 60、HashMap和Hashtable的區(qū)別 (條理上還需要整理,也是先說相同點(diǎn),再說不同點(diǎn))HashMap是Hashtable的輕量級實(shí)現(xiàn)(非線程安全的實(shí)現(xiàn)),他們都完成了Map接口,主要區(qū)別在于HashMap允許空(null)鍵值(key),由于非線程安全,在只有一個(gè)線程訪問的情況下,效率要高于Hashtable。 HashMap允許將null作為一個(gè)entry的key或者value,而Hashtable不允許。 HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因?yàn)閏ontains方法容易讓人引起誤解。 Hashtable繼承自Dictionary類,而HashMap是Java1.2引進(jìn)的Map interface的一個(gè)實(shí)現(xiàn)。 最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多個(gè)線程訪問Hashtable時(shí),不需要自己為它的方法實(shí)現(xiàn)同步,而HashMap 就必須為之提供外同步。 Hashtable和HashMap采用的hash/rehash算法都大概一樣,所以性能不會有很大的差異。 就HashMap與HashTable主要從三方面來說。 一.歷史原因:Hashtable是基于陳舊的Dictionary類的,HashMap是Java 1.2引進(jìn)的Map接口的一個(gè)實(shí)現(xiàn) 二.同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的 三.值:只有HashMap可以讓你將空值作為一個(gè)表的條目的key或value 61、List 和 Map 區(qū)別? 一個(gè)是存儲單列數(shù)據(jù)的集合,另一個(gè)是存儲鍵和值這樣的雙列數(shù)據(jù)的集合,List中存儲的數(shù)據(jù)是有順序,并且允許重復(fù);Map中存儲的數(shù)據(jù)是沒有順序的,其鍵是不能重復(fù)的,它的值是可以有重復(fù)的。 62、List, Set, Map是否繼承自Collection接口? List,Set是,Map不是 63、List、Map、Set三個(gè)接口,存取元素時(shí),各有什么特點(diǎn)? 這樣的題屬于隨意發(fā)揮題:這樣的題比較考水平,兩個(gè)方面的水平:一是要真正明白這些內(nèi)容,二是要有較強(qiáng)的總結(jié)和表述能力。如果你明白,但表述不清楚,在別人那里則等同于不明白。 首先,List與Set具有相似性,它們都是單列元素的集合,所以,它們有一個(gè)功共同的父接口,叫Collection。Set里面不允許有重復(fù)的元素,所謂重復(fù),即不能有兩個(gè)相等(注意,不是僅僅是相同)的對象,即假設(shè)Set集合中有了一個(gè)A對象,現(xiàn)在我要向Set集合再存入一個(gè)B對象,但B對象與A對象equals相等,則B對象存儲不進(jìn)去,所以,Set集合的add方法有一個(gè)boolean的返回值,當(dāng)集合中沒有某個(gè)元素,此時(shí)add方法可成功加入該元素時(shí),則返回true,當(dāng)集合含有與某個(gè)元素equals相等的元素時(shí),此時(shí)add方法無法加入該元素,返回結(jié)果為false。Set取元素時(shí),沒法說取第幾個(gè),只能以Iterator接口取得所有的元素,再逐一遍歷各個(gè)元素。 List表示有先后順序的集合,注意,不是那種按年齡、按大小、按價(jià)格之類的排序。當(dāng)我們多次調(diào)用add(Obj e)方法時(shí),每次加入的對象就像火車站買票有排隊(duì)順序一樣,按先來后到的順序排序。有時(shí)候,也可以插隊(duì),即調(diào)用add(int index,Obj e)方法,就可以指定當(dāng)前對象在集合中的存放位置。一個(gè)對象可以被反復(fù)存儲進(jìn)List中,每調(diào)用一次add方法,這個(gè)對象就被插入進(jìn)集合中一次,其實(shí),并不是把這個(gè)對象本身存儲進(jìn)了集合中,而是在集合中用一個(gè)索引變量指向這個(gè)對象,當(dāng)這個(gè)對象被add多次時(shí),即相當(dāng)于集合中有多個(gè)索引指向了這個(gè)對象,如圖x所示。List除了可以以Iterator接口取得所有的元素,再逐一遍歷各個(gè)元素之外,還可以調(diào)用get(index i)來明確說明取第幾個(gè)。 Map與List和Set不同,它是雙列的集合,其中有put方法,定義如下:put(obj key,obj value),每次存儲時(shí),要存儲一對key/value,不能存儲重復(fù)的key,這個(gè)重復(fù)的規(guī)則也是按equals比較相等。取則可以根據(jù)key獲得相應(yīng)的value,即get(Object key)返回值為key 所對應(yīng)的value。另外,也可以獲得所有的key的結(jié)合,還可以獲得所有的value的結(jié)合,還可以獲得key和value組合成的Map.Entry對象的集合。 List 以特定次序來持有元素,可有重復(fù)元素。Set 無法擁有重復(fù)元素,內(nèi)部排序。Map 保存key-value值,value可多值。 HashSet按照hashcode值的某種運(yùn)算方式進(jìn)行存儲,而不是直接按hashCode值的大小進(jìn)行存儲。例如,”abc“---> 78,”def“---> 62,”xyz“---> 65在hashSet中的存儲順序不是62,65,78,這些問題感謝以前一個(gè)叫崔健的學(xué)員提出,最后通過查看源代碼給他解釋清楚,看本次培訓(xùn)學(xué)員當(dāng)中有多少能看懂源碼。LinkedHashSet按插入的順序存儲,那被存儲對象的hashcode方法還有什么作用呢?學(xué)員想想!hashset集合比較兩個(gè)對象是否相等,首先看hashcode方法是否相等,然后看equals方法是否相等。new 兩個(gè)Student插入到HashSet中,看HashSet的size,實(shí)現(xiàn)hashcode和equals方法后再看size。 同一個(gè)對象可以在Vector中加入多次。往集合里面加元素,相當(dāng)于集合里用一根繩子連接到了目標(biāo)對象。往HashSet中卻加不了多次的。 64、說出ArrayList,Vector, LinkedList的存儲性能和特性 ArrayList和Vector都是使用數(shù)組方式存儲數(shù)據(jù),此數(shù)組元素?cái)?shù)大于實(shí)際存儲的數(shù)據(jù)以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及數(shù)組元素移動(dòng)等內(nèi)存操作,所以索引數(shù)據(jù)快而插入數(shù)據(jù)慢,Vector由于使用了synchronized方法(線程安全),通常性能上較ArrayList差,而LinkedList使用雙向鏈表實(shí)現(xiàn)存儲,按序號索引數(shù)據(jù)需要進(jìn)行前向或后向遍歷,但是插入數(shù)據(jù)時(shí)只需要記錄本項(xiàng)的前后項(xiàng)即可,所以插入速度較快。 LinkedList也是線程不安全的,LinkedList提供了一些方法,使得LinkedList可以被當(dāng)作堆棧和隊(duì)列來使用。 65、去掉一個(gè)Vector集合中重復(fù)的元素 Vector newVector = new Vector();For(int i=0;i newVector.add(obj);} 還有一種簡單的方式,HashSet set = new HashSet(vector);66、Collection 和 Collections的區(qū)別。 Collection是集合類的上級接口,繼承與他的接口主要有Set 和List.Collections是針對集合類的一個(gè)幫助類,他提供一系列靜態(tài)方法實(shí)現(xiàn)對各種集合的搜索、排序、線程安全化等操作。 67、Set里的元素是不能重復(fù)的,那么用什么方法來區(qū)分重復(fù)與否呢? 是用==還是equals()? 它們有何區(qū)別? Set里的元素是不能重復(fù)的,元素重復(fù)與否是使用equals()方法進(jìn)行判斷的。 equals()和==方法決定引用值是否指向同一對象equals()在類中被覆蓋,為的是當(dāng)兩個(gè)分離的對象的內(nèi)容和類型相配的話,返回真值。 68、你所知道的集合類都有哪些?主要方法? 最常用的集合類是 List 和 Map。List 的具體實(shí)現(xiàn)包括 ArrayList 和 Vector,它們是可變大小的列表,比較適合構(gòu)建、存儲和操作任何類型對象的元素列表。List 適用于按數(shù)值索引訪問元素的情形。 Map 提供了一個(gè)更通用的元素存儲方法。Map 集合類用于存儲元素對(稱作”鍵“和”值“),其中每個(gè)鍵映射到一個(gè)值。 ArrayList/Vector?List ?Collection HashSet/TreeSet?Set Propeties?HashTable ?Map Treemap/HashMap 我記的不是方法名,而是思想,我知道它們都有增刪改查的方法,但這些方法的具體名稱,我記得不是很清楚,對于set,大概的方法是add,remove, contains;對于map,大概的方法就是put,remove,contains等,因?yàn)椋抑灰趀clispe下按點(diǎn)操作符,很自然的這些方法就出來了。我記住的一些思想就是List類會有g(shù)et(int index)這樣的方法,因?yàn)樗梢园错樞蛉≡?,而set類中沒有g(shù)et(int index)這樣的方法。List和set都可以迭代出所有元素,迭代時(shí)先要得到一個(gè)iterator對象,所以,set和list類都有一個(gè)iterator方法,用于返回那個(gè)iterator對象。map可以返回三個(gè)集合,一個(gè)是返回所有的key的集合,另外一個(gè)返回的是所有value的集合,再一個(gè)返回的key和value組合成的EntrySet對象的集合,map也有g(shù)et方法,參數(shù)是key,返回值是key對應(yīng)的value。 69、兩個(gè)對象值相同(x.equals(y)== true),但卻可有不同的hash code,這句話對不對? 對。 如果對象要保存在HashSet或HashMap中,它們的equals相等,那么,它們的hashcode值就必須相等。 如果不是要保存在HashSet或HashMap,則與hashcode沒有什么關(guān)系了,這時(shí)候hashcode不等是可以的,例如arrayList存儲的對象就不用實(shí)現(xiàn)hashcode,當(dāng)然,我們沒有理由不實(shí)現(xiàn),通常都會去實(shí)現(xiàn)的。 70、TreeSet里面放對象,如果同時(shí)放入了父類和子類的實(shí)例對象,那比較時(shí)使用的是父類的compareTo方法,還是使用的子類的compareTo方法,還是拋異常! (應(yīng)該是沒有針對問題的確切的答案,當(dāng)前的add方法放入的是哪個(gè)對象,就調(diào)用哪個(gè)對象的compareTo方法,至于這個(gè)compareTo方法怎么做,就看當(dāng)前這個(gè)對象的類中是如何編寫這個(gè)方法的)實(shí)驗(yàn)代碼: public class Parent implements Comparable { } public class Child extends Parent { // TODO Auto-generated method stub public Child(){ } public int compareTo(Object o){ super(3);private int age = 0;public Parent(int age){ } public int compareTo(Object o){ } // TODO Auto-generated method stub System.out.println(”method of parent“);Parent o1 =(Parent)o;return age>o1.age?1:age } } System.out.println(”method of child“);Child o1 =(Child)o;return 1;// public class TreeSetTest { /** * @param args */ public static void main(String[] args){ } // TODO Auto-generated method stub TreeSet set = new TreeSet();set.add(new Parent(3));set.add(new Child());set.add(new Parent(4));System.out.println(set.size());} 71、說出一些常用的類,包,接口,請各舉5個(gè) 要讓人家感覺你對java ee開發(fā)很熟,所以,不能僅僅只列core java中的那些東西,要多列你在做ssh項(xiàng)目中涉及的那些東西。就寫你最近寫的那些程序中涉及的那些類。 常用的類:BufferedReader BufferedWriter FileReader FileWirter String Integer java.util.Date,System,Class,List,HashMap 常用的包:java.lang java.io java.util java.sql ,javax.servlet,org.apache.strtuts.action,org.hibernate 常用的接口:Remote List Map Document NodeList ,Servlet,HttpServletRequest,HttpServletResponse,Transaction(Hibernate)、Session(Hibernate),HttpSession 72、java中有幾種類型的流?JDK為每種類型的流提供了一些抽象類以供繼承,請說出他們分別是哪些類? 字節(jié)流,字符流。字節(jié)流繼承于InputStream OutputStream,字符流繼承于InputStreamReader OutputStreamWriter。在java.io包中還有許多其他的流,主要是為了提高性能和使用方便。 73、字節(jié)流與字符流的區(qū)別 要把一片二進(jìn)制數(shù)據(jù)數(shù)據(jù)逐一輸出到某個(gè)設(shè)備中,或者從某個(gè)設(shè)備中逐一讀取一片二進(jìn)制數(shù)據(jù),不管輸入輸出設(shè)備是什么,我們要用統(tǒng)一的方式來完成這些操作,用一種抽象的方式進(jìn)行描述,這個(gè)抽象描述方式起名為IO流,對應(yīng)的抽象類為OutputStream和InputStream,不同的實(shí)現(xiàn)類就代表不同的輸入和輸出設(shè)備,它們都是針對字節(jié)進(jìn)行操作的。 在應(yīng)用中,經(jīng)常要完全是字符的一段文本輸出去或讀進(jìn)來,用字節(jié)流可以嗎?計(jì)算機(jī)中的一切最終都是二進(jìn)制的字節(jié)形式存在。對于“中國”這些字符,首先要得到其對應(yīng)的字節(jié),然后將字節(jié)寫入到輸出流。讀取時(shí),首先讀到的是字節(jié),可是我們要把它顯示為字符,我們需要將字節(jié)轉(zhuǎn)換成字符。由于這樣的需求很廣泛,人家專門提供了字符流的包裝類。 底層設(shè)備永遠(yuǎn)只接受字節(jié)數(shù)據(jù),有時(shí)候要寫字符串到底層設(shè)備,需要將字符串轉(zhuǎn)成字節(jié)再進(jìn)行寫入。字符流是字節(jié)流的包裝,字符流則是直接接受字符串,它內(nèi)部將串轉(zhuǎn)成字節(jié),再寫入底層設(shè)備,這為我們向IO設(shè)別寫入或讀取字符串提供了一點(diǎn)點(diǎn)方便。 字符向字節(jié)轉(zhuǎn)換時(shí),要注意編碼的問題,因?yàn)樽址D(zhuǎn)成字節(jié)數(shù)組,其實(shí)是轉(zhuǎn)成該字符的某種編碼的字節(jié)形式,讀取也是反之的道理。 講解字節(jié)流與字符流關(guān)系的代碼案例: import java.io.BufferedReader;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.FileReader;import java.io.FileWriter;import java.io.InputStreamReader;import java.io.PrintWriter; public class IOTest { public static void main(String[] args)throws Exception { String str = ”中國人“; /*FileOutputStream fos = new FileOutputStream(”1.txt“); fos.write(str.getBytes(”UTF-8“)); fos.close();*/ /*FileWriter fw = new FileWriter(”1.txt“); fw.write(str); fw.close();*/ PrintWriter pw = new PrintWriter(”1.txt“,”utf-8“); pw.write(str); pw.close(); /*FileReader fr = new FileReader(”1.txt“); } } char[] buf = new char[1024];int len = fr.read(buf);String myStr = new String(buf,0,len);System.out.println(myStr);*/ /*FileInputStream fr = new FileInputStream(”1.txt“);byte[] buf = new byte[1024];int len = fr.read(buf);String myStr = new String(buf,0,len,”UTF-8“);System.out.println(myStr);*/ BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(”1.txt“),”UTF-8“));String myStr = br.readLine();br.close();System.out.println(myStr);74、什么是java序列化,如何實(shí)現(xiàn)java序列化?或者請解釋Serializable接口的作用。 我們有時(shí)候?qū)⒁粋€(gè)java對象變成字節(jié)流的形式傳出去或者從一個(gè)字節(jié)流中恢復(fù)成一個(gè)java對象,例如,要將java對象存儲到硬盤或者傳送給網(wǎng)絡(luò)上的其他計(jì)算機(jī),這個(gè)過程我們可以自己寫代碼去把一個(gè)java對象變成某個(gè)格式的字節(jié)流再傳輸,但是,jre本身就提供了這種支持,我們可以調(diào)用OutputStream的writeObject方法來做,如果要讓java 幫我們做,要被傳輸?shù)膶ο蟊仨殞?shí)現(xiàn)serializable接口,這樣,javac編譯時(shí)就會進(jìn)行特殊處理,編譯的類才可以被writeObject方法操作,這就是所謂的序列化。需要被序列化的類必須實(shí)現(xiàn)Serializable接口,該接口是一個(gè)mini接口,其中沒有需要實(shí)現(xiàn)的方法,implements Serializable只是為了標(biāo)注該對象是可被序列化的。 例如,在web開發(fā)中,如果對象被保存在了Session中,tomcat在重啟時(shí)要把Session對象序列化到硬盤,這個(gè)對象就必須實(shí)現(xiàn)Serializable接口。如果對象要經(jīng)過分布式系統(tǒng)進(jìn)行網(wǎng)絡(luò)傳輸或通過rmi等遠(yuǎn)程調(diào)用,這就需要在網(wǎng)絡(luò)上傳輸對象,被傳輸?shù)膶ο缶捅仨殞?shí)現(xiàn)Serializable接口。75、描述一下JVM加載class文件的原理機(jī)制? JVM中類的裝載是由ClassLoader和它的子類來實(shí)現(xiàn)的,Java ClassLoader 是一個(gè)重要的Java運(yùn)行時(shí)系統(tǒng)組件。它負(fù)責(zé)在運(yùn)行時(shí)查找和裝入類文件的類。 76、heap和stack有什么區(qū)別。 java的內(nèi)存分為兩類,一類是棧內(nèi)存,一類是堆內(nèi)存。棧內(nèi)存是指程序進(jìn)入一個(gè)方法時(shí),會為這個(gè)方法單獨(dú)分配一塊私屬存儲空間,用于存儲這個(gè)方法內(nèi)部的局部變量,當(dāng)這個(gè)方法結(jié)束時(shí),分配給這個(gè)方法的棧會釋放,這個(gè)棧中的變量也將隨之釋放。 堆是與棧作用不同的內(nèi)存,一般用于存放不放在當(dāng)前方法棧中的那些數(shù)據(jù),例如,使用new創(chuàng)建的對象都放在堆里,所以,它不會隨方法的結(jié)束而消失。方法中的局部變量使用final修飾后,放在堆中,而不是棧中。 77、GC是什么? 為什么要有GC? GC是垃圾收集的意思(Gabage Collection),內(nèi)存處理是編程人員容易出現(xiàn)問題的地方,忘記或者錯(cuò)誤的內(nèi)存回收會導(dǎo)致程序或系統(tǒng)的不穩(wěn)定甚至崩潰,Java提供的GC功能可以自動(dòng)監(jiān)測對象是否超過作用域從而達(dá)到自動(dòng)回收內(nèi)存的目的,Java語言沒有提供釋放已分配內(nèi)存的顯示操作方法。 78、垃圾回收的優(yōu)點(diǎn)和原理。并考慮2種回收機(jī)制。 Java語言中一個(gè)顯著的特點(diǎn)就是引入了垃圾回收機(jī)制,使c++程序員最頭疼的內(nèi)存管理的問題迎刃而解,它使得Java程序員在編寫程序的時(shí)候不再需要考慮內(nèi)存管理。由于有個(gè)垃圾回收機(jī)制,Java中的對象不再有”作用域“的概念,只有對象的引用才有”作用域“。垃圾回收可以有效的防止內(nèi)存泄露,有效的使用可以使用的內(nèi)存。垃圾回收器通常是作為一個(gè)單獨(dú)的低級別的線程運(yùn)行,不可預(yù)知的情況下對內(nèi)存堆中已經(jīng)死亡的或者長時(shí)間沒有使用的對象進(jìn)行清楚和回收,程序員不能實(shí)時(shí)的調(diào)用垃圾回收器對某個(gè)對象或所有對象進(jìn)行垃圾回收?;厥諜C(jī)制有分代復(fù)制垃圾回收和標(biāo)記垃圾回收,增量垃圾回收。 79、垃圾回收器的基本原理是什么?垃圾回收器可以馬上回收內(nèi)存嗎?有什么辦法主動(dòng)通知虛擬機(jī)進(jìn)行垃圾回收? 對于GC來說,當(dāng)程序員創(chuàng)建對象時(shí),GC就開始監(jiān)控這個(gè)對象的地址、大小以及使用情況。通常,GC采用有向圖的方式記錄和管理堆(heap)中的所有對象。通過這種方式確定哪些對象是”可達(dá)的“,哪些對象是”不可達(dá)的“。當(dāng)GC確定一些對象為”不可達(dá)“時(shí),GC就有責(zé)任回收這些內(nèi)存空間??梢?。程序員可以手動(dòng)執(zhí)行System.gc(),通知GC運(yùn)行,但是Java語言規(guī)范并不保證GC一定會執(zhí)行。 80、什么時(shí)候用assert。 assertion(斷言)在軟件開發(fā)中是一種常用的調(diào)試方式,很多開發(fā)語言中都支持這種機(jī)制。在實(shí)現(xiàn)中,assertion就是在程序中的一條語句,它對一個(gè)boolean表達(dá)式進(jìn)行檢查,一個(gè)正確程序必須保證這個(gè)boolean表達(dá)式的值為true;如果該值為false,說明程序已經(jīng)處于不正確的狀態(tài)下,assert將給出警告或退出。一般來說,assertion用于保證程序最基本、關(guān)鍵的正確性。assertion檢查通常在開發(fā)和測試時(shí)開啟。為了提高性能,在軟件發(fā)布后,assertion檢查通常是關(guān)閉的。 package com.huawei.interview; public class AssertTest { } /** * @param args */ public static void main(String[] args){ } // TODO Auto-generated method stub int i = 0;for(i=0;i<5;i++){ } //假設(shè)程序不小心多了一句--i;--i;assert i==5; System.out.println(i); 81、java中會存在內(nèi)存泄漏嗎,請簡單描述。 所謂內(nèi)存泄露就是指一個(gè)不再被程序使用的對象或變量一直被占據(jù)在內(nèi)存中。java中有垃圾回收機(jī)制,它可以保證一對象不再被引用的時(shí)候,即對象編程了孤兒的時(shí)候,對象將自動(dòng)被垃圾回收器從內(nèi)存中清除掉。由于Java 使用有向圖的方式進(jìn)行垃圾回收管理,可以消除引用循環(huán)的問題,例如有兩個(gè)對象,相互引用,只要它們和根進(jìn)程不可達(dá)的,那么GC也是可以回收它們的,例如下面的代碼可以看到這種情況的內(nèi)存回收: package com.huawei.interview; import java.io.IOException; public class GarbageTest { private static void gcTest()throws IOException { System.in.read();System.in.read();System.in.read();System.in.read();p1.setMate(p2);p2.setMate(p1);System.out.println(”before exit gctest!“);System.in.read();System.in.read();System.gc(); Person p2 = new Person(); Person p1 = new Person();/** * @param args * @throws IOException */ public static void main(String[] args)throws IOException { } // TODO Auto-generated method stub try { } System.out.println(”has exited gcTest!“);System.in.read();System.in.read(); System.out.println(”out begin gc!“);for(int i=0;i<100;i++){ } System.gc();System.in.read();System.in.read();gcTest();// TODO Auto-generated catch block e.printStackTrace();} catch(IOException e){ } } System.out.println(”exit gctest!");private static class Person { } byte[] data = new byte[20000000];Person mate = null;public void setMate(Person other){ } mate = other; java中的內(nèi)存泄露的情況:長生命周期的對象持有短生命周期對象的引用就很可能發(fā)生內(nèi)存泄露,盡管短生命周期對象已經(jīng)不再需要,但是因?yàn)殚L生命周期對象持有它的引用而導(dǎo)致不能被回收,這就是java中內(nèi)存泄露的發(fā)生場景,通俗地說,就是程序員可能創(chuàng)建了一個(gè)對象,以后一直不再使用這個(gè)對象,這個(gè)對象卻一直被引用,即這個(gè)對象無用但是卻無法被垃圾回收器回收的,這就是java中可能出現(xiàn)內(nèi)存泄露的情況,例如,緩存系統(tǒng),我們加載了一個(gè)對象放在緩存中(例如放在一個(gè)全局map對象中),然后一直不再使用它,這個(gè)對象一直被緩存引用,但卻不再被使用。 檢查java中的內(nèi)存泄露,一定要讓程序?qū)⒏鞣N分支情況都完整執(zhí)行到程序結(jié)束,然后看某個(gè)對象是否被使用過,如果沒有,則才能判定這個(gè)對象屬于內(nèi)存泄露。 如果一個(gè)外部類的實(shí)例對象的方法返回了一個(gè)內(nèi)部類的實(shí)例對象,這個(gè)內(nèi)部類對象被長期引用了,即使那個(gè)外部類實(shí)例對象不再被使用,但由于內(nèi)部類持久外部類的實(shí)例對象,這個(gè)外部類對象將不會被垃圾回收,這也會造成內(nèi)存泄露。 下面內(nèi)容來自于網(wǎng)上(主要特點(diǎn)就是清空堆棧中的某個(gè)元素,并不是徹底把它從數(shù)組中拿掉,而是把存儲的總數(shù)減少,本人寫得可以比這個(gè)好,在拿掉某個(gè)元素時(shí),順便也讓它從數(shù)組中消失,將那個(gè)元素所在的位置的值設(shè)置為null即可): 我實(shí)在想不到比那個(gè)堆棧更經(jīng)典的例子了,以致于我還要引用別人的例子,下面的例子不是我想到的,是書上看到的,當(dāng)然如果沒有在書上看到,可能過一段時(shí)間我自己也想的到,可是那時(shí)我說是我自己想到的也沒有人相信的。 public class Stack { private Object[] elements=new Object[10];private int size = 0;public void push(Object e){ ensureCapacity();elements[size++] = e;} public Object pop(){ if(size == 0) throw new EmptyStackException(); return elements[--size]; } private void ensureCapacity(){ if(elements.length == size){ Object[] oldElements = elements; elements = new Object[2 * elements.length+1]; System.arraycopy(oldElements,0, elements, 0, size); } } } 上面的原理應(yīng)該很簡單,假如堆棧加了10個(gè)元素,然后全部彈出來,雖然堆棧是空的,沒有我們要的東西,但是這是個(gè)對象是無法回收的,這個(gè)才符合了內(nèi)存泄露的兩個(gè)條件:無用,無法回收。 但是就是存在這樣的東西也不一定會導(dǎo)致什么樣的后果,如果這個(gè)堆棧用的比較少,也就浪費(fèi)了幾個(gè)K內(nèi)存而已,反正我們的內(nèi)存都上G了,哪里會有什么影響,再說這個(gè)東西很快就會被回收的,有什么關(guān)系。下面看兩個(gè)例子。 例子1 public class Bad{ public static Stack s=Stack(); static{ s.push(new Object()); s.pop();//這里有一個(gè)對象發(fā)生內(nèi)存泄露 s.push(new Object());//上面的對象可以被回收了,等于是自愈了 } } 因?yàn)槭莝tatic,就一直存在到程序退出,但是我們也可以看到它有自愈功能,就是說如果你的Stack最多有100個(gè)對象,那么最多也就只有100個(gè)對象無法被回收其實(shí)這個(gè)應(yīng)該很容易理解,Stack內(nèi)部持有100個(gè)引用,最壞的情況就是他們都是無用的,因?yàn)槲覀円坏┓判碌倪M(jìn)取,以前的引用自然消失! 內(nèi)存泄露的另外一種情況:當(dāng)一個(gè)對象被存儲進(jìn)HashSet集合中以后,就不能修改這個(gè)對象中的那些參與計(jì)算哈希值的字段了,否則,對象修改后的哈希值與最初存儲進(jìn)HashSet集合中時(shí)的哈希值就不同了,在這種情況下,即使在contains方法使用該對象的當(dāng)前引用作為的參數(shù)去HashSet集合中檢索對象,也將返回找不到對象的結(jié)果,這也會導(dǎo)致無法從HashSet集合中單獨(dú)刪除當(dāng)前對象,造成內(nèi)存泄露。 西安三元數(shù)碼軟件有限公司 外派JAVA軟件工程師筆試題4303 返回上級目錄 選擇題 1:在軟件生命周期中,下列哪個(gè)說法是不準(zhǔn)確的? A.軟件生命周期分為計(jì)劃、開發(fā)和運(yùn)行三個(gè)階段 B.在計(jì)劃階段要進(jìn)行問題焉醛和需求分析 C.在開發(fā)后期要進(jìn)行編寫代碼和軟件測試 D.在運(yùn)行階段主要是進(jìn)行軟件維護(hù) 2:public class Parent { int change(){…} } class Child extends Parent { } Which methods can be added into class Child? A.public int change(){} B.abstract int chang(){} C.private int change(){} D.none 3: 1.Give the following method: 2.public void method(){ 3.String a,b; 4.a=new String(“hello world”);5.b=new String(“game over”);6.System.out.println(a+b+”ok”);7.a=null;8.a=b; 9.System.out.println(a);10.} 11.In the absence of compiler optimization, which is the earliest point the object a refered is definitely elibile to be garbage collection.A.before line 5 B.before line 6 C.before line 7 D.before line 9 4: 1.String s=”Example String”;Which operation is not legal? A.int i=s.length();B.s[3]=”x”; C.String short_s=s.trim();D.String t=”root”+s; 5:關(guān)于垃圾收集的哪些敘述是對的。 A.程序開發(fā)者必須自己創(chuàng)建一個(gè)線程進(jìn)行內(nèi)存釋放的工作。 B.垃圾收集將檢查并釋放不再使用的內(nèi)存。 C.垃圾收集允許程序開發(fā)者明確指定并立即釋放該內(nèi)存。 D.垃圾收集能夠在期望的時(shí)間釋放被java對象使用的內(nèi)存。 6: 1.Give the following code: 2.public class Example{ 3.public static void main(String args[]){ 4.int l=0;5.do{ 6.System.out.println(“Doing it for l is:”+l);7.}while(--l>0) 8.System.out.println(“Finish”);9.} 10.} 11.Which well be output: A.Doing it for l is 3 B.Doing it for l is 1 C.Doing it for l is 2 D.Doing it for l is 0 7: Which of the following statements are true? A.The automatic garbage collection of the JVM prevents programs from ever running out of memory B.A program can suggest that garbage collection be performed and force it C.Garbage collection is platform independent D.An object becomes eligible for garbage collection when all references denoting it are set to null.8:下面關(guān)于變量及其范圍的陳述哪些是錯(cuò)的。 A.實(shí)例變量是類的成員變量。 B.實(shí)例變量用關(guān)鍵字static聲明。 C.在方法中定義的局部變量在該方法被執(zhí)行時(shí)創(chuàng)建 D.局部變量在使用前必須被初始化。 9: 1.Which is the most appropriate code snippet that can be inserted at line 18 in the following code? 2.3.(Assume that the code is compiled and run with assertions enabled)4.5.1.import java.util.*;6.7.2.8.9.3.public class AssertTest 10.11.4.{ 12.13.5.private HashMap cctld;14.15.6.16.17.7.public AssertTest()18.19.8.{ 20.21.9.cctld = new HashMap();22.23.10.cctld.put(“in”, “India”);24.25.11.cctld.put(“uk”, “United Kingdom”);26.27.12.cctld.put(“au”, “Australia”);28.29.13.// more code...30.31.14.} 32.33.15.// other methods....34.35.16.public String getCountry(String countryCode)36.37.17.{ 38.39.18.// What should be inserted here? 40.41.19.String country =(String)cctld.get(countryCode);42.43.20.return country;44.45.21.} 46.47.22.} A.assert countryCode!= null; B.assert countryCode!= null : “Country code can not be null”;C.assert cctld!= null : “No country code data is available”;D.assert cctld : “No country code data is available”;10:在下述選項(xiàng)時(shí),沒有構(gòu)成死循環(huán)的程序是 A.int i=100 while(1){ i=i%100+1;if(i>100)break;} B.for(;;); C.int k=1000;do { ++k;}while(k>=10000);D.int s=36;while(s);--s;11: 1.給出下面的代碼片斷。。下面的哪些陳述為錯(cuò)誤的? 2.1)public void create(){ 3.2)Vector myVect;4.3)myVect = new Vector();5.4)} A.第二行的聲明不會為變量myVect分配內(nèi)存空間。 B.第二行語句創(chuàng)建一個(gè)Vector類對象。 C.第三行語句創(chuàng)建一個(gè)Vector類對象。 D.第三行語句為一個(gè)Vector類對象分配內(nèi)存空間 12:A class design requires that a member variable should be accessible only by same package, which modifer word should be used? A.protected B.public C.no modifer D.private 13: 1.Give the following java source fragement: 2.//point x 3.public class Interesting{ 4.//do something 5.} 6.Which statement is correctly Java syntax at point x? A.public class MyClass{//do other thing…} B.static int PI=3.14 C.class MyClass{//do something…} D.none 14:Which fragments are not correct in Java source file? A.package testpackage;public class Test{//do something...} B.import java.io.*;package testpackage;public class Test{// do something...} C.import java.io.*;class Person{// do something...} public class Test{// do something...} D.import java.io.*;import java.awt.*;public class Test{// do something...} 15:以下的C程序代碼片段運(yùn)行后C和d的值分別是多少 Int a =1,b =2;Int c,d;c =(a&b)&&a;d =(a&&b)&a; A.0,0 B.0,1 C.1,0 D.1,1 16: 1.What will be the result of executing the following code? 2.3.public static void main(String args[])4.{ 5.char digit = 'a'; 6.for(int i = 0;i < 10;i++)7.{ 8.switch(digit)9.{ 10.case 'x' : 11.{ 12.int j = 0;13.System.out.println(j);14.} 15.default : 16.{ 17.int j = 100;18.System.out.println(j);19.} 20.} 21.} 22.int i = j; 23.System.out.println(i);24.} 25.26.Choices: A.100 will be printed 11 times.B.The code will not compile because the variable i cannot be declared twice within the main()method.C.The code will not compile because the variable j cannot be declared twice within the switch statement.D.None of these.17: 1.Give this class outline: 2.class Example{ 3.private int x; 4.//rest of class body… 5.} 6.Assuming that x invoked by the code java Example, which statement can made x be directly accessible in main()method of Example.java? A.Change private int x to public int x B.change private int x to static int x C.Change private int x to protected int x D.change private int x to final int x 18:Which are not Java keywords? A.TRUE B.const C.super D.void 19:設(shè)有變量說明語句int a=1,b=0;則執(zhí)行以下程序段的輸出結(jié)果為()。 switch(a){ case 1: switch(b){ case 0:printf(“**0**”);break;case 1:printf(“**1**”);break;} case 2:printf(“**2**”);break;} printf(“n”); A.**0** B.**0****2** C.**0****1****2** D.有語法錯(cuò)誤 20:軟件生命周期的瀑布模型把軟件項(xiàng)目分為3個(gè)階段、8個(gè)子階段,以下哪一個(gè)是正常的開發(fā)順序? A.計(jì)劃階段、開發(fā)階段、運(yùn)行階段 B.設(shè)計(jì)階段、開發(fā)階段、編碼階段 C.設(shè)計(jì)階段、編碼階段、維護(hù)階段 D.計(jì)劃階段、編碼階段、測試階段 21: 1.What will happen when you attempt to compile and run the following code? 2.3.class Base 4.5.{ 6.7.int i = 99;8.9.public void amethod()10.11.{ 12.13.System.out.println(“Base.amethod()”);14.15.} 16.17.Base()18.19.{ 20.21.amethod();22.23.} 24.25.} 26.27.public class Derived extends Base 28.29.{ 30.31.int i =-1;32.33.34.35.public static void main(String argv[])36.37.{ 38.39.Base b = new Derived();40.41.System.out.println(b.i);42.43.b.amethod();44.45.} 46.47.public void amethod()48.49.{ 50.51.System.out.println(“Derived.amethod()”);52.53.} 54.55.} 56.57.Choices: A.Derived.amethod()-1 Derived.amethod()B.Derived.amethod()99 C.Compile time error D.Derived.amethod()簡答題 22:怎樣在復(fù)雜的各種形式的網(wǎng)頁中提取mp3下載的結(jié)構(gòu)化數(shù)據(jù)? 23:編寫一程序,利用RandomAccessFile類將一個(gè)文件的全部內(nèi)容追加到另一個(gè)文件的末尾。 24:已知abc+cba=1333,其中a,b,c均為一位數(shù),編程求出滿足條件的a,b,c所有組合。 25:servlet的生命周期? 26:Static Inner Class 和 Inner Class的不同,說得越多越好。 27:如果有幾千個(gè)session,怎么提高效率。 28: 1.public class Something { 2.void doSomething(){ 3.private String s = "";4.int l = s.length();5.} 6.} 7.有錯(cuò)嗎? 29:是否可以從一個(gè)static方法內(nèi)部發(fā)出對非static方法的調(diào)用? 30:error和exception有什么區(qū)別? 31:Is Tomcat faster than serving static HTML pages than Apache httpd? 個(gè) 人 簡 歷 模 板 【個(gè)人信息】: 姓名: 年齡: 學(xué)歷: 聯(lián)系電話: 楊** 21歲 本科 138******11 Java軟件工程師 學(xué)習(xí)時(shí)間 2008/9-2012/6 性別: 項(xiàng)目經(jīng)驗(yàn) : 專業(yè): 電子郵箱: 男 一年 計(jì)算機(jī)科學(xué)與技術(shù)y****t@***.com 目標(biāo)地點(diǎn): 專業(yè) 計(jì)算機(jī)科學(xué)與技術(shù) 深圳 上海 北京 【求職意向】: 目標(biāo)職位: 【教育背景】: 學(xué)校名稱 湖南師范大學(xué) 【自我評價(jià)】: 本人有責(zé)任感、學(xué)習(xí)能力強(qiáng)、有上進(jìn)心、具有很強(qiáng)的團(tuán)隊(duì)精神,善于與人溝通,表達(dá)能力良好;喜好編程開發(fā),并且有一定的編程功底,在工作上積極負(fù)責(zé),能夠很好的根據(jù)項(xiàng)目計(jì)劃書完成軟件的開發(fā)。 【技能專長】: 1.熟練使用Jsp,Javabean,Servlet,JDBC等Web開發(fā)技術(shù)進(jìn)行開發(fā) 2.熟練使用HTML、Javascript、Ajax等表現(xiàn)層技術(shù),了解XML; 3.熟悉Struts、Hibernate、Spring等開源框架,熟悉MVC三層架構(gòu)開發(fā)模式; 4.熟練掌握SQL Server 2000/2005、Oracle數(shù)據(jù)庫的操作; 5.熟練使用Eclipse,能夠使用PowerDesigner、Visio等建模工具; 6.熟練掌握Tomcat,了解Jboss; 7.了解C/C++等; 8.在項(xiàng)目開發(fā)過程中善于交流,有良好的開發(fā)及協(xié)同團(tuán)隊(duì)工作能力。 【項(xiàng)目經(jīng)驗(yàn):】: 項(xiàng)目名稱:迅捷物流管理系統(tǒng) 周期:3個(gè)月 開發(fā)工具:Eclipse,PowerDesigner,SVN,Dreamweaver 開發(fā)環(huán)境:Windows xp,Oracle 9g,JDK1.6,Tomcat6.0 開發(fā)人數(shù):6人 技術(shù)框架:Struts + Hibernate + Spring + Ajax + Log4j等 項(xiàng)目描述: 1.使用本系統(tǒng)可以大大提高物流業(yè)務(wù)公司的運(yùn)作效率。通過全面的信息管理與分析,輔助提高物流公司業(yè)務(wù)的決策水平。本系統(tǒng)可以迅速提升公司管理水平,為降低公司運(yùn)營成本,提高效率提供有力的技術(shù)保障。 2.本系統(tǒng)采用B/S模型,采用4層架構(gòu)。分為:視圖層、控制層、業(yè)務(wù)邏輯層和數(shù)據(jù)訪問層,使用Log4j 實(shí)現(xiàn)日志管理和系統(tǒng)異常處理。 主要模塊: 1.客戶服務(wù)(客戶管理、訂單管理、操作員工作量查詢) 2.調(diào)度中心(訂單調(diào)度、任務(wù)單管理) 3.分站管理(分站管理、發(fā)票管理) 4.庫房管理(中心庫房購貨入庫/調(diào)撥出庫、分站庫房調(diào)撥入庫、領(lǐng)/退貨管理) 5.配送管理(進(jìn)/退貨管理、商品管理、庫房管理、供應(yīng)商管理、業(yè)務(wù)統(tǒng)計(jì)查詢) 6.財(cái)務(wù)管理(結(jié)算管理、發(fā)票管理,報(bào)表管理) 項(xiàng)目責(zé)任:參與文檔的編寫和數(shù)據(jù)庫設(shè)計(jì),主要負(fù)責(zé)財(cái)務(wù)管理模塊開發(fā)的功能實(shí)現(xiàn)以及系統(tǒng)的集成測試。 對jfreechart有了更深一步的了解。 項(xiàng)目名稱:聊天室系統(tǒng) 周期:3個(gè)月 開發(fā)工具:Eclipse,PowerDesigner,Dreamweaver 開發(fā)環(huán)境:Windows xp,Oracle 9g,JDK1.6,Tomcat6.0 開發(fā)人數(shù):1人 技術(shù)框架: jsp+ Ajax等 功能描述: 1.登錄模塊: 用戶登錄,包括驗(yàn)證用戶是否在線。 2.管理模塊:實(shí)時(shí)顯示在線人員列表及在線人數(shù)。 3.聊天模塊: 用戶發(fā)言,包括選擇表情和字體顏色功能。 4.退出模塊: 安全退出聊天室。 項(xiàng)目責(zé)任:這個(gè)聊天室系統(tǒng)是我在學(xué)習(xí)了Ajax之后,通過在網(wǎng)上查找資料和使用樂趣聊天室系統(tǒng)后的體會進(jìn)行了文檔和數(shù)據(jù)庫的設(shè)計(jì)及后面的代碼編寫。 個(gè)人簡歷 個(gè)人基本信息姓名:性別:聯(lián)系方式:出生年月: 電子郵箱:畢業(yè)院校:北京化工大學(xué)北方學(xué)院專業(yè):軟件工程學(xué)歷:本科(統(tǒng)招)求職意向 Java軟件開發(fā)工程師 教育背景2008年 9月~2012年 7月北京化工大學(xué)北方學(xué)院軟件工程本科專業(yè)技能? ? ? ? ? ? ? ? ? ? ? 熟練掌握Core Java基礎(chǔ),具有良好的編碼風(fēng)格和編程習(xí)慣;熟練掌握基于Servlet、JSP、HTML的Web編程;熟悉JQuery、Struts2、Hibernate、Spring等應(yīng)用開發(fā)框架及MVC模式;熟悉Ajax,JavaScript,XML,Css等技術(shù); 熟悉JSP頁面上的標(biāo)簽技術(shù)如EL、JSTL;熟悉MySQL、Oracle數(shù)據(jù)庫,熟練書寫基于標(biāo)準(zhǔn)的SQL語句; 了解常用的commons組件(log4j,ant),掌握應(yīng)用log4j記錄日志;熟悉Unix/Linux操作系統(tǒng)的常用命令;熟練使用MyEclipse工具進(jìn)行開發(fā),Tomcat服務(wù)器;熟悉Java設(shè)計(jì)模式:單例模式、工廠模式等;能夠獨(dú)立思考和解決常見問題,有查閱資料解決技術(shù)問題的能力。項(xiàng)目經(jīng)驗(yàn)網(wǎng)上購物系統(tǒng)開發(fā)環(huán)境: Linux, MyEclipse, Tomcat, MySQL 使用技術(shù): Struts2+ Hibernate + JSP + Spring + Jquery + Ajax 等 項(xiàng)目描述: 1.注冊模塊: 使用JQuery和Ajax技術(shù)對表單進(jìn)行驗(yàn)證,struts框架進(jìn)行后臺驗(yàn)證, 注冊成功后向用戶郵箱發(fā)送激活碼。 2.帳號激活: 解析用戶提交的激活碼, 相應(yīng)地修改其激活狀態(tài), 激活后方能登錄。 3.瀏覽商品: 主頁面左邊是商品分類列表, 根據(jù)用戶所選的類別, 分頁顯示所有該類商品。 4.購 物 車: 用戶購買商品后, 生成商品條目添加到購物車中, 并且通過cookie技術(shù)將用戶所購買商品的信息保存到瀏覽器, 如果用戶禁止cookie使用session機(jī)制保存在服務(wù)器, 可以根據(jù)cookie、session恢復(fù)購物車.用戶可以進(jìn)入購物車對商品進(jìn)行增, 刪, 改以及恢復(fù)操作。 5.生成訂單: 用戶必須登錄后才能結(jié)算, 結(jié)算后, 生成訂單, 并且清空購物車以及對應(yīng)的Cookie、session。 6.動(dòng)態(tài)更新: 根據(jù)商品的交易量, 更新網(wǎng)站主頁的 ”熱銷榜”。 責(zé)任描述: 在既有的體系結(jié)構(gòu)設(shè)計(jì)和數(shù)據(jù)表的條件下, 完成所有模塊的編碼和測試。該系 統(tǒng)基于MVC框架,使用JSP完成顯示邏輯, 頁面中使用到了Struts2標(biāo)簽和ognl 表達(dá)式進(jìn)行數(shù)據(jù)的動(dòng)態(tài)綁定, 并且運(yùn)用Ajax異步請求方式完成頁面的局部更新,比如用戶注冊頁面驗(yàn)證,驗(yàn)證碼的更新,商品瀏覽頁面的各個(gè)模塊的更新,模塊 內(nèi)頁面的翻頁。利用Cookie和Session機(jī)制對購物車?yán)锷唐愤M(jìn)行保存,快速選 取送貨地址??刂破饔蒘truts2框架提供支持,通過攔截器、action和XML的搭配很好的處理頁面發(fā)送的請求。通過Hibernate實(shí)現(xiàn)數(shù)據(jù)庫的訪問和數(shù)據(jù)的持久化,提高了程序的靈活性。DAO、工廠模式的應(yīng)用降低了組件之間的聯(lián)系。 采用Spring的IOC和DI技術(shù)實(shí)現(xiàn)頁面以及組件的注入,AOP實(shí)現(xiàn)對日志的記錄、用戶的登錄檢查和事務(wù)管理。 項(xiàng)目心得: 1.對于Struts2,Hibernate,Spring框架和MVC設(shè)計(jì)模式有了更深入的理解。 2.編碼時(shí)不要心急,耐心的完成每一個(gè)方法的邏輯和測試, 步步為營, 增量式開發(fā)。 編碼時(shí), 積極和團(tuán)隊(duì)中的其他成員交流與溝通可以事半功倍。有些問題和細(xì)節(jié)自己 是很難發(fā)現(xiàn), 經(jīng)常是小組談?wù)摃r(shí), 受到隊(duì)友的啟發(fā),順利的解決問題。 其他 1.在線考試系統(tǒng) 2.貪吃蛇 2.簡單相冊 3.五子棋 4.簡單的HTML打字游戲 5.webQQ 培訓(xùn)經(jīng)歷自我評價(jià)2011年6月~2011年11月北京達(dá)內(nèi)科技有限公司Java軟件開發(fā)實(shí)習(xí)生 1.具有一定的邏輯思維能力, 對計(jì)算機(jī)編程有著濃厚的興趣。 2.敢于接受挑戰(zhàn),喜歡鉆研, 具備獨(dú)立解決問題的能力。 3.沉穩(wěn),工欲善其事, 必先利其器, 在寫代碼之前我習(xí)慣花一些時(shí)間將邏輯關(guān)系理順,把一些細(xì)節(jié)考慮清楚, 每一步都盡量做到心里有數(shù)。 4.具有一定的英文閱讀能力,能夠閱讀英文文檔。 5.為人誠懇,熱心,具有團(tuán)隊(duì)合作精神,小組遇到問題時(shí)一起談?wù)?,找到最佳的解決方 案。 6.性格隨和, 樂觀, 懂得及時(shí)釋放壓力, 保持積極飽滿的工作狀態(tài)。 7.經(jīng)過培訓(xùn),技能得到了很大的提升,如果還有機(jī)會充實(shí)自己,我也會非常珍惜。 JAVA筆試題 ? 軟件開發(fā)工程師(JAVA)筆試題 請?jiān)?0分鐘以內(nèi)做答 答案請寫在答題紙上 一、選擇題 1、下面哪項(xiàng)是不合法的標(biāo)識符:(c e)A.$persons B.TwoUsers C.*point D._endline E.final 2、下列運(yùn)算符合法的是(a) A.&& B.<> C.if D.:= 3、下面描述中哪兩項(xiàng)相等:(bg)[選擇兩項(xiàng)] A.<%= YoshiBean.size%> B.<%= YoshiBean.getSize()%> C.<%= YoshiBean.getProperty(“size”)%> D. 4、設(shè)float x = 1,y = 2,z = 3,則表達(dá)式 y+=z--/++x的值是:(a)A.3.5 B.3 C.4 D.5 A.equals()方法判定引用值是否指向同一對象 B.==操作符判定兩個(gè)不同的對象的內(nèi)容和類型是否一致 C.equal()方法只有在兩個(gè)對象的內(nèi)容一致時(shí)返回true D.類File重寫方法equals()在兩個(gè)不同的對象的內(nèi)容和類型一致時(shí)返回true 6、如果一個(gè)對象僅僅聲明實(shí)現(xiàn)了cloneable接口,但是不聲明clone方法,外部能夠調(diào)用其clone方法嗎?(b)A.能 B.不能 C.不確定 7、下列說法錯(cuò)誤的有(bd) A. 能被java.exe成功運(yùn)行的java class文件必須有main()方法 B. J2SDK就是Java API C. Appletviewer.exe可利用jar選項(xiàng)運(yùn)行.jar文件 D. 能被Appletviewer成功運(yùn)行的java class文件必須有main()方法 8、下列正確的有(acd) A. call by value不會改變實(shí)際參數(shù)的數(shù)值 B. call by reference能改變實(shí)際參數(shù)的參考地址 C. call by reference不能改變實(shí)際參數(shù)的參考地址 D. call by reference能改變實(shí)際參數(shù)的內(nèi)容 9、下列說法錯(cuò)誤的有(bcd) A. 數(shù)組是一種對象 B. 數(shù)組屬于一種原生類 C. int number=[]={31,23,33,43,35,63} 5、下面的哪些敘述為真:(d) D. 數(shù)組的大小可以任意改變 10、不能用來修飾interface的有(ad) JAVA筆試題 A.private B.public C.protected D.static 11、關(guān)于Float,下列說法正確的是(a) A.Float是一個(gè)類 B.Float在java.lang包中 C.Float a=1.0是正確的賦值方法 D.Float a= new Float(1.0)是正確的賦值方法 12、下列哪種說法是正確的(d) A. 實(shí)例方法可直接調(diào)用超類的實(shí)例方法 B. 實(shí)例方法可直接調(diào)用超類的類方法 C. 實(shí)例方法可直接調(diào)用其他類的實(shí)例方法 D. 實(shí)例方法可直接調(diào)用本類的類方法 13、下列說法錯(cuò)誤的有(c) A.在類方法中可用this來調(diào)用本類的類方法 B.在類方法中調(diào)用本類的類方法時(shí)可直接調(diào)用 C.在類方法中只能調(diào)用本類中的類方法 D.在類方法中絕對不能調(diào)用實(shí)例方法 14、下面說法哪些是正確的? bd A.Applet可以訪問本地文件 B.對static方法的調(diào)用不需要類實(shí)例 C.socket類在java.lang中 D.127.0.0.1地址代表本機(jī) 1.public class Test1 { 2.public float aMethod(float a, float b)throws 3.IOException { } 4.} 5.public class Test2 extends Test1 { 6.//Line6 7.} 將以下(ac)方法插入行6是不合法的。 A.float aMethod(float a, float b){} B.public int aMethod(int a, int b)throws Exception {} C.public float aMethod(float P, float q){} D.public int aMethod(int a, int b)throws IOException {} 16、關(guān)于以下程序段,正確的說法是:(b) 1.String s1 = “abc” + “def”;2.String s2 = new String(s1);3.if(s1.equals(s2))4.System.out.println(“.equals()succeeded”);5.if(s1 == s2)6.System.out.println(“== succeeded”);A.行4與行6都將執(zhí)行 B.行4執(zhí)行,行6不執(zhí)行 ?? 15、類Test1、Test2定義如下: C.行6執(zhí)行,行4不執(zhí)行 D.行 4、行6都不執(zhí)行 JAVA筆試題 17、下面程序的執(zhí)行結(jié)果為:(a) 1.public class Test { 2.static Boolean foo(char c){ 3.System.out.println(c);4.return true;5.} 6.public static void main(String[] args){ 7.int i = 0;8.for(foo(‘A’);foo(‘B’)&&(i<2);foo(‘C’)){ 9.i++;10.foo(‘D’);11.} 12.} 13.} A.ABDCBDCB B.ABCDABCD C.Compilation fails C.An exception is thrown at runtime 18、閱讀下面的程序 1.public class Outer { 2.public void someOuterMethod(){ 3.//Line3 4.} 5.public class Inner(){} 6.public static void main(String[] args){ 7.Outer o = new Outer();8.//Line8 9.} 10.} Which instantiates is an instance of Inner?(c) A.new Inner();// At line3 B.new Inner();// At line 8 C.new o.Inner();// At line 8 C.new Outer.inner();// At line 8 19、選出能正確賦值的: public class TestA { private int a;return m;public int change(int m){ } } public class TestB extend TestA{ public int b;public static void main(){ TestA aa = new TestA();int k; TestB bb = new TestB(); } } 在Line13處可以正確賦值的有:(d)// Line 13 JAVA筆試題 A.k= m;B.k=b;C.k=aa.a;D.k=bb.change(30);E.k=bb.a 20、已知如下代碼: switch(m){ case 0: System.out.println(“Condition 0”);case 1: System.out.println(“Condition 1”);case 2: System.out.println(“Condition 2”);case 3: System.out.println(“Condition 3”);break;default: System.out.println(“Other Condition”);} 當(dāng) m 的值為什么時(shí)輸出 “Condition 2”?(abc)A.0 B.1 C.2 D.3 E.4 F.None 21、給出程序段 public class Parent { public int addValue(int a,int b){ int s;s=a+b;return s;} } class Child extends Parent{} 可以加在Child類的方法有:(cd)A.int addValue(int a,int b){} B.public void addValue(int a,int b){} C.public int addValue(int a){} D.public int addValue(int a,int b){} 22、下述哪些說法是正確的?(d)A.實(shí)例變量是類的成員變量 B.實(shí)例變量是用static關(guān)鍵字聲明的 C.方法變量在方法執(zhí)行時(shí)創(chuàng)建 D.方法變量在使用之前必須初始化 23、對于下列代碼: public class Sample{ long length; public Sample(long l){ length = l;} public static void main(String arg[]){ Sample s1, s2, s3; s1 = new Sample(21L); s2 = new Sample(21L); s3 = s2; long m = 21L; } } 下列哪些表達(dá)式返回值為'true'?(d) JAVA筆試題 A.s1 = = s2;B.s2 = = s3;C.m = = s1;D.s1.equals(m) 26、當(dāng) Frame 改變大小時(shí),放在其中的按鈕大小不變,則使用如下哪個(gè) layout?(e)A.FlowLayout B.CardLayout C.North and South of BorderLayout D.East and West of BorderLayout E.GridLayout 27、已知如下的命令執(zhí)行 java MyTest a b c 請問哪個(gè)語句是正確的?(cd)A.args[0] = “MyTest a b c” B.args[0] = “MyTest” C.args[0] = “a” D.args[1]= “b” 28、下面哪個(gè)語句是創(chuàng)建數(shù)組的正確語句?(ab)A.float f[][] = new float[6][6];B.float []f[] = new float[6][6];C.float f[][] = new float[][6];D.float [][]f = new float[6][6];E.float [][]f = new float[6][];30、以下關(guān)于數(shù)據(jù)庫范式的描述,哪些是錯(cuò)誤的(c) A.如果把多個(gè)數(shù)據(jù)項(xiàng)用一個(gè)大的 String 表示為一個(gè)字段,則不滿足 private String name;public String getName(){ return name;} public Ball(String name){ this.name = name;} public void play(){ ball = new Ball(“Football”); JAVA筆試題 System.out.println(ball.getName());} } 上面代碼是否有錯(cuò),如果有錯(cuò),錯(cuò)誤在何處? 紅處 2、詳細(xì)解釋下面的語句: Class.class.getClass()Class與class繼承自O(shè)bject,class試題來代表java運(yùn)行時(shí)的class和interface等等 Class.class就是得到或者生成這個(gè)Class類的Class Object 而getClass()本身就是返回一個(gè)類對應(yīng)的Class Object,所以最后Class.class.getClass()最后還是返回Class Object 7、編寫一個(gè)截取字符串的函數(shù),輸入為一個(gè)字符串和字節(jié)數(shù),輸出為按字節(jié)截取的字符串。但是要保證漢字不被截半個(gè),如“我ABC”4,應(yīng)該截為“我AB”,輸入“我ABC漢DEF”,應(yīng)該輸出為“我ABC”而不是“我ABC+漢的半個(gè)”。 public static boolean isLetter(char c){ int k=0X80;return c/k==0?true:false;} public static int lengths(String strSrc){ if(strSrc==null){ return 0;} int len=0;char[] strChar=strSrc.toCharArray();for(int i=0;i JAVA筆試題 public static String subString(String origin,int len){ if(origin==null || origin.equals(“")|| len<1){ return ”“;} if(len>lengths(origin)){ return origin;} byte[] strByte=new byte[len];System.arraycopy(origin.getBytes(),0,strByte,0,len);int count=0;for(int i=0;i } public static void main(String[] args){ System.out.println(”“+ subString(”我ABC漢DEF",6));} 10、SQL問答題 表結(jié)構(gòu): 1、表名:g_cardapply 字段(字段名/類型/長度): g_applyno varchar 8: //申請單號(關(guān)鍵字)g_applydate bigint 8: //申請日期 g_state varchar 2: //申請狀態(tài) 2、表名:g_cardapplydetail 字段(字段名/類型/長度): g_applyno varchar 8: //申請單號(關(guān)鍵字)g_name varchar 30: //申請人姓名 g_idcard varchar 18: //申請人身份證號 g_state varchar 2: //申請狀態(tài) 其中,兩個(gè)表的關(guān)聯(lián)字為申請單號 題目: JAVA筆試題 1、查詢身份證號碼為***082的申請日期 2、查詢同一個(gè)身份證號碼有兩條以上記錄的身份證號碼及記錄個(gè)數(shù) 3、將身份證號碼為***082的記錄在兩個(gè)表中的申請狀態(tài)均改為07 4、刪除g_cardapplydetail表中所有姓李的記錄 1、select g_applydate from g_cardapply a,g_cardapplydetail b where a.g_applyno=b.g_applyno and b.g_idcard=’***082’ 2、select g_idcard,count(g_applyno)from g_cardapplydetail group by g_idcard having count(g_applyno)>2 3、update g_cardapply a,g_cardapplydetail b set a.g_state=’07’,b.g_state=’07’ where a.g_applyno=b.applyno and b.g_idcard=’ ***082’ 4、delete from g_cardapplydetail where g_name like ‘李%’第二篇:java工程師面試題
第三篇:Java軟件開發(fā)工程師個(gè)人簡歷
第四篇:java軟件開發(fā)工程師 簡歷
第五篇:軟件開發(fā)工程師(JAVA)筆試題A