(一)Java部分
1、列舉出JAVA中6個(gè)比較常用的包【天威誠信面試題】
【參考答案】
java.lang;java.util;java.io;java.sql;java.awt;java.net;javax.swing
2、JDK中哪些類(lèi)是不能繼承的?【信雅達面試題】
【參考答案】
不能繼承的是類(lèi)是那些用final關(guān)鍵字修飾的類(lèi)。一般比較基本的類(lèi)型或防止擴展類(lèi)無(wú)意間破壞原來(lái)方法的實(shí)現的類(lèi)型都應該是final的。
3、String是最基本的數據類(lèi)型嗎?【天能智健面試題】
【參考答案】
基本數據類(lèi)型包括byte、int、char、long、float、double、boolean和short。
所以String不屬于基本數據類(lèi)型范疇內,但String屬于最常見(jiàn)一種引用類(lèi)型。
4、short s1 = 1; s1 = s1 + 1;有什么錯? short s1 = 1; s1 += 1;有什么錯?【博炎科技面試題】
【參考答案】
對于short s1 = 1; s1 = s1 + 1;由于s1+1運算時(shí)會(huì )自動(dòng)提升表達式的類(lèi)型,所以結果是int型,再賦值給short類(lèi)型s1時(shí),編譯器會(huì )提示錯誤,需要強制轉換類(lèi)型。
對于short s1 = 1; s1 += 1;由于+=是java語(yǔ)言規定的運算符,Java編譯器會(huì )對它進(jìn)行特殊處理,因此可以正確編譯。
【分析】
主要考查幾種基本數據類(lèi)型在運算時(shí)的,由低到高會(huì )自動(dòng)轉換,而由高到低時(shí)會(huì )強制轉換。
5、Java對象初始化順序?【騰鵬科技面試題】
【參考答案】
分為兩種,一種是本類(lèi)的初始化,一種是含有父類(lèi)的初始化順序。這里分開(kāi)來(lái)說(shuō),
本類(lèi)的初始化順序是:靜態(tài)變量、靜態(tài)初始化塊、變量、初始化塊、構造函數
繼承類(lèi)的初始化順序是:父類(lèi)靜態(tài)變量、父類(lèi)靜態(tài)初始化塊、子類(lèi)靜態(tài)變量、子類(lèi)靜態(tài)初始塊、父類(lèi)變量、父類(lèi)初始化塊、父類(lèi)構造函數、子類(lèi)變量、子類(lèi)初始化塊、子類(lèi)構造函數。
【分析】
static{
System.out.println("靜態(tài)塊");
}
{
System.out.println("初始化模塊"); }
public ClassName() {
System.out.println("構造方法");
}
說(shuō)明:
原則上回答全面的話(huà),應該是完整的說(shuō)出帶有繼承的這種類(lèi)的初始化過(guò)程,下面有個(gè)步驟可以參考:
1.裝載程序的時(shí)候首先找到的是它的基(父)類(lèi),如果有多層基(父)類(lèi)則會(huì )一級一級的往上找最后找到根基(父)類(lèi)。
2.執行根基礎(父)類(lèi)中的static初始化,再執行下一個(gè)衍生類(lèi)中的static,依此類(lèi)推,一直保持這個(gè)順序。
3.此時(shí)類(lèi)已經(jīng)裝載完畢,開(kāi)始創(chuàng )建對象,所有的基本數據類(lèi)型都會(huì )設成它們的默認值,對象句柄設為null
4.調用基礎(父)類(lèi)的構造方法,基礎(父)類(lèi)的構建采用與衍生類(lèi)構造方法完全相同的處理過(guò)程。
5.構造方法初始完之后,進(jìn)行變量的初始化。
6.執行構造方法中剩余的部分。
6、寫(xiě)幾個(gè)線(xiàn)程安全類(lèi),不安全的,支持排序的類(lèi)名?【軟通動(dòng)力面試題】
【參考答案】
?線(xiàn)程安全類(lèi):Vector、Hashtable、Stack。
?線(xiàn)程不安全的類(lèi):ArrayList、Linkedlist、HashSet、TreeSet、HashMap、TreeMap等。
?支持排序的類(lèi)有HashSet、LinkedHashSet、TreeSet等(Set接口下的實(shí)現都支持排序)
【分析】
此題主要考查集合框架的知識。在集合框架中Collection接口為集合的根類(lèi)型,提供集合操作的常用API方法,該接口下派生出兩個(gè)子接口,一個(gè)是不支持排序的List接口,一個(gè)是有自身排序的Set接口,所以回答排序與不排序分別從兩接口的實(shí)現中在作答。線(xiàn)程安全上來(lái)說(shuō),Vector類(lèi)比同屬于List接口的ArrayList要早,是一個(gè)線(xiàn)程安全的類(lèi),在JDK1.2以后才推出一個(gè)異步的ArrayList類(lèi),比Vector類(lèi)效率高。同理Stack繼承自Vector也線(xiàn)程安全的類(lèi),另外在在Map接口的實(shí)現在Hashtable也是個(gè)線(xiàn)程安全的類(lèi)。
7、哪幾個(gè)方法可以實(shí)現一個(gè)線(xiàn)程?【上海華信面試題】
【參考答案】
一是繼承Thread,重寫(xiě)Thread類(lèi)的方法run方法;另種是實(shí)現runnable接口并實(shí)現run方法。
【分析】
考查線(xiàn)程的基本實(shí)現,很多公司喜歡考查這方面知識,另外補充一下關(guān)于線(xiàn)程的run方法,在多線(xiàn)程API中啟動(dòng)一個(gè)線(xiàn)程是調用start()方法,線(xiàn)程進(jìn)入就緒狀態(tài)。
8、STOP()和SUSPEND()不推薦使用的原因?
【參考答案】
stop()是因為它不安全。它會(huì )解除由線(xiàn)程獲取的所有鎖定,當在一個(gè)線(xiàn)程對象上調用stop()方法時(shí),這個(gè)線(xiàn)程對象所運行的線(xiàn)程就會(huì )立即停止,假如一個(gè)線(xiàn)程正在執行:synchronized void { x = 3; y = 4;}由于方法是同步的,多個(gè)線(xiàn)程訪(fǎng)問(wèn)時(shí)總能保證x,y被同時(shí)賦值,而如果一個(gè)線(xiàn)程正在執行到x = 3;時(shí),被調用了stop()方法,即使在同步塊中,它也干脆地stop了,這樣就產(chǎn)生了不完整的殘廢數據。而多線(xiàn)程編程中最最基礎的條件要保證數據的完整性,所以請忘記線(xiàn)程的stop方法,以后我們再也不要說(shuō)“停止線(xiàn)程”了。而且如果對象處于一種不連貫狀態(tài),那么其他線(xiàn)程能在那種狀態(tài)下檢查和修改它們。
suspend()方法容易發(fā)生死鎖。調用suspend()的時(shí)候,目標線(xiàn)程會(huì )停下來(lái),但卻仍然持有在這之前獲得的鎖定。此時(shí),其他任何線(xiàn)程都不能訪(fǎng)問(wèn)鎖定的資源,除非被"掛起"的線(xiàn)程恢復運行。對任何線(xiàn)程來(lái)說(shuō),如果它們想恢復目標線(xiàn)程,同時(shí)又試圖使用任何一個(gè)鎖定的資源,就會(huì )造成死鎖。所以不應該使用suspend(),而應在自己的Thread類(lèi)中置入一個(gè)標志,指出線(xiàn)程應該活動(dòng)還是掛起。若標志指出線(xiàn)程應該掛起,便用wait()命其進(jìn)入等待狀態(tài)。若標志指出線(xiàn)程應當恢復,則用一個(gè)notify()重新啟動(dòng)線(xiàn)程。
【分析】
9、"=="和equals方法有什么區別?【中科軟】
【參考答案】
==操作符專(zhuān)門(mén)用來(lái)比較兩個(gè)變量的值是否相等,也就是用于比較變量所對應的內存中所存儲的數值是否相同,要比較兩個(gè)基本類(lèi)型的數據或兩個(gè)引用變量是否相等,只能用==操作符。
如果一個(gè)變量指向的數據是對象類(lèi)型的,那么,這時(shí)候涉及了兩塊內存,對象本身占用一塊內存(堆內存),變量也占用一塊內存,例如Objet obj = new Object();變量obj是一個(gè)內存,new Object()是另一個(gè)內存,此時(shí),變量obj所對應的內存中存儲的數值就是對象占用的那塊內存的首地址。對于指向對象類(lèi)型的變量,如果要比較兩個(gè)變量是否指向同一個(gè)對象,即要看這兩個(gè)變量所對應的內存中的數值是否相等,這時(shí)候就需要用==操作符進(jìn)行比較。
equals方法是用于比較兩個(gè)獨立對象的內容是否相同,就好比去比較兩個(gè)人的長(cháng)相是否相同,它比較的兩個(gè)對象是獨立的。例如,對于下面的代碼:
String a=new String("foo");
String b=new String("foo");
兩條new語(yǔ)句創(chuàng )建了兩個(gè)對象,然后用a,b這兩個(gè)變量分別指向了其中一個(gè)對象,這是兩個(gè)不同的對象,它們的首地址是不同的,即a和b中存儲的數值是不相同的,所以,表達式a==b將返回false,而這兩個(gè)對象中的內容是相同的,所以,表達式a.equals(b)將返回true。
在實(shí)際開(kāi)發(fā)中,我們經(jīng)常要比較傳遞進(jìn)行來(lái)的字符串內容是否等,例如,String input =…;input.equals(“quit”),如果一個(gè)類(lèi)沒(méi)有自己定義equals方法,那么它將繼承Object類(lèi)的equals方法,Object類(lèi)的equals方法的實(shí)現代碼如下:
boolean equals(Object o){
return this==o;
}
這說(shuō)明,如果一個(gè)類(lèi)沒(méi)有自己定義equals方法,它默認的equals方法(從Object類(lèi)繼承的)就是使用==操作符,也是在比較兩個(gè)變量指向的對象是否是同一對象,這時(shí)候使用equals和使用==會(huì )得到同樣的結果,如果比較的是兩個(gè)獨立的對象則總返回false。如果你編寫(xiě)的類(lèi)希望能夠比較該類(lèi)創(chuàng )建的兩個(gè)實(shí)例對象的內容是否相同,那么你必須覆蓋equals方法,由你自己寫(xiě)代碼來(lái)決定在什么情況即可認為兩個(gè)對象的內容是相同的。
10、靜態(tài)變量和實(shí)例變量的區別?
【參考答案】
在語(yǔ)法定義上的區別:靜態(tài)變量前要加static關(guān)鍵字,而實(shí)例變量前則不加。
在程序運行時(shí)的區別:實(shí)例變量屬于某個(gè)對象的屬性,必須創(chuàng )建了實(shí)例對象,其中的實(shí)例變量才會(huì )被分配空間,才能使用這個(gè)實(shí)例變量。靜態(tài)變量不屬于某個(gè)實(shí)例對象,而是屬于類(lèi),所以也稱(chēng)為類(lèi)變量,只要程序加載了類(lèi)的字節碼,不用創(chuàng )建任何實(shí)例對象,靜態(tài)變量就會(huì )被分配空間,靜態(tài)變量就可以被使用了??傊?,實(shí)例變量必須創(chuàng )建對象后才可以通過(guò)這個(gè)對象來(lái)使用,靜態(tài)變量則可以直接使用類(lèi)名來(lái)引用。
例如,對于下面的程序,無(wú)論創(chuàng )建多少個(gè)實(shí)例對象,永遠都只分配了一個(gè)staticVar變量,并且每創(chuàng )建一個(gè)實(shí)例對象,這個(gè)staticVar就會(huì )加1;但是,每創(chuàng )建一個(gè)實(shí)例對象,就會(huì )分配一個(gè)instanceVar,即可能分配多個(gè)instanceVar,并且每個(gè)instanceVar的值都只自加了1次。
public class VariantTest
{
public static int staticVar = 0;
public int instanceVar = 0;
public VariantTest()
{
staticVar++;
instanceVar++;
System.out.println(“staticVar=”+ staticVar +”,instanceVar=”+ instanceVar);
}
}
備注:這個(gè)解答除了說(shuō)清楚兩者的區別外,最后還用一個(gè)具體的應用例子來(lái)說(shuō)明兩者的差異,體現了自己有很好的解說(shuō)問(wèn)題和設計案例的能力,思維敏捷,超過(guò)一般程序員,有寫(xiě)作能力!
11、構造器的名能不能和類(lèi)的名字相同?
【參考答案】
構造器的名稱(chēng)必須與類(lèi)名相同。
【分析】
構造器或構造函數(有些書(shū)這樣叫)主要用來(lái)對類(lèi)的成員變量進(jìn)行初始化,當類(lèi)創(chuàng )建實(shí)例時(shí)調用。
12、在一個(gè)主方法類(lèi)可不可以調用一個(gè)非靜態(tài)的方法?
【參考答案】
可以調用。因為Java的主方法(main)方法本身也是static類(lèi)型方法,一個(gè)static類(lèi)型方法,發(fā)起對另一個(gè)static方法的調用沒(méi)有問(wèn)題。
【分析】
靜態(tài)方法可以調用其它的靜態(tài)方法,但是不能調用非靜態(tài)方法,這個(gè)好比Java中的類(lèi)變量與實(shí)例變量的關(guān)系。類(lèi)變量是被所有類(lèi)成員共享,而實(shí)例變量只被該實(shí)例共享,
13、一個(gè)類(lèi)中可不可以有2個(gè)公共的方法?
【參考答案】
可以。Java中對公共方法的個(gè)數沒(méi)有約束,但是對公共的類(lèi)有約束,一個(gè)Java源文件中只能定義一個(gè)public類(lèi)型的類(lèi)。
14、GC是什么,為什么要使用它?【阿斯拓】
【參考答案】
GC是垃圾收集的意思(Gabage Collection),內存處理是編程人員容易出現問(wèn)題的地方,忘記或者錯誤的內存回收會(huì )導致程序或系統的不穩定甚至崩潰,Java提供的GC功能可以自動(dòng)監測對象是否超過(guò)作用域,從而達到自動(dòng)回收內存的目的,Java語(yǔ)言沒(méi)有提供釋放已分配內存的顯示操作方法。
【分析】
15、說(shuō)一下垃圾回收的原理,可以直接從內存中回收嗎?
【參考答案】
Java語(yǔ)言中一個(gè)顯著(zhù)的特點(diǎn)就是引入了垃圾回收機制,使c++程序員最頭疼的內存管理的問(wèn)題迎刃而解,它使得Java程序員在編寫(xiě)程序的時(shí)候不再需要考慮內存管理。垃圾回收可以有效的防止內存泄露,有效的使用可以使用的內存。垃圾回收器通常是作為一個(gè)單獨的低級別的線(xiàn)程運行,不可預知的情況下對內存堆中已經(jīng)死亡的或者長(cháng)時(shí)間沒(méi)有使用的對象進(jìn)行清除和回收,程序員不能實(shí)時(shí)的調用垃圾回收器對某個(gè)對象或所有對象進(jìn)行垃圾回收,因為Java語(yǔ)言規范并不保證GC一定會(huì )執行?;厥諜C制有分代復制垃圾回收和標記垃圾回收,增量垃圾回收。
【分析】
16、Java的異常有哪幾種,有什么區別?
【參考答案】
兩大類(lèi),一般異常和運行時(shí)異常。一般異常,這些異常是在定義方法時(shí)聲明拋出的,這些異常必需用try catch拋出,或throws處理,如果不處理,程序將編譯失敗。比如:IOException、FileNotFoundException、SQLException等。
運行時(shí)異常是程序運行時(shí)可能報出的異常??梢杂胻ry catch抓取,也可以不做任何處理。例如:NullPointerException異常就是一種比較常見(jiàn)的運行時(shí)異常。
【分析】
17、switch語(yǔ)句能否作用在byte上,能否作用在long上,能否作用在String上?
【參考答案】
在switch(表達式)中,括號表達式只能是一個(gè)整數表達式或者枚舉常量(更大字體),整數表達式可以是int基本類(lèi)型或Integer包裝類(lèi)型,由于,byte,short,char都可以隱含轉換為int,所以,這些類(lèi)型以及這些類(lèi)型的包裝類(lèi)型也是可以的。顯然,long和String類(lèi)型都不符合switch的語(yǔ)法規定,并且不能被隱式轉換成int類(lèi)型,所以,它們不能作用于swtich語(yǔ)句中。
18、Integer與int的區別?
【參考答案】
int是java提供的8種原始數據類(lèi)型之一,另外Java為每個(gè)原始類(lèi)型提供了封裝類(lèi),Integer是java為int提供的封裝類(lèi)。int的默認值為0,而Integer的默認值為null,即Integer可以區分出未賦值和值為0的區別,int則無(wú)法表達出未賦值的情況。
19、Java Reflection是什么?【】
【參考答案】
JAVA反射,Reflection是Java程序開(kāi)發(fā)語(yǔ)言的特征之一,它允許運行中的Java程序對自身進(jìn)行檢查,或者說(shuō)"自審",并能直接操作程序的內部屬性。
【分析】
20、寫(xiě)幾個(gè)java.lang.Object類(lèi)中的方法名稱(chēng)。
【參考答案】
主要有equals()、toString()、getClass()、hashCode()、clone()、notify()、wait()、notify()方法。
【分析】
這種題能記多少個(gè)就說(shuō)多少個(gè),不一定要求你所有的都記住,但是要理解其中部分重要方法的含義和作用。
21、&和&&的區別?
【參考答案】
&和&&都可以用作邏輯與的運算符,表示邏輯與(and),當運算符兩邊的表達式的結果都為true時(shí),整個(gè)運算結果才為true,否則,只要有一方為false,則結果為false。
&&還具有短路的功能,即如果第一個(gè)表達式為false,則不再計算第二個(gè)表達式。
&還可以用作位運算符,當&操作符兩邊的表達式不是boolean類(lèi)型時(shí),&表示按位與操作,我們通常使用0x0f來(lái)與一個(gè)整數進(jìn)行&運算,來(lái)獲取該整數的最低4個(gè)bit位。
【分析】
先說(shuō)分別說(shuō)兩者的作用,再說(shuō)出&&和&各自的不同之處。
22、數組有沒(méi)有length()這個(gè)方法,String有沒(méi)有length()這個(gè)方法。
【參考答案】
數組沒(méi)有length()方法,但有length屬性
String有length()方法。
【分析】
考查平時(shí)使用數組和字符串的一些細節,一般在使用
23、String s=new String(“xyz”)創(chuàng )建了幾個(gè)對象
【參考答案】
2個(gè)string對象,一個(gè)是=null的s,一個(gè)是=“xyz”的string
兩個(gè)或一個(gè)”xyz”對應一個(gè)對象,這個(gè)對象放在字符串常量緩沖區,常量”xyz”不管出現多少遍,都是緩沖區中的那一個(gè)。New String每寫(xiě)一遍,就創(chuàng )建一個(gè)新的對象,它一句那個(gè)常量”xyz”對象的內容來(lái)創(chuàng )建出一個(gè)新String對象。如果以前就用過(guò)’xyz’,這句代表就不會(huì )創(chuàng )建”xyz”自己了,直接從緩沖區拿。
【分析】
24、能不能自己寫(xiě)個(gè)類(lèi),也叫java.lang.String?
可以,但在應用的時(shí)候,需要用自己的類(lèi)加載器去加載,否則,系統的類(lèi)加載器永遠只是去加載jre.jar包中的那個(gè)java.lang.String。由于在tomcat的web應用程序中,都是由webapp自己的類(lèi)加載器先自己加載WEB-INF/classess目錄中的類(lèi),然后才委托上級的類(lèi)加載器加載,如果我們在tomcat的web應用程序中寫(xiě)一個(gè)java.lang.String,這時(shí)候Servlet程序加載的就是我們自己寫(xiě)的java.lang.String,但是這么干就會(huì )出很多潛在的問(wèn)題,原來(lái)所有用了java.lang.String類(lèi)的都將出現問(wèn)題。
雖然java提供了endorsed技術(shù),可以覆蓋jdk中的某些類(lèi),具體做法是….。但是,能夠被覆蓋的類(lèi)是有限制范圍,反正不包括java.lang這樣的包中的類(lèi)。
例如,運行下面的程序:
package java.lang;
public class String {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("string");
}
}
報告的錯誤如下:
java.lang.NoSuchMethodError: main
Exception in thread "main"
這是因為加載了jre自帶的java.lang.String,而該類(lèi)中沒(méi)有main方法。
25、你對面向對象思想的理解?
【參考答案】
面向對象編程(Object-Oriented Programming)簡(jiǎn)稱(chēng)OOP技術(shù),是開(kāi)發(fā)計算機應用程序的一種新方法、新思想。過(guò)去的面向過(guò)程編程中常常會(huì )導致所有的代碼都包含在幾個(gè)模塊中,使程序難以閱讀和維護,在做一些修改時(shí)常常牽一動(dòng)百,使以后的開(kāi)發(fā)和維護難以為繼。而使用OOP技術(shù),使用許多代碼模塊,每個(gè)模塊都只提供特定的功能,它們是彼此獨立的,可以增加代碼重用的幾率,更加有利于軟件的開(kāi)發(fā)、維護和升級。另外OOP的三大核心特性:繼承、封裝、多態(tài)的特性,使得在面對象編上能夠設計出高內聚、低耦合的系統結構,使得系統更靈活、更容易擴展,而且成本較低,所以這一編程思想是目前一種應用最為普遍的軟件設計思想。
【分析】
26、最常見(jiàn)的runtime exception運行時(shí)異常?
【參考答案】
ClassCastException(類(lèi)型轉換異常)、NumberFormatException(格式化異常)、
ArrayIndexOutOfBoundsException(數組越界異常)、ArithmeticException(算術(shù)異常)、NullPointerException(空指針異常)等等
【分析】
這道題主要考查大家平時(shí)在項目開(kāi)發(fā)過(guò)程中經(jīng)常遇到的一些異常類(lèi)型信息,通過(guò)這些異常來(lái)考查大家的項目經(jīng)驗與項目排錯能力。
27、用JDBC來(lái)實(shí)現訪(fǎng)問(wèn)數據庫記錄可以采用下面的幾個(gè)步驟:
【參考答案】
1、通過(guò)驅動(dòng)器管理器獲取連接接口(Connection)。
2、獲得Statement或它的子類(lèi)。
3、指定Statement中的參數。
4、通過(guò)Statement發(fā)送SQL語(yǔ)句。
5、檢查并處理返回的結果。
6、關(guān)閉Statement。
7、關(guān)閉連接接
【分析】
28、Error和exception的區別與聯(lián)系?
【參考答案】
error表示恢復不是不可能,但很困難的情況下的一種嚴重問(wèn)題。比如說(shuō)內存溢,網(wǎng)絡(luò )故障等,不可能指望程序能處理的一類(lèi)錯誤。
Exception表示一種由程序設計或實(shí)現問(wèn)題,像我們常說(shuō)的異常處理,就是屬于這類(lèi),一般程序可以捕獲和處理這些異常。
【分析】
這道題的難點(diǎn)在Error很多時(shí)候由于我們無(wú)法重現這種Error導致很多同學(xué)甚至不知道Error到底是什么,所以很容易把題目中的兩種錯誤劃上等號。
29、String s = "Hello";s = s + " world!";這兩行代碼執行后,原始的String對象中的內容到底變了沒(méi)有?
【參考答案】
沒(méi)有。因為String被設計成不可變(immutable)類(lèi),所以它的所有對象都是不可變對象。在這段代碼中,s原先指向一個(gè)String對象,內容是"Hello",然后我們對s進(jìn)行了+操作,那么s所指向的那個(gè)對象是否發(fā)生了改變呢?答案是沒(méi)有。這時(shí),s不指向原來(lái)那個(gè)對象了,而指向了另一個(gè)String對象,內容為"Hello world!",原來(lái)那個(gè)對象還存在于內存之中,只是s這個(gè)引用變量不再指向它了。
通過(guò)上面的說(shuō)明,我們很容易導出另一個(gè)結論,如果經(jīng)常對字符串進(jìn)行各種各樣的修改,或者說(shuō),不可預見(jiàn)的修改,那么使用String來(lái)代表字符串的話(huà)會(huì )引起很大的內存開(kāi)銷(xiāo)。因為String對象建立之后不能再改變,所以對于每一個(gè)不同的字符串,都需要一個(gè)String對象來(lái)表示。這時(shí),應該考慮使用StringBuffer類(lèi),它允許修改,而不是每個(gè)不同的字符串都要生成一個(gè)新的對象。并且,這兩種類(lèi)的對象轉換十分容易。
同時(shí),我們還可以知道,如果要使用內容相同的字符串,不必每次都new一個(gè)String。例如我們要在構造器中對一個(gè)名叫s的String引用變量進(jìn)行初始化,把它設置為初始值,應當這樣做:
public class Demo {
private String s;
...
public Demo {
s = "Initial Value";
}
...
}
而非
s = new String("Initial Value");
后者每次都會(huì )調用構造器,生成新對象,性能低下且內存開(kāi)銷(xiāo)大,并且沒(méi)有意義,因為String對象不可改變,所以對于內容相同的字符串,只要一個(gè)String對象來(lái)表示就可以了。也就說(shuō),多次調用上面的構造器創(chuàng )建多個(gè)對象,他們的String類(lèi)型屬性s都指向同一個(gè)對象。
上面的結論還基于這樣一個(gè)事實(shí):對于字符串常量,如果內容相同,Java認為它們代表同一個(gè)String對象。而用關(guān)鍵字new調用構造器,總是會(huì )創(chuàng )建一個(gè)新的對象,無(wú)論內容是否相同。
至于為什么要把String類(lèi)設計成不可變類(lèi),是它的用途決定的。其實(shí)不只String,很多Java標準類(lèi)庫中的類(lèi)都是不可變的。在開(kāi)發(fā)一個(gè)系統的時(shí)候,我們有時(shí)候也需要設計不可變類(lèi),來(lái)傳遞一組相關(guān)的值,這也是面向對象思想的體現。不可變類(lèi)有一些優(yōu)點(diǎn),比如因為它的對象是只讀的,所以多線(xiàn)程并發(fā)訪(fǎng)問(wèn)也不會(huì )有任何問(wèn)題。當然也有一些缺點(diǎn),比如每個(gè)不同的狀態(tài)都要一個(gè)對象來(lái)代表,可能會(huì )造成性能上的問(wèn)題。所以Java標準類(lèi)庫還提供了一個(gè)可變版本,即StringBuffer。
30、Jdk1.5的新特性?
【參考答案】
JDK1.5的一個(gè)重要主題就是通過(guò)新增一些特性來(lái)簡(jiǎn)化開(kāi)發(fā),這些特性主要包括:泛型、ForEach循環(huán)、自動(dòng)裝包/拆包、枚舉、可變參數、靜態(tài)導入這些。
【分析】
31、面向對象的特征有哪些方面?
【參考答案】
面向對象的編程語(yǔ)言有封裝、繼承、多態(tài)等3個(gè)主要的特征。
u封裝
封裝是保證軟件部件具有優(yōu)良的模塊性的基礎,封裝的目標就是要實(shí)現軟件部件的“高內聚、低耦合”,防止程序相互依賴(lài)性而帶來(lái)的變動(dòng)影響。面向對象的封裝就是把描述一個(gè)對象的屬性和行為的代碼封裝在一個(gè)“模塊”中,也就是一個(gè)類(lèi)中,屬性用變量定義,行為用方法進(jìn)行定義,方法可以直接訪(fǎng)問(wèn)同一個(gè)對象中的屬性。
u繼承
在定義和實(shí)現一個(gè)類(lèi)的時(shí)候,可以在一個(gè)已經(jīng)存在的類(lèi)的基礎之上來(lái)進(jìn)行,把這個(gè)已經(jīng)存在的類(lèi)所定義的內容作為自己的內容,并可以加入若干新的內容,或修改原來(lái)的方法使之更適合特殊的需要,這就是繼承。繼承是子類(lèi)自動(dòng)共享父類(lèi)數據和方法的機制,這是類(lèi)之間的一種關(guān)系,提高了軟件的可重用性和可擴展性。
u多態(tài)
多態(tài)是指程序中定義的引用變量所指向的具體類(lèi)型和通過(guò)該引用變量發(fā)出的方法調用在編程時(shí)并不確定,而是在程序運行期間才確定,即一個(gè)引用變量倒底會(huì )指向哪個(gè)類(lèi)的實(shí)例對象,該引用變量發(fā)出的方法調用到底是哪個(gè)類(lèi)中實(shí)現的方法,必須在由程序運行期間才能決定。因為在程序運行時(shí)才確定具體的類(lèi),這樣,不用修改源程序代碼,就可以讓引用變量綁定到各種不同的類(lèi)實(shí)現上,從而導致該引用調用的具體方法隨之改變,即不修改程序代碼就可以改變程序運行時(shí)所綁定的具體代碼,讓程序可以選擇多個(gè)運行狀態(tài),這就是多態(tài)性。多態(tài)性增強了軟件的靈活性和擴展性。
32、JVM工作原理?
運行jvm字符碼的工作是由解釋器來(lái)完成的。解釋執行過(guò)程分三步進(jìn)行:
代碼的裝入、代碼的校驗、和代碼的執行。
裝入代碼的工作由“類(lèi)裝載器class loader”完成。類(lèi)裝載器負責裝入運行一個(gè)程序需要的所有代碼,這也包括程序代碼中的類(lèi)所繼承的類(lèi)和被調用的類(lèi)。當類(lèi)裝載器裝入一個(gè)類(lèi)時(shí),該類(lèi)被放在自己的名字空間中。除了通過(guò)符號引用自己名字空間以外的類(lèi),類(lèi)之間沒(méi)有其他辦法可以影響其他類(lèi)。在本臺計算機的所有類(lèi)都在同一地址空間中,而所有從外部引進(jìn)的類(lèi),都有一個(gè)自己獨立的名字空間。這使得本地類(lèi)通過(guò)共享相同的名字空間獲得較高的運行效率,同時(shí)又保證它們與從外部引進(jìn)的類(lèi)不會(huì )相互影響。當裝入了運行程序需要的所有類(lèi)后,解釋器便可確定整個(gè)可執行程序的內存布局。解釋器為符號引用與特定的地址空間建立對應關(guān)系及查詢(xún)表。通過(guò)在這一階段確定代碼的內布局,java很好地解決了由超類(lèi)改變而使子類(lèi)
崩潰的問(wèn)題,同時(shí)也防止了代碼的非法訪(fǎng)問(wèn)。隨后,被裝入的代碼由字節碼校驗器進(jìn)行檢查。校驗器可以發(fā)現操作數棧益處、非法數據類(lèi)型轉化等多種錯誤。通過(guò)校驗后,代碼便開(kāi)始執行了。
Java字節碼的執行有兩種方式:
1)即時(shí)編譯方式:解釋器先將字節編譯成機器碼,然后再執行該機器碼。
2)解釋執行方式:解釋器通過(guò)每次解釋并執行一小段代碼來(lái)完成java字節。
碼程序的所有操作。
33、說(shuō)說(shuō)Java中的內存分配?
Java把內存分成兩種,一種叫做棧內存,一種叫做堆內存
在函數中定義的一些基本類(lèi)型的變量和對象的引用變量都是在函數的棧內存中分配。當在一段代碼塊中定義一個(gè)變量時(shí),java就在棧中為這個(gè)變量分配內存空間,當超過(guò)變量的作用域后,java會(huì )自動(dòng)釋放掉為該變量分配的內存空間,該內存空間可以立刻被另作它用。
堆內存用于存放由new創(chuàng )建的對象和數組。在堆中分配的內存,由java虛擬機自動(dòng)垃圾回收器來(lái)管理。在堆中產(chǎn)生了一個(gè)數組或者對象后,還可以在棧中定義一個(gè)特殊的變量,這個(gè)變量的取值等于數組或者對象在堆內存中的首地址,在棧中的這個(gè)特殊的變量就變成了數組或者對象的引用變量,以后就可以在程序中使用棧內存中的引用變量來(lái)訪(fǎng)問(wèn)堆中的數組或者對象,引用變量相當于為數組或者對象起的一個(gè)別名,或者代號。
引用變量是普通變量,定義時(shí)在棧中分配內存,引用變量在程序運行到作用域外釋放。而數組&對象本身在堆中分配,即使程序運行到使用new產(chǎn)生數組和對象的語(yǔ)句所在地代碼塊之外,數組和對象本身占用的堆內存也不會(huì )被釋放,數組和對象在沒(méi)有引用變量指向它的時(shí)候,才變成垃圾,不能再被使用,但是仍然占著(zhù)內存,在隨后的一個(gè)不確定的時(shí)間被垃圾回收器釋放掉。這個(gè)也是java比較占內存的主要原因。但是在寫(xiě)程序的時(shí)候,可以人為的控制。
34、final, finally, finalize的區別。
【參考答案】
final用于聲明屬性,方法和類(lèi),分別表示屬性不可變,方法不可覆蓋,類(lèi)不可繼承。
內部類(lèi)要訪(fǎng)問(wèn)局部變量,局部變量必須定義成final類(lèi)型,例如,一段代碼……
finally是異常處理語(yǔ)句結構的一部分,表示總是執行。
finalize是Object類(lèi)的一個(gè)方法,在垃圾收集器執行的時(shí)候會(huì )調用被回收對象的此方法,可以覆蓋此方法提供垃圾收集時(shí)的其他資源回收,例如關(guān)閉文件等。JVM不保證此方法總被調用
35、Extends和Implement的不同?
【參考答案】
extends是繼承父類(lèi),只要那個(gè)類(lèi)不是聲明為final或者那個(gè)類(lèi)定義為abstract的就能繼承,JAVA中不支持多重繼承,但是可以用接口來(lái)實(shí)現,這樣就要用到implements,繼承只能繼承一個(gè)類(lèi),但implements可以實(shí)現多個(gè)接口,用逗號分開(kāi)就行了
比如class A extends B implements C,D,E
36、抽象類(lèi)是否可以沒(méi)有抽象方法?為什么?
【參考答案】
可以在java中用abstract關(guān)鍵字來(lái)修飾一個(gè)類(lèi)時(shí),這個(gè)類(lèi)叫做抽象類(lèi)。
抽象類(lèi)中不一定要包含abstract方法,但一個(gè)類(lèi)中包含了abstract方法,則這個(gè)類(lèi)必須聲明為abstract類(lèi)。
37、靜態(tài)的多態(tài)和動(dòng)態(tài)的多態(tài)的區別?
【參考答案】
靜態(tài)的多態(tài):即為重載;方法名相同,參數個(gè)數或類(lèi)型不相同。(overloading)
動(dòng)態(tài)的多態(tài):即為重寫(xiě);子類(lèi)覆蓋父類(lèi)的方法,將子類(lèi)的實(shí)例傳與父類(lèi)的引用調用的是子類(lèi)的方法實(shí)現接口的實(shí)例傳與接口的引用調用的實(shí)現類(lèi)的方法。
38、說(shuō)出一些常用的類(lèi),包,接口,請各舉5個(gè)?
【參考答案】
常用的類(lèi):String、StringBuffer、Integer、Vector、ArrayList、Hashtable等
常用的包:java.lang java.io java.util、java.sql。
常用的接口:集合中的List、Set、Map接口;與Servlet API相關(guān)的Servlet接口、HttpServletRequest,HttpServletResponse,HttpSession接口等。
39、Collections和Collection的區別【天晟科技】
【參考答案】
Collection是個(gè)java.util下的接口,它是各種集合結構的父接口,定義了集合對象的基本操作方法。Collections是個(gè)java.util下的工具類(lèi),它包含有各種有關(guān)集合操作的靜態(tài)方法,主要是針對集合類(lèi)的一個(gè)幫助類(lèi)或者叫包裝類(lèi),它提供一系列對各種集合的搜索,排序,線(xiàn)程安全化等操作方法。
40、Class.forName的作用?為什么要用?
【參考答案】
按參數中指定的字符串形式的類(lèi)名去搜索并加載相應的類(lèi),如果該類(lèi)字節碼已經(jīng)被加載過(guò),則返回代表該字節碼的Class實(shí)例對象,否則,按類(lèi)加載器的委托機制去搜索和加載該類(lèi),如果所有的類(lèi)加載器都無(wú)法加載到該類(lèi),則拋出ClassNotFoundException。加載完這個(gè)Class字節碼后,接著(zhù)就可以使用Class字節碼的newInstance方法去創(chuàng )建該類(lèi)的實(shí)例對象了。有時(shí)候,我們程序中所有使用的具體類(lèi)名在設計時(shí)(即開(kāi)發(fā)時(shí))無(wú)法確定,只有程序運行時(shí)才能確定,這時(shí)候就需要使用Class.forName去動(dòng)態(tài)加載該類(lèi),這個(gè)類(lèi)名通常是在配置文件中配置的,例如,spring的ioc中每次依賴(lài)注入的具體類(lèi)就是這樣配置的,jdbc的驅動(dòng)類(lèi)名通常也是通過(guò)配置文件來(lái)配置的,以便在產(chǎn)品交付使用后不用修改源程序就可以更換驅動(dòng)類(lèi)名。
41、Socket如何獲取本地ip地址?
【參考答案】
InetAddress類(lèi)提供的API來(lái)訪(fǎng)問(wèn)。InetAddress.getLocalAddress()
【分析】
42、接口是否可繼承接口?抽象類(lèi)是否可實(shí)現(implements)接口?抽象類(lèi)是否可繼承具體類(lèi)【天威誠信面試題】
【參考答案】
接口可以繼承接口。抽象類(lèi)可以實(shí)現(implements)接口,抽象類(lèi)是否可繼承具體類(lèi)。抽象類(lèi)中可以有靜態(tài)的main方法。
備注:只要明白了接口和抽象類(lèi)的本質(zhì)和作用,這些問(wèn)題都很好回答,你想想,如果你是java語(yǔ)言的設計者,你是否會(huì )提供這樣的支持,如果不提供的話(huà),有什么理由嗎?如果你沒(méi)有道理不提供,那答案就是肯定的了。
只有記住抽象類(lèi)與普通類(lèi)的唯一區別就是不能創(chuàng )建實(shí)例對象和允許有abstract方法。
43、用最有效率的方法算出2乘以8等於幾?
【參考答案】
2 << 3
【分析】
因為將一個(gè)數左移n位,就相當于乘以了2的n次方,那么,一個(gè)數乘以8只要將其左移3位即可,而位運算cpu直接支持的,效率最高,所以2乘以8等於幾的最效率的方法是2 << 3。
44、char型變量中能不能存貯一個(gè)中文漢字?為什么?
【參考答案】
char型變量是用來(lái)存儲Unicode編碼的字符的,unicode編碼字符集中包含了漢字,所以,char型變量中當然可以存儲漢字啦。不過(guò),如果某個(gè)特殊的漢字沒(méi)有被包含在unicode編碼字符集中,那么,這個(gè)char型變量中就不能存儲這個(gè)特殊漢字。補充說(shuō)明:unicode編碼占用兩個(gè)字節,所以,char類(lèi)型的變量也是占用兩個(gè)字節。
45、寫(xiě)clone()方法時(shí),通常都有一行代碼,是什么?
【參考答案】
clone有缺省行為,super.clone();因為首先要把父類(lèi)中的成員復制到位,然后才是復制自己的成員。
46、說(shuō)說(shuō)常用集合類(lèi)有哪些?有哪些方法?
【參考答案】
通常我們使用的集合類(lèi)都大多是由List、Set、Map這三類(lèi)接口派生出來(lái)的類(lèi),例如:
ArrayList、Vector、LinkedList、Stack、TreeSet、Hashtable、HashMap等
集合類(lèi)的大部分方法都是由Collection接口定義的,主要包括有:
add(Ee)、remove(Object e)、addAll(),remove()、contains(Object obj)、clear()等
47、請說(shuō)出作用域public,private,protected,以及不寫(xiě)時(shí)的區別?【天威誠信面試題】
【參考答案】
這四個(gè)作用域的可見(jiàn)范圍如下表所示。
說(shuō)明:如果在修飾的元素上面沒(méi)有寫(xiě)任何訪(fǎng)問(wèn)修飾符,則表示friendly。
作用域同一類(lèi)同一package子孫類(lèi)其他package
public√√√√
protected√√√×
friendly√√××
private√×××
備注:只要記住了有4種訪(fǎng)問(wèn)權限,4個(gè)訪(fǎng)問(wèn)范圍,然后將全選和范圍在水平和垂直方向上分別按排從小到大或從大到小的順序排列,就很容易畫(huà)出上面的圖了。
48、構造器Constructor是否可被override?【億陽(yáng)通訊面試題】
【參考答案】
構造器Constructor不能被繼承,因此不能重寫(xiě)Override,但可以被重載Overload。
49、是否可以從一個(gè)static方法內部發(fā)出對非static方法的調用?【世承軟件面試題】
【參考答案】
不可以。因為非static方法是要與對象關(guān)聯(lián)在一起的,必須創(chuàng )建一個(gè)對象后,才可以在該對象上進(jìn)行方法調用,而static方法調用時(shí)不需要創(chuàng )建對象,可以直接調用。
50、Math.round(11.5)等於多少? Math.round(-11.5)等於多少?【霧隱美地傳媒】
【參考答案】
Math類(lèi)中提供了三個(gè)與取整有關(guān)的方法:ceil、floor、round,這些方法的作用與它們的英文名稱(chēng)的含義相對應,例如,ceil的英文意義是天花板,該方法就表示向上取整,所以,Math.ceil(11.3)的結果為12,Math.ceil(-11.3)的結果是-11;floor的英文意義是地板,該方法就表示向下取整,所以,Math.floor(11.6)的結果為11,Math.floor(-11.6)的結果是-12;最難掌握的是round方法,它表示“四舍五入”,算法為Math.floor(x+0.5),即將原來(lái)的數字加上0.5后再向下取整,所以,Math.round(11.5)的結果為12,Math.round(-11.5)的結果為-11。
51、abstract class(抽象類(lèi))和interface(接口)有什么區別?【百度應用中心面試題】
【參考答案】
含有abstract修飾符的class即為抽象類(lèi),abstract類(lèi)不能創(chuàng )建的實(shí)例對象。含有abstract方法的類(lèi)必須定義為abstract class,abstract class類(lèi)中的方法不必是抽象的。abstract class類(lèi)中定義抽象方法必須在具體(Concrete)子類(lèi)中實(shí)現,所以,不能有抽象構造方法或抽象靜態(tài)方法。如果的子類(lèi)沒(méi)有實(shí)現抽象父類(lèi)中的所有抽象方法,那么子類(lèi)也必須定義為abstract類(lèi)型。
接口(interface)可以說(shuō)成是抽象類(lèi)的一種特例,接口中的所有方法都必須是抽象的。接口中的方法定義默認為public abstract類(lèi)型,接口中的成員變量類(lèi)型默認為public static final。
下面比較一下兩者的語(yǔ)法區別:
1.抽象類(lèi)可以有構造方法,接口中不能有構造方法。
2.抽象類(lèi)中可以有普通成員變量,接口中沒(méi)有普通成員變量
3.抽象類(lèi)中可以包含非抽象的普通方法,接口中的所有方法必須都是抽象的,不能有非抽象的普通方法。
4.抽象類(lèi)中的抽象方法的訪(fǎng)問(wèn)類(lèi)型可以是public,protected和(默認類(lèi)型,雖然
eclipse下不報錯,但應該也不行),但接口中的抽象方法只能是public類(lèi)型的,并且默認即為public abstract類(lèi)型。
5.抽象類(lèi)中可以包含靜態(tài)方法,接口中不能包含靜態(tài)方法
6.抽象類(lèi)和接口中都可以包含靜態(tài)成員變量,抽象類(lèi)中的靜態(tài)成員變量的訪(fǎng)問(wèn)類(lèi)型可以任意,但接口中定義的變量只能是public static final類(lèi)型,并且默認即為public static final類(lèi)型。
7.一個(gè)類(lèi)可以實(shí)現多個(gè)接口,但只能繼承一個(gè)抽象類(lèi)。
下面接著(zhù)再說(shuō)說(shuō)兩者在應用上的區別:
【分析】
這道題的思路是先從總體解釋抽象類(lèi)和接口的基本概念,然后再比較兩者的語(yǔ)法細節,最后再說(shuō)兩者的應用區別。比較兩者語(yǔ)法細節區別的條理是:先從一個(gè)類(lèi)中的構造方法、普通成員變量和方法(包括抽象方法),靜態(tài)變量和方法,繼承性等方面來(lái)回答。
52、Collection框架中實(shí)現比較要實(shí)現什么接口?
【參考答案】
Comparable、Comparator接口
53、是否可以繼承String類(lèi)?
【參考答案】
String類(lèi)是final類(lèi)故不可以繼承。
54、String和StringBuffer的區別
【參考答案】
JAVA平臺提供了兩個(gè)類(lèi):String和StringBuffer,它們可以?xún)Υ婧筒僮髯址?,即包含多個(gè)字符的字符數據。String類(lèi)表示內容不可改變的字符串。而StringBuffer類(lèi)表示內容可以被修改的字符串。當你知道字符數據要改變的時(shí)候你就可以使用StringBuffer。典型地,你可以使用StringBuffers來(lái)動(dòng)態(tài)構造字符數據。另外,String實(shí)現了equals方法,new String(“abc”).equals(new String(“abc”)的結果為true,而StringBuffer沒(méi)有實(shí)現equals方法,所以,new StringBuffer(“abc”).equals(new StringBuffer(“abc”)的結果為false。
String覆蓋了equals方法和hashCode方法,而StringBuffer沒(méi)有覆蓋equals方法和hashCode方法,所以,將StringBuffer對象存儲進(jìn)Java集合類(lèi)中時(shí)會(huì )出現問(wèn)題。
55、StringBuffer與StringBuilder的區別
【參考答案】
StringBuffer和StringBuilder類(lèi)都表示內容可以被修改的字符串,StringBuilder是線(xiàn)程不安全的,運行效率高,如果一個(gè)字符串變量是在方法里面定義,這種情況只可能有一個(gè)線(xiàn)程訪(fǎng)問(wèn)它,不存在不安全的因素了,則用StringBuilder。如果要在類(lèi)里面定義成員變量,并且這個(gè)類(lèi)的實(shí)例對象會(huì )在多線(xiàn)程環(huán)境下使用,那么最好用StringBuffer。
56、try {}里有一個(gè)return語(yǔ)句,那么緊跟在這個(gè)try后的finally {}里的code會(huì )不會(huì )被執行,什么時(shí)候被執行,在return前還是后?【杭州天眼科技】
【參考答案】
答案是在return之前。
【分析】
程序代碼的運行結果:
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(new Test().test());;
}
static int test()
{
int x = 1;
try
{
return x;
}
finally
{
++x;
}
}
}
---------執行結果---------
1
運行結果是1,為什么呢?主函數調用子函數并得到結果的過(guò)程,好比主函數準備一個(gè)空罐子,當子函數要返回結果時(shí),先把結果放在罐子里,然后再將程序邏輯返回到主函數。所謂返回,就是子函數說(shuō),我不運行了,你主函數繼續運行吧,這沒(méi)什么結果可言,結果是在說(shuō)這話(huà)之前放進(jìn)罐子里的。
下面的程序代碼輸出的結果是多少?
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 ;
}
}
}
返回的結果是2。
我可以通過(guò)下面一個(gè)例子程序來(lái)幫助我解釋這個(gè)答案,從下面例子的運行結果中可以發(fā)現,try中的return語(yǔ)句調用的函數先于finally中調用的函數執行,也就是說(shuō)return語(yǔ)句先執行,finally語(yǔ)句后執行,所以,返回的結果是2。Return并不是讓函數馬上返回,而是return語(yǔ)句執行后,將把返回結果放置進(jìn)函數棧中,此時(shí)函數并不是馬上返回,它要執行finally語(yǔ)句后才真正開(kāi)始返回。
在講解答案時(shí)可以用下面的程序來(lái)幫助分析:
public class Test {
/**
* @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());;
}
int test()
{
try
{
return func1();
}
finally
{
return func2();
}
}
int func1()
{
System.out.println("func1");
return 1;
}
int func2()
{
System.out.println("func2");
return 2;
}
}
-----------執行結果-----------------
func1
func2
2
結論:finally中的代碼比return和break語(yǔ)句后執行。
57、Java中的異常處理機制的簡(jiǎn)單原理和應用。
【參考答案】
異常是指java程序運行時(shí)(非編譯)所發(fā)生的非正常情況或錯誤,與現實(shí)生活中的事件很相似,現實(shí)生活中的事件可以包含事件發(fā)生的時(shí)間、地點(diǎn)、人物、情節等信息,可以用一個(gè)對象來(lái)表示,Java使用面向對象的方式來(lái)處理異常,它把程序中發(fā)生的每個(gè)異常也都分別封裝到一個(gè)對象來(lái)表示的,該對象中包含有異常的信息。
Java對異常進(jìn)行了分類(lèi),不同類(lèi)型的異常分別用不同的Java類(lèi)表示,所有異常的根類(lèi)為java.lang.Throwable,Throwable下面又派生了兩個(gè)子類(lèi):Error和Exception,Error表示應用程序本身無(wú)法克服和恢復的一種嚴重問(wèn)題,程序只有死的份了,例如,說(shuō)內存溢出和線(xiàn)程死鎖等系統問(wèn)題。Exception表示程序還能夠克服和恢復的問(wèn)題,其中又分為系統異常和普通異常,系統異常是軟件本身缺陷所導致的問(wèn)題,也就是軟件開(kāi)發(fā)人員考慮不周所導致的問(wèn)題,軟件使用者無(wú)法克服和恢復這種問(wèn)題,但在這種問(wèn)題下還可以讓軟件系統繼續運行或者讓軟件死掉,例如,數組腳本越界(ArrayIndexOutOfBoundsException),空指針異常(NullPointerException)、類(lèi)轉換異常(ClassCastException);普通異常是運行環(huán)境的變化或異常所導致的問(wèn)題,是用戶(hù)能夠克服的問(wèn)題,例如,網(wǎng)絡(luò )斷線(xiàn),硬盤(pán)空間不夠,發(fā)生這樣的異常后,程序不應該死掉。
java為系統異常和普通異常提供了不同的解決方案,編譯器強制普通異常必須try..catch處理或用throws聲明繼續拋給上層調用方法處理,所以普通異常也稱(chēng)為checked異常,而系統異??梢蕴幚硪部梢圆惶幚?,所以,編譯器不強制用try..catch處理或用throws聲明,所以系統異常也稱(chēng)為unchecked異常。
58、多線(xiàn)程有幾種實(shí)現方法?同步有幾種實(shí)現方法?
【參考答案】
多線(xiàn)程有兩種實(shí)現方法,分別是繼承Thread類(lèi)與實(shí)現Runnable接口。
同步的實(shí)現方面有兩種,分別是synchronized,wait與notify。
a.wait():使一個(gè)線(xiàn)程處于等待狀態(tài),并且釋放所持有的對象的lock。
b.sleep():使一個(gè)正在運行的線(xiàn)程處于睡眠狀態(tài),是一個(gè)靜態(tài)方法,調用此方法要捕捉InterruptedException異常。
c.notify():喚醒一個(gè)處于等待狀態(tài)的線(xiàn)程,注意的是在調用此方法的時(shí)候,并不能確切的喚醒某一個(gè)等待狀態(tài)的線(xiàn)程,而是由JVM確定喚醒哪個(gè)線(xiàn)程,而且不是按優(yōu)先級。
d.allnotity():喚醒所有處入等待狀態(tài)的線(xiàn)程,注意并不是給所有喚醒線(xiàn)程一個(gè)對象的鎖,而是讓它們競爭。
59、啟動(dòng)一個(gè)線(xiàn)程是用run()還是start()?
【參考答案】
啟動(dòng)一個(gè)線(xiàn)程是調用start()方法,使線(xiàn)程就緒狀態(tài),以后可以被調度為運行狀態(tài),一個(gè)線(xiàn)程必須關(guān)聯(lián)一些具體的執行代碼,run()方法是該線(xiàn)程所關(guān)聯(lián)的執行代碼。
60、內部類(lèi)可以引用外部類(lèi)的成員嗎?有沒(méi)有什么限制?
【參考答案】
完全可以。如果不是靜態(tài)內部類(lèi),那沒(méi)有什么限制!
如果你把靜態(tài)嵌套類(lèi)當作內部類(lèi)的一種特例,那在這種情況下不可以訪(fǎng)問(wèn)外部類(lèi)的普通成員變量,而只能訪(fǎng)問(wèn)外部類(lèi)中的靜態(tài)成員。
61、List和Map區別?【軟通動(dòng)力】
【參考答案】
一個(gè)是存儲單列數據的集合,另一個(gè)是存儲鍵和值這樣的雙列數據的集合,List中存儲的數據是有順序,并且允許重復;Map中存儲的數據是沒(méi)有順序的,其鍵是不能重復的,它的值是可以有重復的。
62、ArrayList和Vector的區別【博炎科技】
【參考答案】
這兩個(gè)類(lèi)都實(shí)現了List接口(List接口繼承了Collection接口),他們都是有序集合,即存儲在這兩個(gè)集合中的元素的位置都是有順序的,相當于一種動(dòng)態(tài)的數組,我們以后可以按位置索引號取出某個(gè)元素,并且其中的數據是允許重復的。
接著(zhù)說(shuō)ArrayList與Vector的區別,這主要包括兩個(gè)方面:
1、同步性:
Vector是線(xiàn)程安全的,也就是說(shuō)是它的方法之間是線(xiàn)程同步的,而ArrayList是線(xiàn)程序不安全的,它的方法之間是線(xiàn)程不同步的。如果只有一個(gè)線(xiàn)程會(huì )訪(fǎng)問(wèn)到集合,那最好是使用ArrayList,因為它不考慮線(xiàn)程安全,效率會(huì )高些;如果有多個(gè)線(xiàn)程會(huì )訪(fǎng)問(wèn)到集合,那最好是使用Vector,因為不需要我們自己再去考慮和編寫(xiě)線(xiàn)程安全的代碼。
備注:對于Vector&ArrayList、Hashtable&HashMap,要記住線(xiàn)程安全的問(wèn)題,記住Vector與Hashtable是舊的,是java一誕生就提供了的,它們是線(xiàn)程安全的,ArrayList與HashMap是java2時(shí)才提供的,它們是線(xiàn)程不安全的。
2、數據增長(cháng):
ArrayList與Vector都有一個(gè)初始的容量大小,當存儲進(jìn)它們里面的元素的個(gè)數超過(guò)了容量時(shí),就需要增加ArrayList與Vector的存儲空間,每次要增加存儲空間時(shí),不是只增加一個(gè)存儲單元,而是增加多個(gè)存儲單元,每次增加的存儲單元的個(gè)數在內存空間利用與程序效率之間要取得一定的平衡。Vector默認增長(cháng)為原來(lái)兩倍,而ArrayList的增長(cháng)為原來(lái)的1.5倍。ArrayList與Vector都可以設置初始的空間大小,Vector還可以設置增長(cháng)的空間大小,而ArrayList沒(méi)有提供設置增長(cháng)空間的方法。
63、heap和stack有什么區別。
【參考答案】
Java的內存分為兩類(lèi),一類(lèi)是棧內存,一類(lèi)是堆內存。棧內存是指程序進(jìn)入一個(gè)方法時(shí),會(huì )為這個(gè)方法單獨分配一塊私屬存儲空間,用于存儲這個(gè)方法內部的局部變量,當這個(gè)方法結束時(shí),分配給這個(gè)方法的棧會(huì )釋放,這個(gè)棧中的變量也將隨之釋放。
堆是與棧作用不同的內存,一般用于存放不放在當前方法棧中的那些數據,例如,使用
new創(chuàng )建的對象都放在堆里,所以,它不會(huì )隨方法的結束而消失。方法中的局部變量使
用final修飾后,放在堆中,而不是棧中。
64、Java類(lèi)實(shí)現序列化的方法(二種)?如在collection框架中實(shí)現排序,要實(shí)現什么樣的接口
【參考答案】
java.io.Serializable接口或實(shí)現Externalizable接口。
Collection框架中實(shí)現比較要實(shí)現Comparable接口或Comparator接口,并實(shí)現比較方法
65、JAVA實(shí)現向數據庫添加一列。
【參考答案】
Connection con = null;
ResultSet rs = null;
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=db_name";
Connection con = DriverManager.getConnection(url,"","");
StateManager sm =con.createStateMent();
String sql = " alter table student add age int; ";
rs = sm.excute(sql);
66、什么是Java序列化,如何實(shí)現java序列化?或者請解釋Serializable接口的作用。【東軟國際】
【參考答案】
序列化就是一種用來(lái)處理對象流的機制,所謂對象流也就是將對象的內容進(jìn)行流化??梢詫α骰蟮膶ο筮M(jìn)行讀寫(xiě)操作,也可將流化后的對象傳輸于網(wǎng)絡(luò )之間。序列化是為了解決在對對象流進(jìn)行讀寫(xiě)操作時(shí)所引發(fā)的問(wèn)題。
序列化的實(shí)現:將需要被序列化的類(lèi)實(shí)現Serializable接口,該接口沒(méi)有需要實(shí)現的方法,implements Serializable只是為了標注該對象是可被序列化的,然后使用一個(gè)輸出流(如:FileOutputStream)來(lái)構造一個(gè)ObjectOutputStream(對象流)對象,使用ObjectOutputStream對象的writeObject(Object obj)方法就可以將參數為obj的對象寫(xiě)出,那么在另一端,通過(guò)ObjectInputStream對象的readObject(Object obj)獲取到字節流數據后,要將字節流轉換成原對象,這叫反序列化,以便將數據存儲在文件中或在網(wǎng)絡(luò )傳輸。
Serializable接口描述啟用其序列化功能,未實(shí)現此接口的類(lèi)將無(wú)法使其任何狀態(tài)序列化或反序列化。Serializable接口沒(méi)有方法或字段,僅用于標識可序列化的語(yǔ)義,標識實(shí)現了該接口的對象屬性可被序列化。
67、Java中有幾種類(lèi)型的流?JDK為每種類(lèi)型的流提供了一些抽象類(lèi)以供繼承,請說(shuō)出他們分別是哪些類(lèi)?
【參考答案】
字節流,字符流兩種類(lèi)型流。字節流繼承于InputStream、OutputStream;字符流繼承于Reader、Writer。其它與IO操作相關(guān)的類(lèi)都是派生至上述4個(gè)抽象類(lèi),如字節相關(guān)的:FileInputStream、FileOutputStream類(lèi);字符相關(guān)的:BufferedReader、BufferedWriter類(lèi)
68、用JDBC如何調用存儲過(guò)程
【參考答案】
通過(guò)JDBC組件中的CallableStatement接口實(shí)現調用存儲過(guò)程。
核心代碼如下:
Class.forName("com.mysql.jdbc.Driver");
Connection conn=
DriverManager.getConnection("jdbc:mysql:///test","root","root");
CallableStatement cstmt = cn.prepareCall("{call insert_Student(?,?,?)}");
cstmt.registerOutParameter(3,Types.INTEGER);
cstmt.setString(1, "wangwu");
cstmt.setInt(2, 25);
cstmt.execute();
69、JAVA事件有哪些模式?
【參考答案】
1、事件直接驅動(dòng)模式。它的特點(diǎn)是直接而且快,是必須經(jīng)常使用的,主要適合于迅速處理前臺的命令,通常就是我們說(shuō)的command(命令)模式。。2.監控式事件模式。主要借助第三者來(lái)監控和觸發(fā)事件,就是通常我們說(shuō)的觀(guān)察者模式。特點(diǎn)是:有一個(gè)觀(guān)察者置身事外在定期獨立運行著(zhù),我們將我們要監聽(tīng)的事件向這個(gè)觀(guān)察者注冊,這樣觀(guān)察者就代替我們來(lái)監聽(tīng)這個(gè)事件,應用客戶(hù)端通過(guò)觀(guān)察者來(lái)獲得事件狀況。
【分析】
70、JVM加載class文件原理?
【參考答案】
所謂裝載就是尋找一個(gè)類(lèi)或是一個(gè)接口的二進(jìn)制形式并用該二進(jìn)制形式來(lái)構造代表這個(gè)類(lèi)或是這個(gè)接口的class對象的過(guò)程.
在Java中,類(lèi)裝載器把一個(gè)類(lèi)裝入Java虛擬機中,要經(jīng)過(guò)三個(gè)步驟來(lái)完成:裝載、鏈接和初始化,其中鏈接又可以分成校驗、準備、解析
裝載:查找和導入類(lèi)或接口的二進(jìn)制數據;
鏈接:執行下面的校驗、準備和解析步驟,其中解析步驟是可以選擇的;
校驗:檢查導入類(lèi)或接口的二進(jìn)制數據的正確性;
準備:給類(lèi)的靜態(tài)變量分配并初始化存儲空間;
解析:將符號引用轉成直接引用;
初始化:激活類(lèi)的靜態(tài)變量的初始化Java代碼和靜態(tài)Java代碼塊
JVM中類(lèi)的裝載是由ClassLoader和它的子類(lèi)來(lái)實(shí)現的,Java ClassLoader是一個(gè)重要的Java運行時(shí)系統組件。它負責在運行時(shí)查找和裝入類(lèi)文件的類(lèi)
一個(gè)Java應用程序使用兩種類(lèi)型的類(lèi)裝載器:根裝載器(bootstrap)和用戶(hù)定義的裝載器(user-defined)。
根裝載器以某種默認的方式將類(lèi)裝入,包括那些Java API的類(lèi)。在運行期間一個(gè)Java程序能安裝用戶(hù)自己定義的類(lèi)裝載器。根裝載器是虛擬機固有的一部分,而用戶(hù)定義的類(lèi)裝載器則不是,它是用Java語(yǔ)言寫(xiě)的,被編譯成class文件之后然后再被裝入到虛擬機,并像其它的任何對象一樣可以被實(shí)例化。Java類(lèi)裝載器的體系結構如下所示:
Bootstrap(根裝載器)
|
Extension (擴展裝載器)
|
System
|
UserDefine1
/
UserDefine2 UserDefine3
|
UserDefine4
Java的類(lèi)裝載模型是一種代理(delegation)模型。當JVM要求類(lèi)裝載器CL(ClassLoader)裝載一個(gè)類(lèi)時(shí),CL首先將這個(gè)類(lèi)裝載請求轉發(fā)給他的父裝載器。只有當父裝載器沒(méi)有裝載并無(wú)法裝載這個(gè)類(lèi)時(shí),CL才獲得裝載這個(gè)類(lèi)的機會(huì )。這樣,所有類(lèi)裝載器的代理關(guān)系構成了一種樹(shù)狀的關(guān)系。樹(shù)的根是類(lèi)的根裝載器(bootstrap ClassLoader) ,在JVM中它以"null"表示。除根裝載器以外的類(lèi)裝載器有且僅有一個(gè)父裝載器。在創(chuàng )建一個(gè)裝載器時(shí),如果沒(méi)有顯式地給出父裝載器,那么JVM將默認系統裝載器為其父裝載器
下面針對各種類(lèi)裝載器分別進(jìn)行詳細的說(shuō)明:
根(Bootstrap)裝載器:該裝載器沒(méi)有父裝載器,它是JVM實(shí)現的一部分,從sun.boot.class.path裝載運行時(shí)庫的核心代碼。
擴展(Extension)裝載器:繼承的父裝載器為根裝載器,不像根裝載器可能與運行時(shí)的操作系統有關(guān),這個(gè)類(lèi)裝載器是用純Java代碼實(shí)現的,它從java.ext.dirs (擴展目錄)中裝載代碼。
系統(System or Application)裝載器:裝載器為擴展裝載器,我們都知道在安裝JDK的時(shí)候要設置環(huán)境變量(CLASSPATH ),這個(gè)類(lèi)裝載器就是從java.class.path(CLASSPATH環(huán)境變量)中裝載代碼的,它也是用純Java代碼實(shí)現的,同時(shí)還是用戶(hù)自定義類(lèi)裝載器的缺省父裝載器。
小應用程序(Applet)裝載器:裝載器為系統裝載器,它從用戶(hù)指定的網(wǎng)絡(luò )上的特定目錄裝載小應用程序代碼。
71、SOCKET中有幾中連接方式,各有什么區別?
【參考答案】
Sockets有兩種主要的操作方式:面向連接(TCP/IP)的和無(wú)連接(UDP)的。無(wú)連接的操作使用數據報協(xié)議,無(wú)連接的操作是快速的和高效的,但是數據安全性不佳.面向連接的操作使用TCP協(xié)議.面向連接的操作比無(wú)連接的操作效率更低,但是數據的安全性更高
【分析】
72、抽象類(lèi)能否被實(shí)例化?抽象類(lèi)的作用是什么?
【參考答案】
抽象類(lèi)一般不能被實(shí)例化;抽象類(lèi)通常不是由程序員定義的,而是由項目經(jīng)理或模塊設計人設計抽象類(lèi)的原因通常是為了規范方法名抽象類(lèi)必須要繼承,不然沒(méi)法用,作為模塊設計者,可以把讓底層程序員直接用得方法直接調用,而一些需要讓程序員覆蓋后自己做得方法則定義稱(chēng)抽象方法
【分析】
73、Linkedlist、Arraylist內部是如何實(shí)現的(更深入的問(wèn)了LinkedList與ArrayList的區別)【天威誠信面試題】
【參考答案】
ArrayList的內部實(shí)現是基于內部數組Object[],它更像是對數組實(shí)現的一種封裝,所以在向ArrayList的前面或中間插入數據時(shí),必須將其后的所有數據相應的后移,這樣必然要花費較多時(shí)間。
而LinkedList的內部實(shí)現是基于一組雙向鏈表實(shí)現的存儲特性,所以提供了鏈表一樣訪(fǎng)問(wèn)的API接口,它們在性能上有很大的差別。當你訪(fǎng)問(wèn)Linkedlist鏈表中的某個(gè)元素時(shí),就必須從鏈表的一端開(kāi)始沿著(zhù)連接方向一個(gè)一個(gè)元素地去查找,直到找到所需的元素為止,所以,當你的操作是在一列數據的前面或中間添加或刪除數據,并且按照順序訪(fǎng)問(wèn)其中的元素時(shí),就應該使用LinkedList了。
而當你的操作是在一列數據的后面添加數據而不是在前面或中間,并且需要隨機地訪(fǎng)問(wèn)其中的元素時(shí),使用ArrayList會(huì )提供比較好的性能。
【分析】
74、Hashtable的原理【北辰網(wǎng)絡(luò )】
【參考答案】
通過(guò)節點(diǎn)的關(guān)鍵碼確定節點(diǎn)的存儲位置,即給定節點(diǎn)的關(guān)鍵碼k,通過(guò)一定的函數關(guān)系H(散列函數),得到函數值H(k),將此值解釋為該節點(diǎn)的存儲地址
75、JDBC中的PreparedStatement相比Statement的好處?
【參考答案】
預編譯語(yǔ)句java.sql.PreparedStatement ,擴展自Statement,不但具有Statement的所有能力而且具有更強大的功能。不同的是,PreparedStatement是在創(chuàng )建語(yǔ)句對象的同時(shí)給出要執行的sql語(yǔ)句。這樣,sql語(yǔ)句就會(huì )被系統進(jìn)行預編譯,執行的速度會(huì )有所增加,尤其是在執行大語(yǔ)句的時(shí)候,效果更加理想
76、sleep()和wait()區別
【參考答案】
sleep()方法:線(xiàn)程主動(dòng)放棄CPU,使得線(xiàn)程在指定的時(shí)間內進(jìn)入阻塞狀態(tài),不能得到CPU時(shí)間,指定的時(shí)間一過(guò),線(xiàn)程重新進(jìn)入可執行狀態(tài)。典型地,sleep()被用在等待某個(gè)資源就緒的情形:測試發(fā)現條件不滿(mǎn)足后,讓線(xiàn)程阻塞一段時(shí)間后重新測試,直到條件滿(mǎn)足為止。
wait( ):與notify()配套使用,wait()使得線(xiàn)程進(jìn)入阻塞狀態(tài),它有兩種形式,一種允許指定以毫秒為單位的一段時(shí)間作為參數,另一種沒(méi)有參數,當指定時(shí)間參數時(shí)對應的notify()被調用或者超出指定時(shí)間時(shí)線(xiàn)程重新進(jìn)入可執行狀態(tài),后者則必須對應的notify()被調用
(網(wǎng)上的答案:sleep是線(xiàn)程類(lèi)(Thread)的方法,導致此線(xiàn)程暫停執行指定時(shí)間,給執行機會(huì )給其他線(xiàn)程,但是監控狀態(tài)依然保持,到時(shí)后會(huì )自動(dòng)恢復。調用sleep不會(huì )釋放對象鎖。wait是Object類(lèi)的方法,對此對象調用wait方法導致本線(xiàn)程放棄對象鎖,進(jìn)入等待此對象的等待鎖定池,只有針對此對象發(fā)出notify方法(或notifyAll)后本線(xiàn)程才進(jìn)入對象鎖定池準備獲得對象鎖進(jìn)入運行狀態(tài)。)
sleep就是正在執行的線(xiàn)程主動(dòng)讓出cpu,cpu去執行其他線(xiàn)程,在sleep指定的時(shí)間過(guò)后,cpu才會(huì )回到這個(gè)線(xiàn)程上繼續往下執行,如果當前線(xiàn)程進(jìn)入了同步鎖,sleep方法并不會(huì )釋放鎖,即使當前線(xiàn)程使用sleep方法讓出了cpu,但其他被同步鎖擋住了的線(xiàn)程也無(wú)法得到執行。wait是指在一個(gè)已經(jīng)進(jìn)入了同步鎖的線(xiàn)程內,讓自己暫時(shí)讓出同步鎖,以便其他正在等待此鎖的線(xiàn)程可以得到同步鎖并運行,只有其他線(xiàn)程調用了notify方法(notify并不釋放鎖,只是告訴調用過(guò)wait方法的線(xiàn)程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因為鎖還在別人手里,別人還沒(méi)釋放。如果notify方法后面的代碼還有很多,需要這些代碼執行完后才會(huì )釋放鎖,可以在notfiy方法后增加一個(gè)等待和一些代碼,看看效果),調用wait方法的線(xiàn)程就會(huì )解除wait狀態(tài)和程序可以再次得到鎖后繼續向下運行。對于wait的講解一定要配合例子代碼來(lái)說(shuō)明,才顯得自己真明白。
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);
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Thread(new Thread2()).start();
}
private static class Thread1 implements Runnable
{
@Override
public void run() {
// TODO Auto-generated method stub
//由于這里的Thread1和下面的Thread2內部run方法要用同一對象作為監視器,我們這里不能用this,因為在Thread2里面的this和這個(gè)Thread1的this不是同一個(gè)對象。我們用MultiThread.class這個(gè)字節碼對象,當前虛擬機里引用這個(gè)變量時(shí),指向的都是同一個(gè)對象。
synchronized (MultiThread.class) {
System.out.println("enter thread1...");
System.out.println("thread1 is waiting");
try {
//釋放鎖有兩種方式,第一種方式是程序自然離開(kāi)監視器的范圍,也就是離開(kāi)了synchronized關(guān)鍵字管轄的代碼范圍,另一種方式就是在synchronized關(guān)鍵字管轄的代碼內部調用監視器對象的wait方法。這里,使用wait方法釋放鎖。
MultiThread.class.wait();
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("thread1 is going on...");
System.out.println("thread1 is being over!");
}
}
}
private static class Thread2 implements Runnable
{
@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調用下面的sleep方法休息了10毫秒,但thread1仍然不會(huì )執行,因為thread2沒(méi)有釋放鎖,所以Thread1無(wú)法得不到鎖。
MultiThread.class.notify();
System.out.println("thread2 is sleeping ten millisecond...");
try {
Thread.sleep(10);
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("thread2 is going on...");
System.out.println("thread2 is being over!");
}
}
}
})
77、概述反射和序列化
【參考答案】
Reflection:是Java被視為動(dòng)態(tài)語(yǔ)言的一個(gè)關(guān)鍵性質(zhì)。這個(gè)機制允許程序在運行時(shí)透過(guò)Reflection APIs取得任何一個(gè)已知名稱(chēng)的class的內部信息,包括其modifiers(諸如public, static等等)、superclass(例如Object)、實(shí)現之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于運行時(shí)改變fields內容或喚起methods。
序列化:就是一種用來(lái)處理對象流的機制,所謂對象流也就是將對象的內容進(jìn)行流化??梢詫α骰蟮膶ο筮M(jìn)行讀寫(xiě)操作,也可將流化后的對象傳輸于網(wǎng)絡(luò )之間。序列化是為了解決在對對象流進(jìn)行讀寫(xiě)操作時(shí)的問(wèn)題。
78、Java中實(shí)現多態(tài)的機制是什么?
【參考答案】
重寫(xiě),重載
方法的重寫(xiě)Overriding和重載Overloading是Java多態(tài)性的不同表現。
重寫(xiě)Overriding是父類(lèi)與子類(lèi)之間多態(tài)性的一種表現,重載Overloading是一個(gè)類(lèi)中多態(tài)性的一種表現。如果在子類(lèi)中定義某方法與其父類(lèi)有相同的名稱(chēng)和參數,我們說(shuō)該方法被重寫(xiě)(Overriding)。子類(lèi)的對象使用這個(gè)方法時(shí),將調用子類(lèi)中的定義,對它而言,父類(lèi)中的定義如同被“屏蔽”了。
果在一個(gè)類(lèi)中定義了多個(gè)同名的方法,它們或有不同的參數個(gè)數或有不同的參數類(lèi)型,則稱(chēng)為方法的重載(Overloading)。Overloaded的方法是可以改變返回值的類(lèi)型。
79、Overload和Override的區別?Overloaded的方法是否可以改變返回值的類(lèi)型?【軟通動(dòng)力】
【參考答案】
Overload是重載的意思,Override是覆蓋的意思,也就是重寫(xiě)。
重載Overload表示同一個(gè)類(lèi)中可以有多個(gè)名稱(chēng)相同的方法,但這些方法的參數列表各不相同(即參數個(gè)數或類(lèi)型不同)。
重寫(xiě)Override表示子類(lèi)中的方法可以與父類(lèi)中的某個(gè)方法的名稱(chēng)和參數完全相同,通過(guò)子類(lèi)創(chuàng )建的實(shí)例對象調用這個(gè)方法時(shí),將調用子類(lèi)中的定義方法,這相當于把父類(lèi)中定義的那個(gè)完全相同的方法給覆蓋了,這也是面向對象編程的多態(tài)性的一種表現。子類(lèi)覆蓋父類(lèi)的方法時(shí),只能比父類(lèi)拋出更少的異常,或者是拋出父類(lèi)拋出的異常的子異常,因為子類(lèi)可以解決父類(lèi)的一些問(wèn)題,不能比父類(lèi)有更多的問(wèn)題。子類(lèi)方法的訪(fǎng)問(wèn)權限只能比父類(lèi)的更大,不能更小。如果父類(lèi)的方法是private類(lèi)型,那么,子類(lèi)則不存在覆蓋的限制,相當于子類(lèi)中增加了一個(gè)全新的方法。
是否可以改變返回值類(lèi)型,在重載的定義中,與方法是什么類(lèi)型返回值無(wú)關(guān)。
【分析】
override可以翻譯為覆蓋,從字面就可以知道,它是覆蓋了一個(gè)方法并且對其重寫(xiě),以求達到不同的作用。對我們來(lái)說(shuō)最熟悉的覆蓋就是對接口方法的實(shí)現,在接口中一般只是對方法進(jìn)行了聲明,而我們在實(shí)現時(shí),就需要實(shí)現接口聲明的所有方法。除了這個(gè)典型的用法以外,我們在繼承中也可能會(huì )在子類(lèi)覆蓋父類(lèi)中的方法。在覆蓋要注意以下的幾點(diǎn):
1、覆蓋的方法的標志必須要和被覆蓋的方法的標志完全匹配,才能達到覆蓋的效果;
2、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;
3、覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類(lèi);
4、被覆蓋的方法不能為private,否則在其子類(lèi)中只是新定義了一個(gè)方法,并沒(méi)有對其進(jìn)行覆蓋。
overload對我們來(lái)說(shuō)可能比較熟悉,可以翻譯為重載,它是指我們可以定義一些名稱(chēng)相同的方法,通過(guò)定義不同的輸入參數來(lái)區分這些方法,然后再調用時(shí),VM就會(huì )根據不同的參數樣式,來(lái)選擇合適的方法執行。在使用重載要注意以下的幾點(diǎn):
1、在使用重載時(shí)只能通過(guò)不同的參數樣式。例如,不同的參數類(lèi)型,不同的參數個(gè)數,不同的參數順序(當然,同一方法內的幾個(gè)參數類(lèi)型必須不一樣,例如可以是fun(int,float),但是不能為fun(int,int));
2、不能通過(guò)訪(fǎng)問(wèn)權限、返回類(lèi)型、拋出的異常進(jìn)行重載;
3、方法的異常類(lèi)型和數目不會(huì )對重載造成影響;
4、對于繼承來(lái)說(shuō),如果某一方法在父類(lèi)中是訪(fǎng)問(wèn)權限是priavte,那么就不能在子類(lèi)對其進(jìn)行重載,如果定義的話(huà),也只是定義了一個(gè)新方法,而不會(huì )達到重載的效果。
80、ClassLoader如何加載class。
【參考答案】
jvm里有多個(gè)類(lèi)加載,每個(gè)類(lèi)加載可以負責加載特定位置的類(lèi),例如,bootstrap類(lèi)加載負責加載jre/lib/rt.jar中的類(lèi),我們平時(shí)用的jdk中的類(lèi)都位于rt.jar中。extclassloader負責加載jar/lib/ext/*.jar中的類(lèi),appclassloader負責classpath指定的目錄或jar中的類(lèi)。除了bootstrap之外,其他的類(lèi)加載器本身也都是java類(lèi),它們的父類(lèi)是ClassLoader。
81、ArrayList如何實(shí)現插入的數據按自定義的方式有序存放
【參考答案】
實(shí)現Comparable比較接口,并實(shí)現compareTo方法。排序的方法,取決于compareTo方法中的比較定義的返回值,一般有3個(gè)返回值:1、-1、0表示不同的比較結果。
程序示例:
class MyBean implementsComparable{
public intcompareTo(Object obj){
if(! obj instanceof MyBean)
throw new ClassCastException();
MyBean other = (MyBean) obj;
return age > other.age?1:age== other.age?0:-1;
}
}
class MyTreeSet {
private ArrayList datas = new ArrayList();
public void add(Object obj){
for(int i=0;i
if(obj.compareTo(datas.get(i) != 1){
datas.add(i,obj);
}
}
}
}
82、hashCode方法的作用?
【參考答案】
hashcode這個(gè)方法是用來(lái)鑒定2個(gè)對象是否相等的。hashcode方法一般用戶(hù)不會(huì )去調用,比如在hashmap中,由于key是不可以重復的,他在判斷key是不是重復的時(shí)候就判斷了hashcode這個(gè)方法,而且也用到了equals方法。這里不可以重復是說(shuō)equals和hashcode只要有一個(gè)不等就可以了!所以簡(jiǎn)單來(lái)講,hashcode相當于是一個(gè)對象的編碼。我們一般在覆蓋equals的同時(shí)也要覆蓋hashcode,讓他們的邏輯一致。
83、abstract的method是否可同時(shí)是static,是否可同時(shí)是native,是否可同時(shí)是synchronized?
【參考答案】
abstract的method不可以是static的,因為抽象的方法是要被子類(lèi)實(shí)現的,而static與子類(lèi)扯不上關(guān)系!
native方法表示該方法要用另外一種依賴(lài)平臺的編程語(yǔ)言實(shí)現的,不存在著(zhù)被子類(lèi)實(shí)現的問(wèn)題,所以,它也不能是抽象的,不能與abstract混用。例如,FileOutputSteam類(lèi)要硬件打交道,底層的實(shí)現用的是操作系統相關(guān)的api實(shí)現,例如,在windows用c語(yǔ)言實(shí)現的,所以,查看jdk的源代碼,可以發(fā)現FileOutputStream的open方法的定義如下:
private native void open(String name) throws FileNotFoundException;
如果我們要用java調用別人寫(xiě)的c語(yǔ)言函數,我們是無(wú)法直接調用的,我們需要按照java的要求寫(xiě)一個(gè)c語(yǔ)言的函數,又我們的這個(gè)c語(yǔ)言函數去調用別人的c語(yǔ)言函數。由于我們的c語(yǔ)言函數是按java的要求來(lái)寫(xiě)的,我們這個(gè)c語(yǔ)言函數就可以與java對接上,java那邊的對接方式就是定義出與我們這個(gè)c函數相對應的方法,java中對應的方法不需要寫(xiě)具體的代碼,但需要在前面聲明native。
關(guān)于synchronized與abstract合用的問(wèn)題,我覺(jué)得也不行,因為在我幾年的學(xué)習和開(kāi)發(fā)中,從來(lái)沒(méi)見(jiàn)到過(guò)這種情況,并且我覺(jué)得synchronized應該是作用在一個(gè)具體的方法上才有意義。而且,方法上的synchronized同步所使用的同步鎖對象是this,而抽象方法上無(wú)法確定this是什么。
84、Anonymous Inner Class (匿名內部類(lèi))是否可以extends(繼承)其它類(lèi),是否可以implements(實(shí)現)interface(接口)?
【參考答案】
可以繼承其他類(lèi)或實(shí)現其他接口。不僅是可以,而是必須!
85、JAVA語(yǔ)言如何進(jìn)行異常處理,關(guān)鍵字:throws,throw,try,catch,finally分別代表什么意義?在try塊中可以?huà)伋霎惓幔?/span>
【參考答案】
Java使用面向對象的方式來(lái)處理異常,它把程序中發(fā)生的每個(gè)異常也都分別封裝到一個(gè)對象來(lái)表示的,該對象中包含有異常的信息。而throws hrow ry、catch、finally就是Java中用來(lái)對異常進(jìn)行處理的幾個(gè)關(guān)鍵字,在Java編程中規容Java編譯器強制普通異常必須try..catch處理或用throws聲明繼續拋給上層調用方法處理,一般異常必須要求被捕獲和處理,而系統異??梢蕴幚硪部梢圆惶幚?,所以編譯器不強制用try..catch處理或用throws、throw聲明異常。而finally一般與try或trycatch一起使用做為異常的最后處理出口。
86、同步和異步有何異同,在什么情況下分別使用他們?舉例說(shuō)明。
【參考答案】
如果數據將在線(xiàn)程間共享。例如正在寫(xiě)的數據以后可能被另一個(gè)線(xiàn)程讀到,或者正在讀的數據可能已經(jīng)被另一個(gè)線(xiàn)程寫(xiě)過(guò)了,那么這些數據就是共享數據,必須進(jìn)行同步存取。
當應用程序在對象上調用了一個(gè)需要花費很長(cháng)時(shí)間來(lái)執行的方法,并且不希望讓程序等待方法的返回時(shí),就應該使用異步編程,在很多情況下采用異步途徑往往更有效率。
87、當一個(gè)線(xiàn)程進(jìn)入一個(gè)對象的一個(gè)synchronized方法后,其它線(xiàn)程是否可進(jìn)入此對象的其它方法?
【參考答案】
分幾種情況:
1.其他方法前是否加了synchronized關(guān)鍵字,如果沒(méi)加,則能。
2.如果這個(gè)方法內部調用了wait,則可以進(jìn)入其他synchronized方法。
3.如果其他個(gè)方法都加了synchronized關(guān)鍵字,并且內部沒(méi)有調用wait,則不能。
4.如果其他方法是static,它用的同步鎖是當前類(lèi)的字節碼,與非靜態(tài)的方法不能同步,因為非靜態(tài)的方法用的是this。
88、線(xiàn)程的基本概念、線(xiàn)程的基本狀態(tài)以及狀態(tài)之間的關(guān)系
【參考答案】
一個(gè)程序中可以有多條執行線(xiàn)索同時(shí)執行,一個(gè)線(xiàn)程就是程序中的一條執行線(xiàn)索,每個(gè)線(xiàn)程上都關(guān)聯(lián)有要執行的代碼,即可以有多段程序代碼同時(shí)運行,每個(gè)程序至少都有一個(gè)線(xiàn)程,即main方法執行的那個(gè)線(xiàn)程。如果只是一個(gè)cpu,它怎么能夠同時(shí)執行多段程序呢?這是從宏觀(guān)上來(lái)看的,cpu一會(huì )執行a線(xiàn)索,一會(huì )執行b線(xiàn)索,切換時(shí)間很快,給人的感覺(jué)是a,b在同時(shí)執行,好比大家在同一個(gè)辦公室上網(wǎng),只有一條鏈接到外部網(wǎng)線(xiàn),其實(shí),這條網(wǎng)線(xiàn)一會(huì )為a傳數據,一會(huì )為b傳數據,由于切換時(shí)間很短暫,所以,大家感覺(jué)都在同時(shí)上網(wǎng)。
狀態(tài):就緒,運行,synchronize阻塞,wait和sleep掛起,結束。wait必須在synchronized內部調用。
調用線(xiàn)程的start方法后線(xiàn)程進(jìn)入就緒狀態(tài),線(xiàn)程調度系統將就緒狀態(tài)的線(xiàn)程轉為運行狀態(tài),遇到synchronized語(yǔ)句時(shí),由運行狀態(tài)轉為阻塞,當synchronized獲得鎖后,由阻塞轉為運行,在這種情況可以調用wait方法轉為掛起狀態(tài),當線(xiàn)程關(guān)聯(lián)的代碼執行完后,線(xiàn)程變?yōu)榻Y束狀態(tài)。
89、簡(jiǎn)述synchronized和java.util.concurrent.locks.Lock的異同?
【參考答案】
主要相同點(diǎn):Lock能完成synchronized所實(shí)現的所有功能
主要不同點(diǎn):Lock有比synchronized更精確的線(xiàn)程語(yǔ)義和更好的性能。synchronized會(huì )自動(dòng)釋放鎖,而Lock一定要求程序員手工釋放,并且必須在finally從句中釋放。Lock還有更強大的功能,例如,它的tryLock方法可以非阻塞方式去拿鎖。
90、HashMap和Hashtable的區別?【北通網(wǎng)科】
【參考答案】
HashMap是Hashtable的輕量級實(shí)現(非線(xiàn)程安全的實(shí)現),他們都實(shí)現Map接口,主要區別在于HashMap允許空(null)鍵值(key),由于非線(xiàn)程安全,在只有一個(gè)線(xiàn)程訪(fǎng)問(wèn)的情況下,效率要高于Hashtable。
HashMap允許將null作為一個(gè)entry的key或者value,而Hashtable不允許。
HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因為contains方法容易讓人引起誤解。
Hashtable繼承自Dictionary類(lèi),而HashMap是Java1.2引進(jìn)的Map interface的一個(gè)實(shí)現。
最大的不同是,Hashtable的方法是synchronized的,而HashMap不是,在多個(gè)線(xiàn)程訪(fǎng)問(wèn)Hashtable時(shí),不需要自己為它的方法實(shí)現同步,而HashMap就必須為之提供外同步。
Hashtable和HashMap采用的hash/rehash算法都大概一樣,所以性能不會(huì )有很大的差異。
91、List、Set、Map是否繼承自Collection接口?
【參考答案】
List、Set是,Map不是;Map接口定義的是Key-Value存儲的特性,與List和Set不同,Map在存儲對象時(shí),先要定義這個(gè)對象的key的值,再存入與這個(gè)key相對應的Object,Map集合的取值時(shí)根據存入的key(關(guān)鍵字)來(lái)獲取與這個(gè)關(guān)鍵字對應的對象。
92、List、Map、Set三個(gè)接口,存取元素時(shí),各有什么特點(diǎn)?
【參考答案】
首先,List與Set具有相似性,它們都是單列元素的集合,所以,它們有一個(gè)功共同的父接口Collection接口。Set里面不允許有重復的元素,即不能有兩個(gè)相等的對象。
List表示有先后順序的集合,當我們多次調用add(Obj e)方法時(shí),每次加入的對象就像火車(chē)站買(mǎi)票有排隊順序一樣,按先來(lái)后到的順序排序。
Map與List和Set不同,它是雙列的集合每次存儲時(shí),要存儲一對key/value,不能存儲重復的key,這個(gè)重復的規則也是按equals比較相等。取則可以根據key獲得相應的value,即get(Object key)返回值為key所對應的value。另外,也可以獲得所有的key的結合。
【分析】
總結:List以特定次序來(lái)持有元素,可有重復元素。Set無(wú)法擁有重復元素,內部排序。Map保存key-value值,value可多值。上面是大致不同,另外上述3個(gè)只是接口,而具體實(shí)現類(lèi)中,用法大同小異,只是實(shí)現的數據結構不同,例如List接口下的LinkedList主要實(shí)現了雙鏈表的存儲特點(diǎn),Vector是線(xiàn)程安全的集合類(lèi)。
93、說(shuō)出ArrayList,Vector, LinkedList的存儲性能和特性?!?/span>大唐動(dòng)力面試題】
【參考答案】
ArrayList和Vector都是使用數組方式存儲數據,此數組元素數大于實(shí)際存儲的數據以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及數組元素移動(dòng)等內存操作,所以索引數據快而插入數據慢,Vector由于使用了synchronized方法(線(xiàn)程安全),通常性能上較ArrayList差,而LinkedList使用雙向鏈表實(shí)現存儲,按序號索引數據需要進(jìn)行前向或后向遍歷,但是插入數據時(shí)只需要記錄本項的前后項即可,所以插入速度較快。
LinkedList也是線(xiàn)程不安全的,LinkedList提供了一些方法,使得LinkedList可以被當作堆棧和隊列來(lái)使用。
94、如何去掉一個(gè)Vector集合中重復的元素
【參考答案】
Vector newVector = new Vector();
for (int i=0;i
{
Object obj = vector.get(i);
if(!newVector.contains(obj);
newVector.add(obj);
}
還有一種簡(jiǎn)單的方式,HashSet set = new HashSet(vector);
95、Set里的元素是不能重復的,那么用什么方法來(lái)區分重復與否呢?是用==還是equals()?它們有何區別?
【參考答案】
Set里的元素是不能重復的,元素重復與否是使用equals()方法進(jìn)行判斷的。
96、兩個(gè)對象值相同(x.equals(y) == true),但卻可有不同的hash code,這句話(huà)對不對?
【參考答案】
對。
如果對象要保存在HashSet或HashMap中,它們的equals相等,那么,它們的hashcode值就必須相等。
如果不是要保存在HashSet或HashMap,則與hashcode沒(méi)有什么關(guān)系了,這時(shí)候hashcode不等是可以的,例如arrayList存儲的對象就不用實(shí)現hashcode方法。
97、字節流與字符流的區別
【參考答案】
要把一片二進(jìn)制數據數據逐一輸出到某個(gè)設備中,或者從某個(gè)設備中逐一讀取一片二進(jìn)制數據,不管輸入輸出設備是什么,我們要用統一的方式來(lái)完成這些操作,用一種抽象的方式進(jìn)行描述,這個(gè)抽象描述方式起名為IO流,對應的抽象類(lèi)為OutputStream和InputStream,不同的實(shí)現類(lèi)就代表不同的輸入和輸出設備,它們都是針對字節進(jìn)行操作的。
在應用中,經(jīng)常要完全是字符的一段文本輸出去或讀進(jìn)來(lái),用字節流可以嗎?計算機中的一切最終都是二進(jìn)制的字節形式存在。對于“中國”這些字符,首先要得到其對應的字節,然后將字節寫(xiě)入到輸出流。讀取時(shí),首先讀到的是字節,可是我們要把它顯示為字符,我們需要將字節轉換成字符。由于這樣的需求很廣泛,人家專(zhuān)門(mén)提供了字符流的包裝類(lèi)。
底層設備永遠只接受字節數據,有時(shí)候要寫(xiě)字符串到底層設備,需要將字符串轉成字節再進(jìn)行寫(xiě)入。字符流是字節流的包裝,字符流則是直接接受字符串,它內部將串轉成字節,再寫(xiě)入底層設備,這為我們向IO設別寫(xiě)入或讀取字符串提供了一點(diǎn)點(diǎn)方便。
字符向字節轉換時(shí),要注意編碼的問(wèn)題,因為字符串轉成字節數組,
其實(shí)是轉成該字符的某種編碼的字節形式,讀取也是反之的道理。
講解字節流與字符流關(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);
}
}
98、java里面的io跟nio有什么區別
【參考答案】
1、Java NIO和IO之間第一個(gè)最大的區別是,IO是面向流的,NIO是面向緩沖區的。
2、Java IO的各種流是阻塞的。而Java NIO的非阻塞模式,使一個(gè)線(xiàn)程從某通道發(fā)送請求讀取數據,但是它僅能得到目前可用的數據,如果目前沒(méi)有數據可用時(shí),就什么都不會(huì )獲取。而不是保持線(xiàn)程阻塞,所以直至數據變的可以讀取之前,該線(xiàn)程可以繼續做其他的事情。
3、選擇器上,Java IO無(wú)選擇器,而NIO有選擇器,Java NIO的選擇器允許一個(gè)單獨的線(xiàn)程來(lái)監視多個(gè)輸入通道,你可以注冊多個(gè)通道使用一個(gè)選擇器,然后使用一個(gè)單獨的線(xiàn)程來(lái)“選擇”通道:這些通道里已經(jīng)有可以處理的輸入,或者選擇已準備寫(xiě)入的通道。
99、Java中會(huì )存在內存泄漏嗎,請簡(jiǎn)單描述。
【參考答案】
所謂內存泄露就是指一個(gè)不再被程序使用的對象或變量一直被占據在內存中。java中有垃圾回收機制,它可以保證一對象不再被引用的時(shí)候,即對象變成了孤兒的時(shí)候,對象將自動(dòng)被垃圾回收器從內存中清除掉。由于Java使用有向圖的方式進(jìn)行垃圾回收管理,可以消除引用循環(huán)的問(wèn)題,例如有兩個(gè)對象,相互引用,只要它們和根進(jìn)程不可達的,那么GC也是可以回收它們的,例如下面的代碼可以看到這種情況的內存回收:
package com.huawei.interview;
import java.io.IOException;
public class GarbageTest {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
try {
gcTest();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
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();
}
}
private static void gcTest() throws IOException {
System.in.read();
System.in.read();
Person p1 = new Person();
System.in.read();
System.in.read();
Person p2 = new Person();
p1.setMate(p2);
p2.setMate(p1);
System.out.println("before exit gctest!");
System.in.read();
System.in.read();
System.gc();
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中的內存泄露的情況:長(cháng)生命周期的對象持有短生命周期對象的引用就很可能發(fā)生內存泄露,盡管短生命周期對象已經(jīng)不再需要,但是因為長(cháng)生命周期對象持有它的引用而導致不能被回收,這就是java中內存泄露的發(fā)生場(chǎng)景,通俗地說(shuō),就是程序員可能創(chuàng )建了一個(gè)對象,以后一直不再使用這個(gè)對象,這個(gè)對象卻一直被引用,即這個(gè)對象無(wú)用但是卻無(wú)法被垃圾回收器回收的,這就是java中可能出現內存泄露的情況,例如,緩存系統,我們加載了一個(gè)對象放在緩存中(例如放在一個(gè)全局map對象中),然后一直不再使用它,這個(gè)對象一直被緩存引用,但卻不再被使用。
檢查java中的內存泄露,一定要讓程序將各種分支情況都完整執行到程序結束,然后看某個(gè)對象是否被使用過(guò),如果沒(méi)有,則才能判定這個(gè)對象屬于內存泄露。
如果一個(gè)外部類(lèi)的實(shí)例對象的方法返回了一個(gè)內部類(lèi)的實(shí)例對象,這個(gè)內部類(lèi)對象被長(cháng)期引用了,即使那個(gè)外部類(lèi)實(shí)例對象不再被使用,但由于內部類(lèi)持久外部類(lèi)的實(shí)例對象,這個(gè)外部類(lèi)對象將不會(huì )被垃圾回收,這也會(huì )造成內存泄露。
[]是對象已不可到達,而內存又沒(méi)有回收,真正的內存黑洞。
而Java的泄漏,則是因為各種原因,對象對應用已經(jīng)無(wú)用,但一直被持有,一直可到達。
總結原因無(wú)外乎幾方面:
1.被生命周期極長(cháng)的集合類(lèi)不當持有,號稱(chēng)是Java內存泄漏的首因。
這些集合類(lèi)的生命周期通常極長(cháng),而且是一個(gè)輔助管理性質(zhì)的對象,在一個(gè)業(yè)務(wù)事務(wù)運行完后,如果沒(méi)有將某個(gè)業(yè)務(wù)對象主動(dòng)的從中清除的話(huà),這個(gè)集合就會(huì )吃越來(lái)越多內存,可以用WeakReference,如WeakHashMap,使得它持有的對象不增加對象的引用數。
2.Scope定義不對,這個(gè)很簡(jiǎn)單了,方法的局部變量定義成類(lèi)的變量,類(lèi)的靜態(tài)變量等。
3.異常時(shí)沒(méi)有加finally{}來(lái)釋放某些資源,JDBC時(shí)代也是很普遍的事情。
4.另外一些我了解不深的原因,如:Swing里的Listener沒(méi)有顯式remove;內部類(lèi)持有外部對象的隱式引用;Finalizers造成關(guān)聯(lián)對象沒(méi)有被及時(shí)清空等。
內存泄漏的檢測
有不少工具輔助做這個(gè)事情的,如果手上一個(gè)工具也沒(méi)有,可以用JDK自帶的小工具:
·看看誰(shuí)占滿(mǎn)了Heap?
用JDK6的jmap可以顯示運行程序中對象的類(lèi)型,個(gè)數與所占的大小
先用jps找到進(jìn)程號,然后jmap -histo pid顯示或jmap -dump:file=heap_file_name pid導出heap文件
·為什么這些對象仍然可以到達?
用jhat(Java Heap Analysis Tool)分析剛才導出的heap文件。
先jhat heap_file_name,然后打開(kāi)瀏覽器http://localhost:7000/瀏覽。
100、Hashcode和Equals的聯(lián)系
【參考答案】
首先equals()和hashcode()這兩個(gè)方法都是從object類(lèi)中繼承過(guò)來(lái)的,主要用來(lái)比較對象時(shí)進(jìn)行調用。在object類(lèi)中定義如下:
a)、如果兩個(gè)對象相同,那么它們的hashCode值一定要相同;
b)、如果兩個(gè)對象的hashCode相同,它們并不一定相同上面說(shuō)的對象相同指的是用eqauls方法比較。
101、Tread和Threadlocal的作用及區別?
【參考答案】
答:threadlocal是線(xiàn)程局部變量(thread local variable),為每一個(gè)使用該線(xiàn)程的線(xiàn)程都提供一個(gè)變量值的副本,使每一個(gè)線(xiàn)程都可以獨立地改變自己的副本,而不會(huì )和其他線(xiàn)程的副本產(chǎn)生沖突。
102、TCP和UDP的區別?
【參考答案】
TCP/IP的運輸層有兩個(gè)不同的協(xié)議:①用戶(hù)數據報協(xié)議UDP②傳輸控制協(xié)議TCP
二者最大區別:TCP是面向連接的,而UDP是無(wú)連接的.區別大致如下:
1)UDP傳送的數據單位協(xié)議是UDP報文或用戶(hù)數據報,TCP傳送的數據單位協(xié)議是TCP報文段。
2)UDP發(fā)送數據之前不需要建立連接,因此減少了開(kāi)銷(xiāo)和發(fā)送之前的時(shí)延。TCP提供面向連接的服務(wù),不提供廣播或多播服務(wù)。
3)對方的運輸層在收到UDP報文后,不需要給出任何確認。TCP則需要確認。
4)UDP沒(méi)有擁塞控制,因此網(wǎng)絡(luò )出現的擁塞不會(huì )使源主機的發(fā)送速率降低,也不保證可靠交付,因此主機不需要維持具有許多參數的、復雜的連接狀態(tài)表。TCP要提供可靠的、面向連接的運輸服務(wù),因此不可避免地增加了許多的開(kāi)銷(xiāo),這不僅使協(xié)議數據單元的首部增大很多,還要占用許多的處理機資源。
5)UDP用戶(hù)數據報只有8個(gè)字節的首部開(kāi)銷(xiāo),比TCP的20個(gè)字節的首部要短。
103、啟動(dòng)一個(gè)線(xiàn)程用什么方法?【北京永中軟件面試題】
【參考】
使用Thread類(lèi)的start()方法來(lái)啟動(dòng)一個(gè)線(xiàn)程,使線(xiàn)程進(jìn)入就緒狀態(tài)。如果自定義的類(lèi)是Thread類(lèi)的子類(lèi)的話(huà),可以直接使用Start()來(lái)啟,如果是實(shí)現的Runnable接口的話(huà),還要將該類(lèi)的實(shí)例作為參數傳入到Thread對象中來(lái)啟動(dòng)。
104、作用域public等寫(xiě)不寫(xiě)的區別?【北京永中軟件面試題】
【參考】
作用域不寫(xiě)將采用默認的作用域,默認作用域的訪(fǎng)問(wèn)權限是包的權限,也就是除本包中的所有類(lèi)能訪(fǎng)問(wèn),不同包只有子類(lèi)能訪(fǎng)問(wèn)。
105、同步和異步有何異同
【參考答案】
同步(synchronized)和異步(asynchronized)是對于多線(xiàn)程(multi-threading)而言的
同步可防止并發(fā)主要出于數據安全的考慮
如果數據將在線(xiàn)程間共享。例如正在寫(xiě)的數據以后可能被另一個(gè)線(xiàn)程讀到,或者正在讀的數據可能已經(jīng)被另一個(gè)線(xiàn)程寫(xiě)過(guò)了,那么這些數據就是共享數據,必須進(jìn)行同步存取。
異步允許并發(fā)
ajax技術(shù)通常都是異步實(shí)現的,異步主要使用在當應用程序在對象上調用了一個(gè)需要花費很長(cháng)時(shí)間來(lái)執行的方法,并且不希望讓程序等待方法的返回時(shí),就應該使用異步編程,在很多情況下采用異步途徑往往更有效率。
106、Static方法和static字段有什么用處?可以被重載嗎?
【參考答案】
用static修飾的方法叫類(lèi)方法,被所有實(shí)例共享;static修飾的字段為類(lèi)變量,被所有實(shí)例共享,在使用類(lèi)變量時(shí),一般會(huì )結合final一起使用定義類(lèi)常量,不允許被其它的類(lèi)實(shí)例修改。
可以被重載,重載只是參數類(lèi)型、順序和個(gè)數不同。
聯(lián)系客服