Java 面試寶典

肖朋偉發表於2018-09-09

 

1. Java基礎部分

基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,執行緒的語法,集合的語法,io 的語法,虛擬機器方面的語法。

1、一個".java"原始檔中是否可以包括多個類(不是內部類)?有什麼限制?

可以有多個類,但只能有一個public的類,並且public的類名必須與檔名相一致。

2、Java有沒有goto?

java中的保留字,現在沒有在java中使用。

3、說說&和&&的區別。

&和&&都可以用作邏輯與的運算子,表示邏輯與(and),當運算子兩邊的表示式的結果都為true時,整個運算結果才為true,否則,只要有一方為false,則結果為false。

&&還具有短路的功能,即如果第一個表示式為false,則不再計算第二個表示式,例如,對於if(str != null && !str.equals(“”))表示式,當str為null時,後面的表示式不會執行,所以不會出現NullPointerException如果將&&改為&,則會丟擲NullPointerException異常。If(x==33 & ++y>0) y會增長,If(x==33 && ++y>0)不會增長

&還可以用作位運算子,當&操作符兩邊的表示式不是boolean型別時,&表示按位與操作,我們通常使用0x0f來與一個整數進行&運算,來獲取該整數的最低4個bit位,例如,0x31 & 0x0f的結果為0x01。

備註:這道題先說兩者的共同點,再說出&&和&的特殊之處,並列舉一些經典的例子來表明自己理解透徹深入、實際經驗豐富。

4、在JAVA中如何跳出當前的多重巢狀迴圈?

在Java中,要想跳出多重迴圈,可以在外面的迴圈語句前定義一個標號,然後在裡層迴圈體的程式碼中使用帶有標號的break 語句,即可跳出外層迴圈。例如,

 1 ok:
 2 
 3 for(inti=0;i<10;i++)    {
 4 
 5            for(intj=0;j<10;j++)              {
 6 
 7                     System.out.println(“i=”+ i + “,j=” + j);
 8 
 9                     if(j == 5) break ok;
10 
11            }
12 
13 }

另外,我個人通常並不使用標號這種方式,而是讓外層的迴圈條件表示式的結果可以受到裡層迴圈體程式碼的控制,例如,要在二維陣列中查詢到某個數字。

 1  int arr[][] = { { 1, 2, 3 }, { 4, 5, 6, 7 }, { 9 } };
 2 
 3  boolean found = false;
 4  for (int i = 0; i < arr.length && !found; i++) {
 5     for (int j = 0; j < arr[i].length; j++) {
 6         System.out.println("i=" + i + ",j=" + j);
 7         if (arr[i][j] == 5) {
 8             found = true;
 9             break;
10         }
11     }
12  }

5、switch語句能否作用在byte上,能否作用在long上,能否作用在String上?

在switch(expr1)中,expr1只能是一個整數表示式或者列舉常量(更大字型),整數表示式可以是int基本型別或Integer包裝型別,由於,byte,short,char都可以隱含轉換為int,所以,這些型別以及這些型別的包裝型別也是可以的。顯然,long和String型別都不符合switch的語法規定,並且不能被隱式轉換成int型別,所以,它們不能作用於swtich語句中。

6、short s1 = 1; s1 = s1 + 1;有什麼錯? short s1 = 1; s1 += 1;有什麼錯?

對於short s1 = 1; s1 = s1 + 1; 由於s1+1運算時會自動提升表示式的型別,所以結果是int型,再賦值給short型別s1時,編譯器將報告需要強制轉換型別的錯誤。

對於short s1 = 1; s1 += 1;由於 += 是java語言規定的運算子,java編譯器會對它進行特殊處理,因此可以正確編譯。

7、char型變數中能不能存貯一箇中文漢字?為什麼?

char型變數是用來儲存Unicode編碼的字元的,unicode編碼字符集中包含了漢字,所以,char型變數中當然可以儲存漢字啦。不過,如果某個特殊的漢字沒有被包含在unicode編碼字符集中,那麼,這個char型變數中就不能儲存這個特殊漢字。補充說明:unicode編碼佔用兩個位元組,所以,char型別的變數也是佔用兩個位元組。

備註:後面一部分回答雖然不是在正面回答題目,但是,為了展現自己的學識和表現自己對問題理解的透徹深入,可以回答一些相關的知識,做到知無不言,言無不盡。

8、用最有效率的方法算出2乘以8等於幾?

2 << 3,

因為將一個數左移n位,就相當於乘以了2的n次方,那麼,一個數乘以8只要將其左移3位即可,而位運算cpu直接支援的,效率最高,所以,2乘以8等於幾的最效率的方法是2 << 3。

9、請設計一個一百億的計算器

首先要明白這道題目的考查點是什麼,一是大家首先要對計算機原理的底層細節要清楚、要知道加減法的位運算原理和知道計算機中的算術運算會發生越界的情況,二是要具備一定的物件導向的設計思想。

首先,計算機中用固定數量的幾個位元組來儲存的數值,所以計算機中能夠表示的數值是有一定的範圍的,為了便於講解和理解,我們先以byte 型別的整數為例,它用1個位元組進行儲存,表示的最大數值範圍為-128到+127。-1在記憶體中對應的二進位制資料為11111111,如果兩個-1相加,不考慮Java運算時的型別提升,運算後會產生進位,二進位制結果為1,11111110,由於進位後超過了byte型別的儲存空間,所以進位部分被捨棄,即最終的結果為11111110,也就是-2,這正好利用溢位的方式實現了負數的運算。-128在記憶體中對應的二進位制資料為10000000,如果兩個-128相加,不考慮Java運算時的型別提升,運算後會產生進位,二進位制結果為1,00000000,由於進位後超過了byte型別的儲存空間,所以進位部分被捨棄,即最終的結果為00000000,也就是0,這樣的結果顯然不是我們期望的,這說明計算機中的算術運算是會發生越界情況的,兩個數值的運算結果不能超過計算機中的該型別的數值範圍。由於Java中涉及表示式運算時的型別自動提升,我們無法用byte型別來做演示這種問題和現象的實驗,大家可以用下面一個使用整數做實驗的例子程式體驗一下:

1  inta = Integer.MAX_VALUE;
2 
3  intb = Integer.MAX_VALUE;
4 
5  intsum = a + b;
6 
7  System.out.println(“a=”+a+”,b=”+b+”,sum=”+sum);

先不考慮long型別,由於int的正數範圍為2的31次方,表示的最大數值約等於2*1000*1000*1000,也就是20億的大小,所以,要實現一個一百億的計算器,我們得自己設計一個類可以用於表示很大的整數,並且提供了與另外一個整數進行加減乘除的功能,大概功能如下:

(1)這個類內部有兩個成員變數,一個表示符號,另一個用位元組陣列表示數值的二進位制數

(2)有一個構造方法,把一個包含有多位數值的字串轉換到內部的符號和位元組陣列中

(3)提供加減乘除的功能

 1 public class BigInteger {
 2     int sign;
 3     byte[] val;
 4 
 5     public Biginteger(String val) {
 6                     sign= ;
 7                      val= ;
 8             }
 9 
10     public BigInteger add(BigInteger other) {
11     }
12 
13     public BigInteger subtract(BigInteger other) {
14     }
15 
16     public BigInteger multiply(BigInteger other) {
17     }
18 
19     public BigInteger divide(BigInteger other) {
20     }
21 
22 }

備註:要想寫出這個類的完整程式碼,是非常複雜的,如果有興趣的話,可以參看jdk中自帶的java.math.BigInteger類的原始碼。面試的人也知道誰都不可能在短時間內寫出這個類的完整程式碼的,他要的是你是否有這方面的概念和意識,他最重要的還是考查你的能力,所以,你不要因為自己無法寫出完整的最終結果就放棄答這道題,你要做的就是你比別人寫得多,證明你比別人強,你有這方面的思想意識就可以了,畢竟別人可能連題目的意思都看不懂,什麼都沒寫,你要敢於答這道題,即使只答了一部分,那也與那些什麼都不懂的人區別出來,拉開了距離,算是矮子中的高個,機會當然就屬於你了。另外,答案中的框架程式碼也很重要,體現了一些物件導向設計的功底,特別是其中的方法命名很專業,用的英文單詞很精準,這也是能力、經驗、專業性、英語水平等多個方面的體現,會給人留下很好的印象,在程式設計能力和其他方面條件差不多的情況下,英語好除了可以使你獲得更多機會外,薪水可以高出一千元。

10、使用final關鍵字修飾一個變數時,是引用不能變,還是引用的物件不能變?

使用final關鍵字修飾一個變數時,是指引用變數不能變,引用變數所指向的物件中的內容還是可以改變的。例如,對於如下語句:

1 final StringBuffer a=new StringBuffer("immutable");

執行如下語句將報告編譯期錯誤:

1 a=new StringBuffer("");

但是,執行如下語句則可以通過編譯:

1 a.append(" broken!");  

有人在定義方法的引數時,可能想採用如下形式來阻止方法內部修改傳進來的引數物件:

1 publicvoid method(final  StringBuffer  param){
2 
3 }

實際上,這是辦不到的,在該方法內部仍然可以增加如下程式碼來修改引數物件:

1  param.append("a");

11、"=="和equals方法究竟有什麼區別?

(單獨把一個東西說清楚,然後再說清楚另一個,這樣,它們的區別自然就出來了,混在一起說,則很難說清楚)

==操作符專門用來比較兩個變數的值是否相等,也就是用於比較變數所對應的記憶體中所儲存的數值是否相同,要比較兩個基本型別的資料或兩個引用變數是否相等,只能用==操作符。

如果一個變數指向的資料是物件型別的,那麼,這時候涉及了兩塊記憶體,物件本身佔用一塊記憶體(堆記憶體),變數也佔用一塊記憶體,例如Objet obj = new Object();變數obj是一個記憶體,new Object()是另一個記憶體,此時,變數obj所對應的記憶體中儲存的數值就是物件佔用的那塊記憶體的首地址。對於指向物件型別的變數,如果要比較兩個變數是否指向同一個物件,即要看這兩個變數所對應的記憶體中的數值是否相等,這時候就需要用==操作符進行比較。

equals方法是用於比較兩個獨立物件的內容是否相同,就好比去比較兩個人的長相是否相同,它比較的兩個物件是獨立的。例如,對於下面的程式碼:

1  String a=new String("foo");
2 
3  String b=new String("foo");

兩條new語句建立了兩個物件,然後用a,b這兩個變數分別指向了其中一個物件,這是兩個不同的物件,它們的首地址是不同的,即a和b中儲存的數值是不相同的,所以,表示式a==b將返回false,而這兩個物件中的內容是相同的,所以,表示式a.equals(b)將返回true。

在實際開發中,我們經常要比較傳遞進行來的字串內容是否等,例如,String input = …;input.equals(“quit”),許多人稍不注意就使用==進行比較了,這是錯誤的,隨便從網上找幾個專案實戰的教學視訊看看,裡面就有大量這樣的錯誤。記住,字串的比較基本上都是使用equals方法。

如果一個類沒有自己定義equals方法,那麼它將繼承Object類的equals方法,Object類的equals方法的實現程式碼如下:

1  boolean equals(Object o){
2 
3  return this==o;
4 
5  }

這說明,如果一個類沒有自己定義equals方法,它預設的equals方法(從Object 類繼承的)就是使用==操作符,也是在比較兩個變數指向的物件是否是同一物件,這時候使用equals和使用==會得到同樣的結果,如果比較的是兩個獨立的物件則總返回false。如果你編寫的類希望能夠比較該類建立的兩個例項物件的內容是否相同,那麼你必須覆蓋equals方法,由你自己寫程式碼來決定在什麼情況即可認為兩個物件的內容是相同的。

12、靜態變數和例項變數的區別?

在語法定義上的區別:靜態變數前要加static關鍵字,而例項變數前則不加。

在程式執行時的區別:例項變數屬於某個物件的屬性,必須建立了例項物件,其中的例項變數才會被分配空間,才能使用這個例項變數。靜態變數不屬於某個例項物件,而是屬於類,所以也稱為類變數,只要程式載入了類的位元組碼,不用建立任何例項物件,靜態變數就會被分配空間,靜態變數就可以被使用了。總之,例項變數必須建立物件後才可以通過這個物件來使用,靜態變數則可以直接使用類名來引用。

例如,對於下面的程式,無論建立多少個例項物件,永遠都只分配了一個staticVar變數,並且每建立一個例項物件,這個staticVar就會加1;但是,每建立一個例項物件,就會分配一個instanceVar,即可能分配多個instanceVar,並且每個instanceVar的值都只自加了1次。

 1 public class VariantTest {
 2 
 3     public static int staticVar = 0;
 4     public int instanceVar = 0;
 5 
 6     public VariantTest() {
 7         staticVar++;
 8         instanceVar++;
 9         System.out.println("staticVar=" + staticVar + ",instanceVar=" + instanceVar);
10     }
11 }

備註:這個解答除了說清楚兩者的區別外,最後還用一個具體的應用例子來說明兩者的差異,體現了自己有很好的解說問題和設計案例的能力,思維敏捷,超過一般程式設計師,有寫作能力!

13、是否可以從一個static方法內部發出對非static方法的呼叫?

不可以。因為非static方法是要與物件關聯在一起的,必須建立一個物件後,才可以在該物件上進行方法呼叫,而static方法呼叫時不需要建立物件,可以直接呼叫。也就是說,當一個static方法被呼叫時,可能還沒有建立任何例項物件,如果從一個static方法中發出對非static方法的呼叫,那個非static方法是關聯到哪個物件上的呢?這個邏輯無法成立,所以,一個static方法內部發出對非static方法的呼叫。

14、Integer與int的區別

int是java提供的8種原始資料型別之一。Java為每個原始型別提供了封裝類,Integer是java為int提供的封裝類。int的預設值為0,而Integer的預設值為null,即Integer可以區分出未賦值和值為0的區別,int則無法表達出未賦值的情況,例如,要想表達出沒有參加考試和考試成績為0的區別,則只能使用Integer。在JSP開發中,Integer的預設為null,所以用el表示式在文字框中顯示時,值為空白字串,而int預設的預設值為0,所以用el表示式在文字框中顯示時,結果為0,所以,int不適合作為web層的表單資料的型別。

在Hibernate中,如果將OID定義為Integer型別,那麼Hibernate就可以根據其值是否為null而判斷一個物件是否是臨時的,如果將OID定義為了int型別,還需要在hbm對映檔案中設定其unsaved-value屬性為0。

另外,Integer提供了多個與整數相關的操作方法,例如,將一個字串轉換成整數,Integer中還定義了表示整數的最大值和最小值的常量。

15、Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

Math類中提供了三個與取整有關的方法:ceil、floor、round,這些方法的作用與它們的英文名稱的含義相對應,例如,ceil的英文意義是天花板,該方法就表示向上取整,Math.ceil(11.3)的結果為12,Math.ceil(-11.3)的結果是-11;floor的英文意義是地板,該方法就表示向下取整,Math.ceil(11.6)的結果為11,Math.ceil(-11.6)的結果是-12;最難掌握的是round方法,它表示“四捨五入”,演算法為Math.floor(x+0.5),即將原來的數字加上0.5後再向下取整,所以,Math.round(11.5)的結果為12,Math.round(-11.5)的結果為-11。

16、下面的程式碼有什麼不妥之處?

1 1.if(username.equals(“zxx”){}
2 
3 2.int x = 1;
4 
5   return x==1?true:false;

17、請說出作用域public,private,protected,以及不寫時的區別

這四個作用域的可見範圍如下表所示。

說明:如果在修飾的元素上面沒有寫任何訪問修飾符,則表示friendly。 

作用域 當前類 同一package 子孫類 其他package
public
protected ×
default × ×
private × × ×

 

      

   

 

 

備註:只要記住了有4種訪問許可權,4個訪問範圍,然後將全選和範圍在水平和垂直方向上分別按排從小到大或從大到小的順序排列,就很容易畫出上面的圖了。

18、Overload和Override的區別。Overloaded的方法是否可以改變返回值的型別?

Overload是過載的意思,Override是覆蓋的意思,也就是重寫。

過載Overload表示同一個類中可以有多個名稱相同的方法,但這些方法的引數列表各不相同(即引數個數或型別不同)。

重寫Override表示子類中的方法可以與父類中的某個方法的名稱和引數完全相同,通過子類建立的例項物件呼叫這個方法時,將呼叫子類中的定義方法,這相當於把父類中定義的那個完全相同的方法給覆蓋了,這也是物件導向程式設計的多型性的一種表現。子類覆蓋父類的方法時,只能比父類丟擲更少的異常,或者是丟擲父類丟擲的異常的子異常,因為子類可以解決父類的一些問題,不能比父類有更多的問題。子類方法的訪問許可權只能比父類的更大,不能更小。如果父類的方法是private型別,那麼,子類則不存在覆蓋的限制,相當於子類中增加了一個全新的方法。

至於Overloaded的方法是否可以改變返回值的型別這個問題,要看你倒底想問什麼呢?這個題目很模糊。如果幾個Overloaded的方法的引數列表不一樣,它們的返回者型別當然也可以不一樣。但我估計你想問的問題是:如果兩個方法的引數列表完全一樣,是否可以讓它們的返回值不同來實現過載Overload。這是不行的,我們可以用反證法來說明這個問題,因為我們有時候呼叫一個方法時也可以不定義返回結果變數,即不要關心其返回結果,例如,我們呼叫map.remove(key)方法時,雖然remove方法有返回值,但是我們通常都不會定義接收返回結果的變數,這時候假設該類中有兩個名稱和引數列表完全相同的方法,僅僅是返回型別不同,java就無法確定程式設計者倒底是想呼叫哪個方法了,因為它無法通過返回結果型別來判斷。

override可以翻譯為覆蓋,從字面就可以知道,它是覆蓋了一個方法並且對其重寫,以求達到不同的作用。對我們來說最熟悉的覆蓋就是對介面方法的實現,在介面中一般只是對方法進行了宣告,而我們在實現時,就需要實現介面宣告的所有方法。除了這個典型的用法以外,我們在繼承中也可能會在子類覆蓋父類中的方法。在覆蓋要注意以下的幾點:

1、覆蓋的方法的標誌必須要和被覆蓋的方法的標誌完全匹配,才能達到覆蓋的效果;

2、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;

3、覆蓋的方法所丟擲的異常必須和被覆蓋方法的所丟擲的異常一致,或者是其子類;

4、被覆蓋的方法不能為private,否則在其子類中只是新定義了一個方法,並沒有對其進行覆蓋。

overload對我們來說可能比較熟悉,可以翻譯為過載,它是指我們可以定義一些名稱相同的方法,通過定義不同的輸入引數來區分這些方法,然後再呼叫時,VM就會根據不同的引數樣式,來選擇合適的方法執行。在使用過載要注意以下的幾點:

1、在使用過載時只能通過不同的引數樣式。例如,不同的引數型別,不同的引數個數,不同的引數順序(當然,同一方法內的幾個引數型別必須不一樣,例如可以是fun(int,float),但是不能為fun(int,int));

2、不能通過訪問許可權、返回型別、丟擲的異常進行過載;

3、方法的異常型別和數目不會對過載造成影響;

4、對於繼承來說,如果某一方法在父類中是訪問許可權是priavte,那麼就不能在子類對其進行過載,如果定義的話,也只是定義了一個新方法,而不會達到過載的效果。

19、構造器Constructor是否可被override?

構造器Constructor不能被繼承,因此不能重寫Override,但可以被過載Overload。

20、介面是否可繼承介面? 抽象類是否可實現(implements)介面? 抽象類是否可繼承具體類(concrete class)? 抽象類中是否可以有靜態的main方法?

介面可以繼承介面。抽象類可以實現(implements)介面,抽象類是否可繼承具體類。抽象類中可以有靜態的main方法。

備註:只要明白了介面和抽象類的本質和作用,這些問題都很好回答,你想想,如果你是java語言的設計者,你是否會提供這樣的支援,如果不提供的話,有什麼理由嗎?如果你沒有道理不提供,那答案就是肯定的了。

 只有記住抽象類與普通類的唯一區別就是不能建立例項物件和允許有abstract方法。

21、寫clone()方法時,通常都有一行程式碼,是什麼?

clone 有預設行為,super.clone();因為首先要把父類中的成員複製到位,然後才是複製自己的成員。

22、物件導向的特徵有哪些方面

計算機軟體系統是現實生活中的業務在計算機中的對映,而現實生活中的業務其實就是一個個物件協作的過程。物件導向程式設計就是按現實業務一樣的方式將程式程式碼按一個個物件進行組織和編寫,讓計算機系統能夠識別和理解用物件方式組織和編寫的程式程式碼,這樣就可以把現實生活中的業務物件對映到計算機系統中。

物件導向的程式語言有封裝、繼承、抽象、多型等4個主要的特徵。

1-封裝:

封裝是保證軟體部件具有優良的模組性的基礎,封裝的目標就是要實現軟體部件的“高內聚、低耦合”,防止程式相互依賴性而帶來的變動影響。在物件導向的程式語言中,物件是封裝的最基本單位,物件導向的封裝比傳統語言的封裝更為清晰、更為有力。物件導向的封裝就是把描述一個物件的屬性和行為的程式碼封裝在一個“模組”中,也就是一個類中,屬性用變數定義,行為用方法進行定義,方法可以直接訪問同一個物件中的屬性。通常情況下,只要記住讓變數和訪問這個變數的方法放在一起,將一個類中的成員變數全部定義成私有的,只有這個類自己的方法才可以訪問到這些成員變數,這就基本上實現物件的封裝,就很容易找出要分配到這個類上的方法了,就基本上算是會物件導向的程式設計了。把握一個原則:把對同一事物進行操作的方法和相關的方法放在同一個類中,把方法和它操作的資料放在同一個類中。

例如,人要在黑板上畫圓,這一共涉及三個物件:人、黑板、圓,畫圓的方法要分配給哪個物件呢?由於畫圓需要使用到圓心和半徑,圓心和半徑顯然是圓的屬性,如果將它們在類中定義成了私有的成員變數,那麼,畫圓的方法必須分配給圓,它才能訪問到圓心和半徑這兩個屬性,人以後只是呼叫圓的畫圓方法、表示給圓發給訊息而已,畫圓這個方法不應該分配在人這個物件上,這就是物件導向的封裝性,即將物件封裝成一個高度自治和相對封閉的個體,物件狀態(屬性)由這個物件自己的行為(方法)來讀取和改變。一個更便於理解的例子就是,司機將火車剎住了,剎車的動作是分配給司機,還是分配給火車,顯然,應該分配給火車,因為司機自身是不可能有那麼大的力氣將一個火車給停下來的,只有火車自己才能完成這一動作,火車需要呼叫內部的離合器和剎車片等多個器件協作才能完成剎車這個動作,司機剎車的過程只是給火車發了一個訊息,通知火車要執行剎車動作而已。

2-抽象:

抽象就是找出一些事物的相似和共性之處,然後將這些事物歸為一個類,這個類只考慮這些事物的相似和共性之處,並且會忽略與當前主題和目標無關的那些方面,將注意力集中在與當前目標有關的方面。例如,看到一隻螞蟻和大象,你能夠想象出它們的相同之處,那就是抽象。抽象包括行為抽象和狀態抽象兩個方面。例如,定義一個Person類,如下:

1 classPerson{
2 
3         String name;
4 
5         int age;
6 
7 }

人本來是很複雜的事物,有很多方面,但因為當前系統只需要瞭解人的姓名和年齡,所以上面定義的類中只包含姓名和年齡這兩個屬性,這就是一種抽像,使用抽象可以避免考慮一些與目標無關的細節。我對抽象的理解就是不要用顯微鏡去看一個事物的所有方面,這樣涉及的內容就太多了,而是要善於劃分問題的邊界,當前系統需要什麼,就只考慮什麼。

3-繼承:

在定義和實現一個類的時候,可以在一個已經存在的類的基礎之上來進行,把這個已經存在的類所定義的內容作為自己的內容,並可以加入若干新的內容,或修改原來的方法使之更適合特殊的需要,這就是繼承。繼承是子類自動共享父類資料和方法的機制,這是類之間的一種關係,提高了軟體的可重用性和可擴充套件性。

4-多型:

多型是指程式中定義的引用變數所指向的具體型別和通過該引用變數發出的方法呼叫在程式設計時並不確定,而是在程式執行期間才確定,即一個引用變數倒底會指向哪個類的例項物件,該引用變數發出的方法呼叫到底是哪個類中實現的方法,必須在由程式執行期間才能決定。因為在程式執行時才確定具體的類,這樣,不用修改源程式程式碼,就可以讓引用變數繫結到各種不同的類實現上,從而導致該引用呼叫的具體方法隨之改變,即不修改程式程式碼就可以改變程式執行時所繫結的具體程式碼,讓程式可以選擇多個執行狀態,這就是多型性。多型性增強了軟體的靈活性和擴充套件性。例如,下面程式碼中的UserDao是一個介面,它定義引用變數userDao指向的例項物件由daofactory.getDao()在執行的時候返回,有時候指向的是UserJdbcDao這個實現,有時候指向的是UserHibernateDao這個實現,這樣,不用修改原始碼,就可以改變userDao指向的具體類實現,從而導致userDao.insertUser()方法呼叫的具體程式碼也隨之改變,即有時候呼叫的是UserJdbcDao的insertUser方法,有時候呼叫的是UserHibernateDao的insertUser方法:

1 UserDao userDao = daofactory.getDao(); 
2 
3 userDao.insertUser(user);

比喻:人吃飯,你看到的是左手,還是右手?

23、java中實現多型的機制是什麼?

靠的是父類或介面定義的引用變數可以指向子類或具體實現類的例項物件,而程式呼叫的方法在執行期才動態繫結,就是引用變數所指向的具體例項物件的方法,也就是記憶體里正在執行的那個物件的方法,而不是引用變數的型別中定義的方法。

24、abstract class和interface有什麼區別?  

含有abstract修飾符的class即為抽象類,abstract 類不能建立的例項物件。含有abstract方法的類必須定義為abstract class,abstract class類中的方法不必是抽象的。abstract class類中定義抽象方法必須在具體(Concrete)子類中實現,所以,不能有抽象構造方法或抽象靜態方法。如果的子類沒有實現抽象父類中的所有抽象方法,那麼子類也必須定義為abstract型別。

介面(interface)可以說成是抽象類的一種特例,介面中的所有方法都必須是抽象的。介面中的方法定義預設為public abstract型別,介面中的成員變數型別預設為public static final。

下面比較一下兩者的語法區別:

1.抽象類可以有構造方法,介面中不能有構造方法。

2.抽象類中可以有普通成員變數,介面中沒有普通成員變數

3.抽象類中可以包含非抽象的普通方法,介面中的所有方法必須都是抽象的,不能有非抽象的普通方法。

4. 抽象類中的抽象方法的訪問型別可以是public,protected和(預設型別,雖然

eclipse下不報錯,但應該也不行),但介面中的抽象方法只能是public型別的,並且預設即為public abstract型別。

5. 抽象類中可以包含靜態方法,介面中不能包含靜態方法

6. 抽象類和介面中都可以包含靜態成員變數,抽象類中的靜態成員變數的訪問型別可以任意,但介面中定義的變數只能是public static final型別,並且預設即為public static final型別。

7.一個類可以實現多個介面,但只能繼承一個抽象類。

         下面接著再說說兩者在應用上的區別:

介面更多的是在系統架構設計方法發揮作用,主要用於定義模組之間的通訊契約。而抽象類在程式碼實現方面發揮作用,可以實現程式碼的重用,例如,模板方法設計模式是抽象類的一個典型應用,假設某個專案的所有Servlet類都要用相同的方式進行許可權判斷、記錄訪問日誌和處理異常,那麼就可以定義一個抽象的基類,讓所有的Servlet都繼承這個抽象基類,在抽象基類的service方法中完成許可權判斷、記錄訪問日誌和處理異常的程式碼,在各個子類中只是完成各自的業務邏輯程式碼,虛擬碼如下:

 1 import java.io.IOException;
 2 import javax.servlet.ServletException;
 3 import javax.servlet.http.HttpServlet;
 4 import javax.servlet.http.HttpServletRequest;
 5 import javax.servlet.http.HttpServletResponse;
 6 
 7 public abstract class BaseServlet extends HttpServlet {
 8     public final void service(HttpServletRequest request, HttpServletResponse response)
 9             throws IOException, ServletException {
10         // 記錄訪問日誌
11         // 進行許可權判斷
12     }
13 
14     protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
15             throws IOException, ServletException;
16         // 注意訪問許可權定義成protected,顯得既專業,又嚴謹,因為它是專門給子類用的
17 }
18 
19 class MyServlet1 extends BaseServlet {
20     protected void doService(HttpServletRequest request, HttpServletResponse response)
21             throws IOException, ServletException {
22         // 本Servlet只處理的具體業務邏輯程式碼
23     }
24 }

父類方法中間的某段程式碼不確定,留給子類幹,就用模板方法設計模式。

備註:這道題的思路是先從總體解釋抽象類和介面的基本概念,然後再比較兩者的語法細節,最後再說兩者的應用區別。比較兩者語法細節區別的條理是:先從一個類中的構造方法、普通成員變數和方法(包括抽象方法),靜態變數和方法,繼承性等6個方面逐一去比較回答,接著從第三者繼承的角度的回答,特別是最後用了一個典型的例子來展現自己深厚的技術功底。

25、abstract的method是否可同時是static,是否可同時是native,是否可同時是synchronized?

abstract的method 不可以是static的,因為抽象的方法是要被子類實現的,而static與子類扯不上關係!

native方法表示該方法要用另外一種依賴平臺的程式語言實現的,不存在著被子類實現的問題,所以,它也不能是抽象的,不能與abstract混用。例如,FileOutputSteam類要硬體打交道,底層的實現用的是作業系統相關的api實現,例如,在windows用c語言實現的,所以,檢視jdk 的原始碼,可以發現FileOutputStream的open方法的定義如下:

private native void open(String name)throws FileNotFoundException;

如果我們要用java呼叫別人寫的c語言函式,我們是無法直接呼叫的,我們需要按照java的要求寫一個c語言的函式,又我們的這個c語言函式去呼叫別人的c語言函式。由於我們的c語言函式是按java的要求來寫的,我們這個c語言函式就可以與java對接上,java那邊的對接方式就是定義出與我們這個c函式相對應的方法,java中對應的方法不需要寫具體的程式碼,但需要在前面宣告native。

關於synchronized與abstract合用的問題,我覺得也不行,因為在我幾年的學習和開發中,從來沒見到過這種情況,並且我覺得synchronized應該是作用在一個具體的方法上才有意義。而且,方法上的synchronized同步所使用的同步鎖物件是this,而抽象方法上無法確定this是什麼。

26、什麼是內部類?Static Nested Class 和 Inner Class的不同。

內部類就是在一個類的內部定義的類,內部類中不能定義靜態成員(靜態成員不是物件的特性,只是為了找一個容身之處,所以需要放到一個類中而已,這麼一點小事,你還要把它放到類內部的一個類中,過分了啊!提供內部類,不是為讓你幹這種事情,無聊,不讓你幹。我想可能是既然靜態成員類似c語言的全域性變數,而內部類通常是用於建立內部物件用的,所以,把“全域性變數”放在內部類中就是毫無意義的事情,既然是毫無意義的事情,就應該被禁止),內部類可以直接訪問外部類中的成員變數,內部類可以定義在外部類的方法外面,也可以定義在外部類的方法體中,如下所示:

 1 public class Outer {
 2 
 3     int out_x = 0;
 4 
 5     public void method() {
 6         Inner1 inner1 = new Inner1();
 7         class Inner2 // 在方法體內部定義的內部類
 8         {
 9             public void method() {
10                 out_x = 3;
11             }
12         }
13         Inner2 inner2 = new Inner2();
14     }
15 
16     public class Inner1 // 在方法體外面定義的內部類
17     {
18     }
19 }

在方法體外面定義的內部類的訪問型別可以是public,protecte,預設的,private等4種型別,這就好像類中定義的成員變數有4種訪問型別一樣,它們決定這個內部類的定義對其他類是否可見;對於這種情況,我們也可以在外面建立內部類的例項物件,建立內部類的例項物件時,一定要先建立外部類的例項物件,然後用這個外部類的例項物件去建立內部類的例項物件,程式碼如下:

1 Outer outer = new Outer();
2 
3 Outer.Inner1 inner1 = outer.newInnner1();

在方法內部定義的內部類前面不能有訪問型別修飾符,就好像方法中定義的區域性變數一樣,但這種內部類的前面可以使用final或abstract修飾符。這種內部類對其他類是不可見的其他類無法引用這種內部類,但是這種內部類建立的例項物件可以傳遞給其他類訪問。這種內部類必須是先定義,後使用,即內部類的定義程式碼必須出現在使用該類之前,這與方法中的區域性變數必須先定義後使用的道理也是一樣的。這種內部類可以訪問方法體中的區域性變數,但是,該區域性變數前必須加final修飾符。

對於這些細節,只要在eclipse寫程式碼試試,根據開發工具提示的各類錯誤資訊就可以馬上了解到。

在方法體內部還可以採用如下語法來建立一種匿名內部類,即定義某一介面或類的子類的同時,還建立了該子類的例項物件,無需為該子類定義名稱:

1 public class Outer 2
2 {
3     public void start() {
4         new Thread(new Runable() {
5             public void run() {
6             };
7         }).start();
8     }
9 }

最後,在方法外部定義的內部類前面可以加上static關鍵字,從而成為Static Nested Class,它不再具有內部類的特性,所有,從狹義上講,它不是內部類。Static Nested Class與普通類在執行時的行為和功能上沒有什麼區別,只是在程式設計引用時的語法上有一些差別,它可以定義成public、protected、預設的、private等多種型別,而普通類只能定義成public和預設的這兩種型別。在外面引用Static Nested Class類的名稱為“外部類名.內部類名”。在外面不需要建立外部類的例項物件,就可以直接建立Static Nested Class,例如,假設Inner是定義在Outer類中的Static Nested Class,那麼可以使用如下語句建立Inner類:

1 Outer.Inner inner = new Outer.Inner();

由於static Nested Class不依賴於外部類的例項物件,所以,static Nested Class能訪問外部類的非static成員變數。當在外部類中訪問Static Nested Class時,可以直接使用Static Nested Class的名字,而不需要加上外部類的名字了,在Static Nested Class中也可以直接引用外部類的static的成員變數,不需要加上外部類的名字。

在靜態方法中定義的內部類也是Static Nested Class,這時候不能在類前面加static關鍵字,靜態方法中的Static Nested Class與普通方法中的內部類的應用方式很相似,它除了可以直接訪問外部類中的static的成員變數,還可以訪問靜態方法中的區域性變數,但是,該區域性變數前必須加final修飾符。

備註:首先根據你的印象說出你對內部類的總體方面的特點:例如,在兩個地方可以定義,可以訪問外部類的成員變數,不能定義靜態成員,這是大的特點。然後再說一些細節方面的知識,例如,幾種定義方式的語法區別,靜態內部類,以及匿名內部類。

27、內部類可以引用它的包含類的成員嗎?有沒有什麼限制?

完全可以。如果不是靜態內部類,那沒有什麼限制!

如果你把靜態巢狀類當作內部類的一種特例,那在這種情況下不可以訪問外部類的普通成員變數,而只能訪問外部類中的靜態成員,例如,下面的程式碼:

1 class Outer {
2     static int x;
3 
4     static class Inner {
5         void test() {
6             System.out.println(x);
7         }
8     }
9 }

答題時,也要能察言觀色,揣摩提問者的心思,顯然人家希望你說的是靜態內部類不能訪問外部類的成員,但你一上來就頂牛,這不好,要先順著人家,讓人家滿意,然後再說特殊情況,讓人家吃驚。

28、Anonymous Inner Class (匿名內部類) 是否可以extends(繼承)其它類,是否可以implements(實現)interface(介面)?

可以繼承其他類或實現其他介面。不僅是可以,而是必須!

29、super.getClass()方法呼叫

下面程式的輸出結果是多少?

 1 import java.util.Date;
 2 public class Testextends Date
 3 {
 4     public static void main(String[] args) {
 5         new Test().test();
 6     }
 7     public void test() {
 8         System.out.println(super.getClass().getName());
 9     }
10 }

很奇怪,結果是Test

這屬於腦筋急轉彎的題目,在一個qq群有個網友正好問過這個問題,我覺得挺有趣,就研究了一下,沒想到今天還被你面到了,哈哈。

在test方法中,直接呼叫getClass().getName()方法,返回的是Test類名

由於getClass()在Object類中定義成了final,子類不能覆蓋該方法,所以,在

test方法中呼叫getClass().getName()方法,其實就是在呼叫從父類繼承的getClass()方法,等效於呼叫super.getClass().getName()方法,所以,super.getClass().getName()方法返回的也應該是Test。

如果想得到父類的名稱,應該用如下程式碼:

1 getClass().getSuperClass().getName();

30、String是最基本的資料型別嗎?

基本資料型別包括byte、int、char、long、float、double、boolean和short。

java.lang.String類是final型別的,因此不可以繼承這個類、不能修改這個類。為了提高效率節省空間,我們應該用StringBuffer類

31、String s = "Hello";s = s + " world!";這兩行程式碼執行後,原始的String物件中的內容到底變了沒有?

沒有。因為String被設計成不可變(immutable)類,所以它的所有物件都是不可變物件。在這段程式碼中,s原先指向一個String物件,內容是 "Hello",然後我們對s進行了+操作,那麼s所指向的那個物件是否發生了改變呢?答案是沒有。這時,s不指向原來那個物件了,而指向了另一個String物件,內容為"Hello world!",原來那個物件還存在於記憶體之中,只是s這個引用變數不再指向它了。

通過上面的說明,我們很容易匯出另一個結論,如果經常對字串進行各種各樣的修改,或者說,不可預見的修改,那麼使用String來代表字串的話會引起很大的記憶體開銷。因為String物件建立之後不能再改變,所以對於每一個不同的字串,都需要一個String物件來表示。這時,應該考慮使用StringBuffer類,它允許修改,而不是每個不同的字串都要生成一個新的物件。並且,這兩種類的物件轉換十分容易。
同時,我們還可以知道,如果要使用內容相同的字串,不必每次都new一個String。例如我們要在構造器中對一個名叫s的String引用變數進行初始化,把它設定為初始值,應當這樣做:

1 public class Demo {
2 private String s;
3 ...
4 public Demo {
5 s = "Initial Value";
6 }
7 ...
8 }

而非

1 s = new String("Initial Value");

後者每次都會呼叫構造器,生成新物件,效能低下且記憶體開銷大,並且沒有意義,因為String物件不可改變,所以對於內容相同的字串,只要一個String物件來表示就可以了。也就說,多次呼叫上面的構造器建立多個物件,他們的String型別屬性s都指向同一個物件。
上面的結論還基於這樣一個事實:對於字串常量,如果內容相同,Java認為它們代表同一個String物件。而用關鍵字new呼叫構造器,總是會建立一個新的物件,無論內容是否相同。
至於為什麼要把String類設計成不可變類,是它的用途決定的。其實不只String,很多Java標準類庫中的類都是不可變的。在開發一個系統的時候,我們有時候也需要設計不可變類,來傳遞一組相關的值,這也是物件導向思想的體現。不可變類有一些優點,比如因為它的物件是隻讀的,所以多執行緒併發訪問也不會有任何問題。當然也有一些缺點,比如每個不同的狀態都要一個物件來代表,可能會造成效能上的問題。所以Java標準類庫還提供了一個可變版本,即StringBuffer。

32、是否可以繼承String類?

String類是final類故不可以繼承。

33、String s = new String("xyz");建立了幾個String Object? 二者之間有什麼區別?

兩個或一個,”xyz”對應一個物件,這個物件放在字串常量緩衝區,常量”xyz”不管出現多少遍,都是緩衝區中的那一個。New String每寫一遍,就建立一個新的物件,它一句那個常量”xyz”物件的內容來建立出一個新String物件。如果以前就用過’xyz’,這句代表就不會建立”xyz”自己了,直接從緩衝區拿。

34、String 和StringBuffer的區別

JAVA平臺提供了兩個類:String和StringBuffer,它們可以儲存和操作字串,即包含多個字元的字元資料。這個String類提供了數值不可改變的字串。而這個StringBuffer類提供的字串進行修改。當你知道字元資料要改變的時候你就可以使用StringBuffer。典型地,你可以使用StringBuffers來動態構造字元資料。另外,String實現了equals方法,new String(“abc”).equals(newString(“abc”)的結果為true,而StringBuffer沒有實現equals方法,所以,new StringBuffer(“abc”).equals(new StringBuffer(“abc”)的結果為false。

接著要舉一個具體的例子來說明,我們要把1到100的所有數字拼起來,組成一個串。

1 StringBuffer sbf =new StringBuffer(); 
2 for(inti=0;i<100;i++)
3 {
4    sbf.append(i);
5 }

上面的程式碼效率很高,因為只建立了一個StringBuffer物件,而下面的程式碼效率很低,因為建立了101個物件。

1 String str = newString(); 
2 for(inti=0;i<100;i++)
3 {
4    str = str + i;
5 }

在講兩者區別時,應把迴圈的次數搞成10000,然後用endTime-beginTime來比較兩者執行的時間差異,最後還要講講StringBuilder與StringBuffer的區別。

String覆蓋了equals方法和hashCode方法,而StringBuffer沒有覆蓋equals方法和hashCode方法,所以,將StringBuffer物件儲存進Java集合類中時會出現問題。

35、如何把一段逗號分割的字串轉換成一個陣列?

如果不查jdk api,我很難寫出來!我可以說說我的思路:

1.用正規表示式,程式碼大概為:String [] result = orgStr.split(“,”);

2.用StingTokenizer ,程式碼為:StringTokenizer  tokener = StringTokenizer(orgStr,”,”);

1 String [] result = newString[tokener .countTokens()];
2 Int i=0;
3 while(tokener.hasNext(){result[i++]=toker.nextToken();}

36、陣列有沒有length()這個方法? String有沒有length()這個方法?

陣列沒有length()這個方法,有length的屬性。String有有length()這個方法。

37、下面這條語句一共建立了多少個物件:Strings="a"+"b"+"c"+"d";

答:對於如下程式碼:

1 String s1= "a";
2 
3 String s2= s1 + "b";
4 
5 String s3= "a" + "b";
6 
7 System.out.println(s2== "ab");
8 
9 System.out.println(s3== "ab");

第一條語句列印的結果為false,第二條語句列印的結果為true,這說明javac編譯可以對字串常量直接相加的表示式進行優化,不必要等到執行期去進行加法運算處理,而是在編譯時去掉其中的加號,直接將其編譯成一個這些常量相連的結果。

題目中的第一行程式碼被編譯器在編譯時優化後,相當於直接定義了一個”abcd”的字串,所以,上面的程式碼應該只建立了一個String物件。寫如下兩行程式碼,

1 String s = "a" +"b" + "c" + "d";
2 
3 System.out.println(s =="abcd");

最終列印的結果應該為true。

38、try {}裡有一個return語句,那麼緊跟在這個try後的finally {}裡的code會不會被執行,什麼時候被執行,在return前還是後?

也許你的答案是在return之前,但往更細地說,我的答案是在return中間執行,請看下面程式程式碼的執行結果:

 1 public class Test {
 2 
 3     public static void main(String[] args) {
 4         System.out.println(new Test().test());
 5     }
 6 
 7     static int test() {
 8         int x = 1;
 9         try {
10             return x;
11         } finally {
12             ++x;
13         }
14     }
15 }

---------執行結果 ---------

1

執行結果是1,為什麼呢?主函式呼叫子函式並得到結果的過程,好比主函式準備一個空罐子,當子函式要返回結果時,先把結果放在罐子裡,然後再將程式邏輯返回到主函式。所謂返回,就是子函式說,我不執行了,你主函式繼續執行吧,這沒什麼結果可言,結果是在說這話之前放進罐子裡的。

39、下面的程式程式碼輸出的結果是多少?

 1 public class smallT
 2 
 3 {
 4     public static void main(String args[]) {
 5         smallT t = new smallT();
 6         int b = t.get();
 7         System.out.println(b);
 8     }
 9 
10     public int get() {
11         try {
12             return 1;
13         } finally {
14             return 2;
15         }
16     }
17 }

返回的結果是2。

我可以通過下面一個例子程式來幫助我解釋這個答案,從下面例子的執行結果中可以發現,try中的return語句呼叫的函式先於finally中呼叫的函式執行,也就是說return語句先執行,finally語句後執行,所以,返回的結果是2。Return並不是讓函式馬上返回,而是return語句執行後,將把返回結果放置進函式棧中,此時函式並不是馬上返回,它要執行finally語句後才真正開始返回。

在講解答案時可以用下面的程式來幫助分析:

 1 public class Test {
 2 
 3     public static void main(String[] args) {
 4         System.out.println(newTest().test());
 5     }
 6 
 7     int test() {
 8         try {
 9             return func1();
10         } finally {
11             return func2();
12         }
13     }
14 
15     int func1() {
16         System.out.println("func1");
17         return 1;
18     }
19 
20     int func2() {
21         System.out.println("func2");
22         return 2;
23     }
24 }

-----------執行結果-----------------

1 func1
2 
3 func2
4 
5 2

結論:finally中的程式碼比return 和break語句後執行

40、final, finally, finalize的區別。

final 用於宣告屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承。

內部類要訪問區域性變數,區域性變數必須定義成final型別,例如,一段程式碼……

finally是異常處理語句結構的一部分,表示總是執行。

finalize是Object類的一個方法,在垃圾收集器執行的時候會呼叫被回收物件的此方法,可以覆蓋此方法提供垃圾收集時的其他資源回收,例如關閉檔案等。JVM不保證此方法總被呼叫

41、執行時異常與一般異常有何異同?

異常表示程式執行過程中可能出現的非正常狀態,執行時異常表示虛擬機器的通常操作中可能遇到的異常,是一種常見執行錯誤。java編譯器要求方法必須宣告丟擲可能發生的非執行時異常,但是並不要求必須宣告丟擲未被捕獲的執行時異常。

42、error和exception有什麼區別?

error 表示恢復不是不可能但很困難的情況下的一種嚴重問題。比如說記憶體溢位。不可能指望程式能處理這樣的情況。 exception 表示一種設計或實現問題。也就是說,它表示如果程式執行正常,從不會發生的情況。

43、Java中的異常處理機制的簡單原理和應用。

異常是指java程式執行時(非編譯)所發生的非正常情況或錯誤,與現實生活中的事件很相似,現實生活中的事件可以包含事件發生的時間、地點、人物、情節等資訊,可以用一個物件來表示,Java使用物件導向的方式來處理異常,它把程式中發生的每個異常也都分別封裝到一個物件來表示的,該物件中包含有異常的資訊。

Java對異常進行了分類,不同型別的異常分別用不同的Java類表示,所有異常的根類為java.lang.Throwable,Throwable下面又派生了兩個子類:Error和Exception,Error 表示應用程式本身無法克服和恢復的一種嚴重問題,程式只有死的份了,例如,說記憶體溢位和執行緒死鎖等系統問題。Exception表示程式還能夠克服和恢復的問題,其中又分為系統異常和普通異常,系統異常是軟體本身缺陷所導致的問題,也就是軟體開發人員考慮不周所導致的問題,軟體使用者無法克服和恢復這種問題,但在這種問題下還可以讓軟體系統繼續執行或者讓軟體死掉,例如,陣列指令碼越界(ArrayIndexOutOfBoundsException),空指標異常(NullPointerException)、類轉換異常(ClassCastException);普通異常是執行環境的變化或異常所導致的問題,是使用者能夠克服的問題,例如,網路斷線,硬碟空間不夠,發生這樣的異常後,程式不應該死掉。

java為系統異常和普通異常提供了不同的解決方案,編譯器強制普通異常必須try..catch處理或用throws宣告繼續拋給上層呼叫方法處理,所以普通異常也稱為checked異常,而系統異常可以處理也可以不處理,所以,編譯器不強制用try..catch處理或用throws宣告,所以系統異常也稱為unchecked異常。 

提示答題者:就按照三個級別去思考:虛擬機器必須當機的錯誤,程式可以死掉也可以不死掉的錯誤,程式不應該死掉的錯誤;

44、請寫出你最常見到的5個runtimeexception。

這道題主要考你的程式碼量到底多大,如果你長期寫程式碼的,應該經常都看到過一些系統方面的異常,你不一定真要回答出5個具體的系統異常,但你要能夠說出什麼是系統異常,以及幾個系統異常就可以了,當然,這些異常完全用其英文名稱來寫是最好的,如果實在寫不出,那就用中文吧,有總比沒有強!

所謂系統異常,就是…..,它們都是RuntimeException的子類,在jdk doc中查RuntimeException類,就可以看到其所有的子類列表,也就是看到了所有的系統異常。我比較有印象的系統異常有:NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException。

45、JAVA語言如何進行異常處理,關鍵字:throws,throw,try,catch,finally分別代表什麼意義?在try塊中可以丟擲異常嗎?

46、java中有幾種方法可以實現一個執行緒?用什麼關鍵字修飾同步方法? stop()和suspend()方法為何不推薦使用?

java5以前,有如下兩種:

第一種:

newThread(){}.start();這表示呼叫Thread子類物件的run方法,newThread(){}表示一個Thread的匿名子類的例項物件,子類加上run方法後的程式碼如下:

1 new Thread(){
2 
3    public void run(){
4 
5    }
6 
7 }.start();

第二種:

new Thread(newRunnable(){}).start();這表示呼叫Thread物件接受的Runnable物件的run方法,newRunnable(){}表示一個Runnable的匿名子類的例項物件,runnable的子類加上run方法後的程式碼如下:

1 new Thread(newRunnable(){
2 
3                public void run(){
4 
5                }    
6 
7         }
8 
9    ).start();

從java5開始,還有如下一些執行緒池建立多執行緒的方式:

 

 1 ExecutorService pool = Executors.newFixedThreadPool(3);
 2 
 3 for (int i = 0; i < 10; i++) {
 4     pool.execute(new Runnable() {
 5         @Override
 6         public void run() {
 7 
 8         }
 9     });
10 }
11 
12 Executors.newCachedThreadPool().execute(new Runnable() {
13     @Override
14     public void run() {
15 
16     }
17 });
18 
19 Executors.newSingleThreadExecutor().execute(new Runnable() {
20     @Override
21     public void run() {
22 
23     }
24 });

有兩種實現方法,分別使用new Thread()和newThread(runnable)形式,第一種直接呼叫thread的run方法,所以,我們往往使用Thread子類,即new SubThread()。第二種呼叫runnable的run方法。

有兩種實現方法,分別是繼承Thread類與實現Runnable介面

用synchronized關鍵字修飾同步方法

反對使用stop(),是因為它不安全。它會解除由執行緒獲取的所有鎖定,而且如果物件處於一種不連貫狀態,那麼其他執行緒能在那種狀態下檢查和修改它們。結果很難檢查出真正的問題所在。suspend()方法容易發生死鎖。呼叫suspend()的時候,目標執行緒會停下來,但卻仍然持有在這之前獲得的鎖定。此時,其他任何執行緒都不能訪問鎖定的資源,除非被"掛起"的執行緒恢復執行。對任何執行緒來說,如果它們想恢復目標執行緒,同時又試圖使用任何一個鎖定的資源,就會造成死鎖。所以不應該使用suspend(),而應在自己的Thread類中置入一個標誌,指出執行緒應該活動還是掛起。若標誌指出執行緒應該掛起,便用wait()命其進入等待狀態。若標誌指出執行緒應當恢復,則用一個notify()重新啟動執行緒。

47、sleep() 和 wait() 有什麼區別?

     (網上的答案:sleep是執行緒類(Thread)的方法,導致此執行緒暫停執行指定時間,給執行機會給其他執行緒,但是監控狀態依然保持,到時後會自動恢復。呼叫sleep不會釋放物件鎖。 wait是Object類的方法,對此物件呼叫wait方法導致本執行緒放棄物件鎖,進入等待此物件的等待鎖定池,只有針對此物件發出notify方法(或notifyAll)後本執行緒才進入物件鎖定池準備獲得物件鎖進入執行狀態。)

sleep就是正在執行的執行緒主動讓出cpu,cpu去執行其他執行緒,在sleep指定的時間過後,cpu才會回到這個執行緒上繼續往下執行,如果當前執行緒進入了同步鎖,sleep方法並不會釋放鎖,即使當前執行緒使用sleep方法讓出了cpu,但其他被同步鎖擋住了的執行緒也無法得到執行。wait是指在一個已經進入了同步鎖的執行緒內,讓自己暫時讓出同步鎖,以便其他正在等待此鎖的執行緒可以得到同步鎖並執行,只有其他執行緒呼叫了notify方法(notify並不釋放鎖,只是告訴呼叫過wait方法的執行緒可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因為鎖還在別人手裡,別人還沒釋放。如果notify方法後面的程式碼還有很多,需要這些程式碼執行完後才會釋放鎖,可以在notfiy方法後增加一個等待和一些程式碼,看看效果),呼叫wait方法的執行緒就會解除wait狀態和程式可以再次得到鎖後繼續向下執行。對於wait的講解一定要配合例子程式碼來說明,才顯得自己真明白。

 1 package com.huawei.interview;
 2 
 3 public class MultiThread {
 4 
 5     public static void main(String[] args) {
 6         new Thread(new Thread1()).start();
 7         try {
 8             Thread.sleep(10);
 9         } catch (InterruptedException e) {
10             e.printStackTrace();
11         }
12         new Thread(new Thread2()).start();
13     }
14 
15     private static class Thread1 implements Runnable {
16         @Override
17         public void run() {
18             // 由於這裡的Thread1和下面的Thread2內部run方法要用同一物件作為監視器,我們這裡不能用this,因為在Thread2裡面的this和這個Thread1的this不是同一個物件。我們用MultiThread.class這個位元組碼物件,當前虛擬機器裡引用這個變數時,指向的都是同一個物件。
19             synchronized (MultiThread.class) {
20                 System.out.println("enterthread1...");
21                 System.out.println("thread1 iswaiting");
22                 try {
23                     // 釋放鎖有兩種方式,第一種方式是程式自然離開監視器的範圍,也就是離開了synchronized關鍵字管轄的程式碼範圍,另一種方式就是在synchronized關鍵字管轄的程式碼內部呼叫監視器物件的wait方法。這裡,使用wait方法釋放鎖。
24                     MultiThread.class.wait();
25                 } catch (InterruptedException e) {
26                     e.printStackTrace();
27                 }
28                 System.out.println("thread1 is goingon...");
29                 System.out.println("thread1 is beingover!");
30             }
31         }
32     }
33 
34     private static class Thread2 implements Runnable {
35         @Override
36         public void run() {
37             synchronized (MultiThread.class) {
38                 System.out.println("enterthread2...");
39                 System.out.println("thread2 notify otherthread can release wait status..");
40                 // 由於notify方法並不釋放鎖,即使thread2呼叫下面的sleep方法休息了10毫秒,但thread1仍然不會執行,因為thread2沒有釋放鎖,所以Thread1無法得不到鎖。
41                 MultiThread.class.notify();
42                 System.out.println("thread2 is sleeping tenmillisecond...");
43                 try {
44                     Thread.sleep(10);
45                 } catch (InterruptedException e) {
46                     e.printStackTrace();
47                 }
48                 System.out.println("thread2 is goingon...");
49                 System.out.println("thread2 is beingover!");
50             }
51         }
52     }
53 }

48、同步和非同步有何異同,在什麼情況下分別使用他們?舉例說明。

如果資料將線上程間共享。例如正在寫的資料以後可能被另一個執行緒讀到,或者正在讀的資料可能已經被另一個執行緒寫過了,那麼這些資料就是共享資料,必須進行同步存取。

當應用程式在物件上呼叫了一個需要花費很長時間來執行的方法,並且不希望讓程式等待方法的返回時,就應該使用非同步程式設計,在很多情況下采用非同步途徑往往更有效率。

49. 下面兩個方法同步嗎?(自己發明)

1 class Test {
2     synchronized static void sayHello3() {
3     }
4 
5     synchronized void getX() {
6     }
7 }

50、多執行緒有幾種實現方法?同步有幾種實現方法?

多執行緒有兩種實現方法,分別是繼承Thread類與實現Runnable介面

同步的實現方面有兩種,分別是synchronized,wait與notify

wait():使一個執行緒處於等待狀態,並且釋放所持有的物件的lock。

sleep():使一個正在執行的執行緒處於睡眠狀態,是一個靜態方法,呼叫此方法要捕捉InterruptedException異常。

notify():喚醒一個處於等待狀態的執行緒,注意的是在呼叫此方法的時候,並不能確切的喚醒某一個等待狀態的執行緒,而是由JVM確定喚醒哪個執行緒,而且不是按優先順序。

Allnotity():喚醒所有處入等待狀態的執行緒,注意並不是給所有喚醒執行緒一個物件的鎖,而是讓它們競爭。

51、啟動一個執行緒是用run()還是start()? .

啟動一個執行緒是呼叫start()方法,使執行緒就緒狀態,以後可以被排程為執行狀態,一個執行緒必須關聯一些具體的執行程式碼,run()方法是該執行緒所關聯的執行程式碼。

52、當一個執行緒進入一個物件的一個synchronized方法後,其它執行緒是否可進入此物件的其它方法?

分幾種情況:

     1.其他方法前是否加了synchronized關鍵字,如果沒加,則能。

     2.如果這個方法內部呼叫了wait,則可以進入其他synchronized方法。

     3.如果其他個方法都加了synchronized關鍵字,並且內部沒有呼叫wait,則不能。

     4.如果其他方法是static,它用的同步鎖是當前類的位元組碼,與非靜態的方法不能同步,因為非靜態的方法用的是this。

53、執行緒的基本概念、執行緒的基本狀態以及狀態之間的關係

一個程式中可以有多條執行線索同時執行,一個執行緒就是程式中的一條執行線索,每個執行緒上都關聯有要執行的程式碼,即可以有多段程式程式碼同時執行,每個程式至少都有一個執行緒,即main方法執行的那個執行緒。如果只是一個cpu,它怎麼能夠同時執行多段程式呢?這是從巨集觀上來看的,cpu一會執行a線索,一會執行b線索,切換時間很快,給人的感覺是a,b在同時執行,好比大家在同一個辦公室上網,只有一條連結到外部網線,其實,這條網線一會為a傳資料,一會為b傳資料,由於切換時間很短暫,所以,大家感覺都在同時上網。

  狀態:就緒,執行,synchronize阻塞,wait和sleep掛起,結束。wait必須在synchronized內部呼叫。

呼叫執行緒的start方法後執行緒進入就緒狀態,執行緒排程系統將就緒狀態的執行緒轉為執行狀態,遇到synchronized語句時,由執行狀態轉為阻塞,當synchronized獲得鎖後,由阻塞轉為執行,在這種情況可以呼叫wait方法轉為掛起狀態,當執行緒關聯的程式碼執行完後,執行緒變為結束狀態。

54、簡述synchronized和java.util.concurrent.locks.Lock的異同?

主要相同點:Lock能完成synchronized所實現的所有功能

主要不同點:Lock有比synchronized更精確的執行緒語義和更好的效能。synchronized會自動釋放鎖,而Lock一定要求程式設計師手工釋放,並且必須在finally從句中釋放。Lock還有更強大的功能,例如,它的tryLock方法可以非阻塞方式去拿鎖。

舉例說明(對下面的題用lock進行了改寫):

 1 package com.huawei.interview;
 2 
 3 import java.util.concurrent.locks.Lock;
 4 
 5 import java.util.concurrent.locks.ReentrantLock;
 6 
 7 public class ThreadTest {
 8 
 9     private int j;
10 
11     private Lock lock = new ReentrantLock();
12 
13     public static void main(String[] args) {
14         ThreadTest tt = new ThreadTest();
15         for (int i = 0; i < 2; i++) {
16             new Thread(tt.new Adder()).start();
17             new Thread(tt.new Subtractor()).start();
18         }
19     }
20 
21     private class Subtractor implements Runnable {
22         @Override
23         public void run() {
24             while (true) {
25                 /*
26                  * synchronized (ThreadTest.this) {
27                  * 
28                  * System.out.println("j--=" + j--);
29                  * 
30                  * //這裡拋異常了,鎖能釋放嗎?
31                  * 
32                  * }
33                  */
34                 lock.lock();
35                 try {
36                     System.out.println("j--=" + j--);
37                 } finally {
38                     lock.unlock();
39                 }
40             }
41         }
42     }
43 
44     private class Adder implements Runnable {
45         @Override
46         public void run() {
47             while (true) {
48                 /*
49                  * synchronized (ThreadTest.this) {
50                  * 
51                  * System.out.println("j++=" + j++);
52                  * 
53                  * }
54                  */
55                 lock.lock();
56                 try {
57                     System.out.println("j++=" + j++);
58                 } finally {
59                     lock.unlock();
60                 }
61             }
62         }
63     }
64 }

55、設計4個執行緒,其中兩個執行緒每次對j增加1,另外兩個執行緒對j每次減少1。寫出程式。

以下程式使用內部類實現執行緒,對j增減的時候沒有考慮順序問題。

 1 public class ThreadTest1
 2 
 3 {
 4     private int j;
 5 
 6     public static void main(String args[]) {
 7         ThreadTest1 tt = new ThreadTest1();
 8         Inc inc = tt.new Inc();
 9         Dec dec = tt.new Dec();
10         for (int i = 0; i < 2; i++) {
11             Thread t = new Thread(inc);
12             t.start();
13             t = new Thread(dec);
14             t.start();
15         }
16     }
17 
18     private synchronized void inc() {
19         j++;
20         System.out.println(Thread.currentThread().getName() + "-inc:" + j);
21     }
22 
23     private synchronized void dec() {
24         j--;
25         System.out.println(Thread.currentThread().getName() + "-dec:" + j);
26     }
27 
28     class Inc implements Runnable {
29         public void run() {
30             for (int i = 0; i < 100; i++) {
31                 inc();
32             }
33         }
34     }
35 
36     class Dec implements Runnable {
37         public void run() {
38             for (int i = 0; i < 100; i++) {
39                 dec();
40             }
41         }
42     }
43

----------隨手再寫的一個-------------

 1 public class A {
 2     JManger j = new JManager();
 3 
 4     public static void main(String[] args) {
 5         new A().call();
 6     }
 7 
 8 void call
 9     {
10    for(int i=0;i<2;i++){
11         new Thread(
12                new Runnable(){ public void run(){while(true){j.accumulate()}}}
13         ).start();
14         new Thread(new Runnable(){ public void run(){while(true){j.sub()}}}).start();
15    }
16 }
17 }
18 
19 class JManager {
20     private j = 0;
21    public synchronized void subtract()
22    {
23         j--
24    }
25 
26     public synchronized void accumulate() {
27         j++;
28     }
29 }

56、子執行緒迴圈10次,接著主執行緒迴圈100,接著又回到子執行緒迴圈10次,接著再回到主執行緒又迴圈100,如此迴圈50次,請寫出程式。

最終的程式程式碼如下:

 1 public class ThreadTest {
 2 
 3     public static void main(String[] args) {
 4         new ThreadTest().init();
 5     }
 6 
 7     public void init() {
 8         final Business business = new Business();
 9         new Thread(new Runnable() {
10             public void run() {
11                 for (int i = 0; i < 50; i++) {
12                     business.SubThread(i);
13                 }
14             }
15         }).start();
16 
17         for (int i = 0; i < 50; i++) {
18             business.MainThread(i);
19         }
20     }
21 
22     private class Business {
23         boolean bShouldSub = true;// 這裡相當於定義了控制該誰執行的一個訊號燈
24 
25         public synchronized void MainThread(int i) {
26             if (bShouldSub)
27                 try {
28                     this.wait();
29                 } catch (InterruptedException e) {
30                     e.printStackTrace();
31                 }
32             for (int j = 0; j < 5; j++) {
33                 System.out.println(Thread.currentThread().getName() + ":i=" + i + ",j=" + j);
34             }
35             bShouldSub = true;
36             this.notify();
37         }
38 
39         public synchronized void SubThread(int i) {
40             if (!bShouldSub)
41                 try {
42                     this.wait();
43                 } catch (InterruptedException e) {
44                     e.printStackTrace();
45                 }
46 
47             for (int j = 0; j < 10; j++) {
48                 System.out.println(Thread.currentThread().getName() + ":i=" + i + ",j=" + j);
49             }
50             bShouldSub = false;
51             this.notify();
52         }
53     }
54 
55 }

備註:不可能一上來就寫出上面的完整程式碼,最初寫出來的程式碼如下,問題在於兩個執行緒的程式碼要參照同一個變數,即這兩個執行緒的程式碼要共享資料,所以,把這兩個執行緒的執行程式碼搬到同一個類中去:

 

 1 public class ThreadTest {
 2 
 3     private static boolean bShouldMain = false;
 4 
 5     public static void main(String[] args) {
 6 
 7         // new Thread() {
 8         // public void run() {
 9         // for (int i = 0; i < 50; i++) {
10         // for (int j = 0; j < 10; j++) {
11         // System.out.println("i=" + i + ",j=" + j);
12         // }
13         // }
14         // }
15         // }.start();
16 
17         // final String str = new String("");
18 
19         new Thread(new Runnable() {
20             public void run() {
21                 for (int i = 0; i < 50; i++) {
22                     synchronized (ThreadTest.class) {
23                         if (bShouldMain) {
24                             try {
25                                 ThreadTest.class.wait();
26                             } catch (InterruptedException e) {
27                                 e.printStackTrace();
28                             }
29                         }
30                         for (int j = 0; j < 10; j++) {
31                             System.out.println(Thread.currentThread().getName() + "i=" + i + ",j=" + j);
32                         }
33                         bShouldMain = true;
34                         ThreadTest.class.notify();
35                     }
36                 }
37             }
38         }).start();
39         for (int i = 0; i < 50; i++) {
40             synchronized (ThreadTest.class) {
41                 if (!bShouldMain) {
42                     try {
43                         ThreadTest.class.wait();
44                     } catch (InterruptedException e) {
45                         e.printStackTrace();
46                     }
47                 }
48                 for (int j = 0; j < 5; j++) {
49                     System.out.println(Thread.currentThread().getName() + "i=" + i + ",j=" + j);
50                 }
51                 bShouldMain = false;
52                 ThreadTest.class.notify();
53             }
54         }
55     }
56 }

下面使用jdk5中的併發庫來實現的:

 1 import java.util.concurrent.ExecutorService;
 2 import java.util.concurrent.Executors;
 3 import java.util.concurrent.locks.Condition;
 4 import java.util.concurrent.locks.Lock;
 5 import java.util.concurrent.locks.ReentrantLock;
 6 
 7 public class ThreadTest {
 8     private static Lock lock = new ReentrantLock();
 9     private static Condition subThreadCondition = lock.newCondition();
10     private static boolean bBhouldSubThread = false;
11 
12     public static void main(String[] args) {
13         ExecutorService threadPool = Executors.newFixedThreadPool(3);
14         threadPool.execute(new Runnable() {
15             public void run() {
16                 for (int i = 0; i < 50; i++) {
17                     lock.lock();
18                     try {
19                         if (!bBhouldSubThread)
20                             subThreadCondition.await();
21                         for (int j = 0; j < 10; j++) {
22                             System.out.println(Thread.currentThread().getName() + ",j=" + j);
23                         }
24                         bBhouldSubThread = false;
25                         subThreadCondition.signal();
26                     } catch (Exception e) {
27                     } finally {
28                         lock.unlock();
29                     }
30                 }
31             }
32         });
33         threadPool.shutdown();
34         for (int i = 0; i < 50; i++) {
35             lock.lock();
36             try {
37                 if (bBhouldSubThread)
38                     subThreadCondition.await();
39                 for (int j = 0; j < 10; j++) {
40                     System.out.println(Thread.currentThread().getName() + ",j=" + j);
41                 }
42                 bBhouldSubThread = true;
43                 subThreadCondition.signal();
44             } catch (Exception e) {
45             } finally {
46                 lock.unlock();
47             }
48         }
49     }
50 }

57、介紹Collection框架的結構

答:隨意發揮題,天南海北誰便談,只要讓別覺得你知識淵博,理解透徹即可。

58、Collection框架中實現比較要實現什麼介面

1    comparable/comparator

59、ArrayList和Vector的區別

答:

這兩個類都實現了List介面(List介面繼承了Collection介面),他們都是有序集合,即儲存在這兩個集合中的元素的位置都是有順序的,相當於一種動態的陣列,我們以後可以按位置索引號取出某個元素,,並且其中的資料是允許重複的,這是HashSet之類的集合的最大不同處,HashSet之類的集合不可以按索引號去檢索其中的元素,也不允許有重複的元素(本來題目問的與hashset沒有任何關係,但為了說清楚ArrayList與Vector的功能,我們使用對比方式,更有利於說明問題)。

接著才說ArrayList與Vector的區別,這主要包括兩個方面:. 
(1)同步性:

       Vector是執行緒安全的,也就是說是它的方法之間是執行緒同步的,而ArrayList是執行緒序不安全的,它的方法之間是執行緒不同步的。如果只有一個執行緒會訪問到集合,那最好是使用ArrayList,因為它不考慮執行緒安全,效率會高些;如果有多個執行緒會訪問到集合,那最好是使用Vector,因為不需要我們自己再去考慮和編寫執行緒安全的程式碼。

備註:對於Vector&ArrayList、Hashtable&HashMap,要記住執行緒安全的問題,記住Vector與Hashtable是舊的,是java一誕生就提供了的,它們是執行緒安全的,ArrayList與HashMap是java2時才提供的,它們是執行緒不安全的。所以,我們講課時先講老的。
(2)資料增長:

       ArrayList與Vector都有一個初始的容量大小,當儲存進它們裡面的元素的個數超過了容量時,就需要增加ArrayList與Vector的儲存空間,每次要增加儲存空間時,不是隻增加一個儲存單元,而是增加多個儲存單元,每次增加的儲存單元的個數在記憶體空間利用與程式效率之間要取得一定的平衡。Vector預設增長為原來兩倍,而ArrayList的增長策略在文件中沒有明確規定(從原始碼看到的是增長為原來的1.5倍)。ArrayList與Vector都可以設定初始的空間大小,Vector還可以設定增長的空間大小,而ArrayList沒有提供設定增長空間的方法。

    總結:即Vector增長原來的一倍,ArrayList增加原來的0.5倍。

60、HashMap和Hashtable的區別

(條理上還需要整理,也是先說相同點,再說不同點)

HashMap是Hashtable的輕量級實現(非執行緒安全的實現),他們都完成了Map介面,主要區別在於HashMap允許空(null)鍵值(key),由於非執行緒安全,在只有一個執行緒訪問的情況下,效率要高於Hashtable。

HashMap允許將null作為一個entry的key或者value,而Hashtable不允許。

HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因為contains方法容易讓人引起誤解。

Hashtable繼承自Dictionary類,而HashMap是Java1.2引進的Mapinterface的一個實現。

最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多個執行緒訪問Hashtable時,不需要自己為它的方法實現同步,而HashMap 就必須為之提供外同步。

Hashtable和HashMap採用的hash/rehash演算法都大概一樣,所以效能不會有很大的差異。

就HashMap與HashTable主要從三方面來說。 
一.歷史原因:Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map介面的一個實現 
二.同步性:Hashtable是執行緒安全的,也就是說是同步的,而HashMap是執行緒序不安全的,不是同步的 
三.值:只有HashMap可以讓你將空值作為一個表的條目的key或value

61、List 和 Map 區別?

一個是儲存單列資料的集合,另一個是儲存鍵和值這樣的雙列資料的集合,List中儲存的資料是有順序,並且允許重複;Map中儲存的資料是沒有順序的,其鍵是不能重複的,它的值是可以有重複的。

62、List, Set, Map是否繼承自Collection介面?

   List,Set是,Map不是

63、List、Map、Set三個介面,存取元素時,各有什麼特點?

這樣的題屬於隨意發揮題:這樣的題比較考水平,兩個方面的水平:一是要真正明白這些內容,二是要有較強的總結和表述能力。如果你明白,但表述不清楚,在別人那裡則等同於不明白。

  首先,List與Set具有相似性,它們都是單列元素的集合,所以,它們有一個功共同的父介面,叫Collection。Set裡面不允許有重複的元素,所謂重複,即不能有兩個相等(注意,不是僅僅是相同)的物件,即假設Set集合中有了一個A物件,現在我要向Set集合再存入一個B物件,但B物件與A物件equals相等,則B物件儲存不進去,所以,Set集合的add方法有一個boolean的返回值,當集合中沒有某個元素,此時add方法可成功加入該元素時,則返回true,當集合含有與某個元素equals相等的元素時,此時add方法無法加入該元素,返回結果為false。Set取元素時,沒法說取第幾個,只能以Iterator介面取得所有的元素,再逐一遍歷各個元素。

       List表示有先後順序的集合,注意,不是那種按年齡、按大小、按價格之類的排序。當我們多次呼叫add(Obj e)方法時,每次加入的物件就像火車站買票有排隊順序一樣,按先來後到的順序排序。有時候,也可以插隊,即呼叫add(int index,Obj e)方法,就可以指定當前物件在集合中的存放位置。一個物件可以被反覆儲存進List中,每呼叫一次add方法,這個物件就被插入進集合中一次,其實,並不是把這個物件本身儲存進了集合中,而是在集合中用一個索引變數指向這個物件,當這個物件被add多次時,即相當於集合中有多個索引指向了這個物件,如圖x所示。List除了可以以Iterator介面取得所有的元素,再逐一遍歷各個元素之外,還可以呼叫get(index i)來明確說明取第幾個。

       Map與List和Set不同,它是雙列的集合,其中有put方法,定義如下:put(obj key,obj value),每次儲存時,要儲存一對key/value,不能儲存重複的key,這個重複的規則也是按equals比較相等。取則可以根據key獲得相應的value,即get(Object key)返回值為key所對應的value。另外,也可以獲得所有的key的結合,還可以獲得所有的value的結合,還可以獲得key和value組合成的Map.Entry物件的集合。

  List 以特定次序來持有元素,可有重複元素。Set 無法擁有重複元素,內部排序。Map 儲存key-value值,value可多值。

  HashSet按照hashcode值的某種運算方式進行儲存,而不是直接按hashCode值的大小進行儲存。例如,"abc" ---> 78,"def"---> 62,"xyz" ---> 65在hashSet中的儲存順序不是62,65,78,這些問題感謝以前一個叫崔健的學員提出,最後通過檢視原始碼給他解釋清楚,看本次培訓學員當中有多少能看懂原始碼。LinkedHashSet按插入的順序儲存,那被儲存物件的hashcode方法還有什麼作用呢?學員想想!hashset集合比較兩個物件是否相等,首先看hashcode方法是否相等,然後看equals方法是否相等。new 兩個Student插入到HashSet中,看HashSet的size,實現hashcode和equals方法後再看size。

  同一個物件可以在Vector中加入多次。往集合裡面加元素,相當於集合裡用一根繩子連線到了目標物件。往HashSet中卻加不了多次的。

64、說出ArrayList,Vector, LinkedList的儲存效能和特性

  ArrayList和Vector都是使用陣列方式儲存資料,此陣列元素數大於實際儲存的資料以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及陣列元素移動等記憶體操作,所以索引資料快而插入資料慢,Vector由於使用了synchronized方法(執行緒安全),通常效能上較ArrayList差,而LinkedList使用雙向連結串列實現儲存,按序號索引資料需要進行前向或後向遍歷,但是插入資料時只需要記錄本項的前後項即可,所以插入速度較快。

  LinkedList也是執行緒不安全的,LinkedList提供了一些方法,使得LinkedList可以被當作堆疊和佇列來使用。

65、去掉一個Vector集合中重複的元素

1 Vector newVector = new Vector();
2 for (int i = 0; i < newVector.size(); i++) {
3     Object obj = newVector.get(i);
4     if (!newVector.contains(obj))
5         ;
6     newVector.add(obj);
7 }

還有一種簡單的方式

1 HashSet set = new HashSet(vector);

66、Collection 和 Collections的區別。

Collection是集合類的上級介面,繼承與他的介面主要有Set和List.

Collections是針對集合類的一個幫助類,他提供一系列靜態方法實現對各種集合的搜尋、排序、執行緒安全化等操作。

67、Set裡的元素是不能重複的,那麼用什麼方法來區分重複與否呢? 是用==還是equals()? 它們有何區別?

Set裡的元素是不能重複的,元素重複與否是使用equals()方法進行判斷的。

equals()和==方法決定引用值是否指向同一物件equals()在類中被覆蓋,為的是當兩個分離的物件的內容和型別相配的話,返回真值。

68、你所知道的集合類都有哪些?主要方法?

最常用的集合類是 List 和 Map。List 的具體實現包括 ArrayList 和 Vector,它們是可變大小的列表,比較適合構建、儲存和操作任何型別物件的元素列表。 List 適用於按數值索引訪問元素的情形。

Map 提供了一個更通用的元素儲存方法。 Map 集合類用於儲存元素對(稱作"鍵"和"值"),其中每個鍵對映到一個值。

 1 ArrayList/Vector
 2 
 3 Collection
 4 
 5 HashSet/TreeSet
 6 
 7 Propeties HashTable
 8 
 9 Map
10 
11 Treemap/HashMap

我記的不是方法名,而是思想,我知道它們都有增刪改查的方法,但這些方法的具體名稱,我記得不是很清楚,對於set,大概的方法是add,remove,contains;對於map,大概的方法就是put,remove,contains等,因為,我只要在eclispe下按點操作符,很自然的這些方法就出來了。我記住的一些思想就是List類會有get(int index)這樣的方法,因為它可以按順序取元素,而set類中沒有get(int index)這樣的方法。List和set都可以迭代出所有元素,迭代時先要得到一個iterator物件,所以,set和list類都有一個iterator方法,用於返回那個iterator物件。map可以返回三個集合,一個是返回所有的key的集合,另外一個返回的是所有value的集合,再一個返回的key和value組合成的EntrySet物件的集合,map也有get方法,引數是key,返回值是key對應的value。

69、兩個物件值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對不對?

對。

如果物件要儲存在HashSet或HashMap中,它們的equals相等,那麼,它們的hashcode值就必須相等。

如果不是要儲存在HashSet或HashMap,則與hashcode沒有什麼關係了,這時候hashcode不等是可以的,例如arrayList儲存的物件就不用實現hashcode,當然,我們沒有理由不實現,通常都會去實現的。

70、TreeSet裡面放物件,如果同時放入了父類和子類的例項物件,那比較時使用的是父類的compareTo方法,還是使用的子類的compareTo方法,還是拋異常!

(應該是沒有針對問題的確切的答案,當前的add方法放入的是哪個物件,就呼叫哪個物件的compareTo方法,至於這個compareTo方法怎麼做,就看當前這個物件的類中是如何編寫這個方法的)

實驗程式碼:

 1 import java.util.TreeSet;
 2 
 3 public class Parent implements Comparable {
 4     private int age = 0;
 5 
 6     public Parent(int age) {
 7         this.age = age;
 8     }
 9 
10     public int compareTo(Object o) {
11         System.out.println("method of parent");
12         Parent o1 = (Parent) o;
13         return age > o1.age ? 1 : age < o1.age ? -1 : 0;
14     }
15 }
16 
17 class Child extends Parent {
18     public Child() {
19         super(3);
20     }
21 
22     public int compareTo(Object o) {
23         System.out.println("method of child");
24         return 1;
25     }
26 }
27 
28 class TreeSetTest {
29     public static void main(String[] args) {
30         TreeSet set = new TreeSet();
31         set.add(new Parent(3));
32         set.add(new Child());
33         set.add(new Parent(4));
34         System.out.println(set.size());
35     }
36 }

71、說出一些常用的類,包,介面,請各舉5個

要讓人家感覺你對java ee開發很熟,所以,不能僅僅只列core java中的那些東西,要多列你在做ssh專案中涉及的那些東西。就寫你最近寫的那些程式中涉及的那些類。

常用的類:

 1 BufferedReader, 
 2 BufferedWriter,  
 3 FileReader,  
 4 FileWirter, 
 5 String,  
 6 Integer,
 7 
 8 java.util.Date,
 9 System,
10 Class,
11 List,
12 HashMap

常用的包:

1 java.lang,  
2 java.io,  
3 java.util,  
4 java.sql,
5 javax.servlet,
6 org.apache.strtuts.action,
7 org.hibernate

常用的介面:

 1 Remote,
 2 List,
 3 Map,
 4 Document,
 5 NodeList,
 6 Servlet,
 7 HttpServletRequest,
 8 HttpServletResponse,
 9 Transaction(Hibernate),
10 Session(Hibernate),
11 HttpSession

72、java中有幾種型別的流?JDK為每種型別的流提供了一些抽象類以供繼承,請說出他們分別是哪些類?

位元組流,字元流。位元組流繼承於InputStream OutputStream,字元流繼承於InputStreamReader OutputStreamWriter。在java.io包中還有許多其他的流,主要是為了提高效能和使用方便。

73、位元組流與字元流的區別

       要把一片二進位制資料資料逐一輸出到某個裝置中,或者從某個裝置中逐一讀取一片二進位制資料,不管輸入輸出裝置是什麼,我們要用統一的方式來完成這些操作,用一種抽象的方式進行描述,這個抽象描述方式起名為IO流,對應的抽象類為OutputStream和InputStream,不同的實現類就代表不同的輸入和輸出裝置,它們都是針對位元組進行操作的。

       在應用中,經常要完全是字元的一段文字輸出去或讀進來,用位元組流可以嗎?計算機中的一切最終都是二進位制的位元組形式存在。對於“中國”這些字元,首先要得到其對應的位元組,然後將位元組寫入到輸出流。讀取時,首先讀到的是位元組,可是我們要把它顯示為字元,我們需要將位元組轉換成字元。由於這樣的需求很廣泛,人家專門提供了字元流的包裝類。

  底層裝置永遠只接受位元組資料,有時候要寫字串到底層裝置,需要將字串轉成位元組再進行寫入。字元流是位元組流的包裝,字元流則是直接接受字串,它內部將串轉成位元組,再寫入底層裝置,這為我們向IO設別寫入或讀取字串提供了一點點方便。

  字元向位元組轉換時,要注意編碼的問題,因為字串轉成位元組陣列,

  其實是轉成該字元的某種編碼的位元組形式,讀取也是反之的道理。

講解位元組流與字元流關係的程式碼案例:

 1 import java.io.BufferedReader;
 2 import java.io.FileInputStream;
 3 import java.io.InputStreamReader;
 4 import java.io.PrintWriter;
 5 
 6 public class IOTest {
 7 
 8     public static void main(String[] args) throws Exception {
 9 
10         String str = "中國人";
11 
12         /*
13          * FileOutputStream fos = new FileOutputStream("1.txt");
14          * fos.write(str.getBytes("UTF-8")); 
15          * fos.close();
16          */
17 
18         /*
19          * FileWriter fw = new FileWriter("1.txt"); 
20          * fw.write(str);
21          * fw.close();
22          */
23         
24         PrintWriter pw = new PrintWriter("1.txt", "utf-8");
25         pw.write(str);
26         pw.close();
27         
28         /*
29          * FileReader fr = newFileReader("1.txt"); 
30          * char[] buf = new char[1024];
31          * int len = fr.read(buf); 
32          * String myStr = new String(buf,0,len);
33          * System.out.println(myStr);
34          */
35 
36         /*
37          * FileInputStream fr = new FileInputStream("1.txt"); 
38          * byte[] buf = new
39          * byte[1024]; 
40          * int len = fr.read(buf); 
41          * String myStr = new String(buf,0,len,"UTF-8"); 
42          * System.out.println(myStr);
43          */
44         
45         BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("1.txt"), "UTF-8"));
46         String myStr = br.readLine();
47         br.close();
48         System.out.println(myStr);
49     }
50 }

74、什麼是java序列化,如何實現java序列化?或者請解釋Serializable介面的作用。

我們有時候將一個java物件變成位元組流的形式傳出去或者從一個位元組流中恢復成一個java物件,例如,要將java物件儲存到硬碟或者傳送給網路上的其他計算機,這個過程我們可以自己寫程式碼去把一個java物件變成某個格式的位元組流再傳輸,但是,jre本身就提供了這種支援,我們可以呼叫OutputStream的writeObject方法來做,如果要讓java 幫我們做,要被傳輸的物件必須實現serializable介面,這樣,javac編譯時就會進行特殊處理,編譯的類才可以被writeObject方法操作,這就是所謂的序列化。需要被序列化的類必須實現Serializable介面,該介面是一個mini介面,其中沒有需要實現的方法,implements Serializable只是為了標註該物件是可被序列化的。

例如,在web開發中,如果物件被儲存在了Session中,tomcat在重啟時要把Session物件序列化到硬碟,這個物件就必須實現Serializable介面。如果物件要經過分散式系統進行網路傳輸或通過rmi等遠端呼叫,這就需要在網路上傳輸物件,被傳輸的物件就必須實現Serializable介面。

75、描述一下JVM載入class檔案的原理機制?

JVM中類的裝載是由ClassLoader和它的子類來實現的,Java ClassLoader 是一個重要的Java執行時系統元件。它負責在執行時查詢和裝入類檔案的類。

76、heap和stack有什麼區別。

java的記憶體分為兩類,一類是棧記憶體,一類是堆記憶體。棧記憶體是指程式進入一個方法時,會為這個方法單獨分配一塊私屬儲存空間,用於儲存這個方法內部的區域性變數,當這個方法結束時,分配給這個方法的棧會釋放,這個棧中的變數也將隨之釋放。

堆是與棧作用不同的記憶體,一般用於存放不放在當前方法棧中的那些資料,例如,使用new建立的物件都放在堆裡,所以,它不會隨方法的結束而消失。方法中的區域性變數使用final修飾後,放在堆中,而不是棧中。

77、GC是什麼? 為什麼要有GC?

GC是垃圾收集的意思(Gabage Collection),記憶體處理是程式設計人員容易出現問題的地方,忘記或者錯誤的記憶體回收會導致程式或系統的不穩定甚至崩潰,Java提供的GC功能可以自動監測物件是否超過作用域從而達到自動回收記憶體的目的,Java語言沒有提供釋放已分配記憶體的顯示操作方法。

78、垃圾回收的優點和原理。並考慮2種回收機制。

Java語言中一個顯著的特點就是引入了垃圾回收機制,使c++程式設計師最頭疼的記憶體管理的問題迎刃而解,它使得Java程式設計師在編寫程式的時候不再需要考慮記憶體管理。由於有個垃圾回收機制,Java中的物件不再有"作用域"的概念,只有物件的引用才有"作用域"。垃圾回收可以有效的防止記憶體洩露,有效的使用可以使用的記憶體。垃圾回收器通常是作為一個單獨的低階別的執行緒執行,不可預知的情況下對記憶體堆中已經死亡的或者長時間沒有使用的物件進行清楚和回收,程式設計師不能實時的呼叫垃圾回收器對某個物件或所有物件進行垃圾回收。回收機制有分代複製垃圾回收和標記垃圾回收,增量垃圾回收。

79、垃圾回收器的基本原理是什麼?垃圾回收器可以馬上回收記憶體嗎?有什麼辦法主動通知虛擬機器進行垃圾回收?

對於GC來說,當程式設計師建立物件時,GC就開始監控這個物件的地址、大小以及使用情況。通常,GC採用有向圖的方式記錄和管理堆(heap)中的所有物件。通過這種方式確定哪些物件是"可達的",哪些物件是"不可達的"。當GC確定一些物件為"不可達"時,GC就有責任回收這些記憶體空間。可以。程式設計師可以手動執行System.gc(),通知GC執行,但是Java語言規範並不保證GC一定會執行。

80、什麼時候用assert。

assertion(斷言)在軟體開發中是一種常用的除錯方式,很多開發語言中都支援這種機制。在實現中,assertion就是在程式中的一條語句,它對一個boolean表示式進行檢查,一個正確程式必須保證這個boolean表示式的值為true;如果該值為false,說明程式已經處於不正確的狀態下,assert將給出警告或退出。一般來說,assertion用於保證程式最基本、關鍵的正確性。assertion檢查通常在開發和測試時開啟。為了提高效能,在軟體釋出後,assertion檢查通常是關閉的。

 1 public class AssertTest {
 2     public static void main(String[] args) {
 3         int i = 0;
 4         for (i = 0; i < 5; i++) {
 5             System.out.println(i);
 6         }
 7         // 假設程式不小心多了一句--i;
 8         --i;
 9         assert i == 5;
10     }
11 }

81、java中會存在記憶體洩漏嗎,請簡單描述。

所謂記憶體洩露就是指一個不再被程式使用的物件或變數一直被佔據在記憶體中。java中有垃圾回收機制,它可以保證一物件不再被引用的時候,即物件程式設計了孤兒的時候,物件將自動被垃圾回收器從記憶體中清除掉。由於Java 使用有向圖的方式進行垃圾回收管理,可以消除引用迴圈的問題,例如有兩個物件,相互引用,只要它們和根程式不可達的,那麼GC也是可以回收它們的,例如下面的程式碼可以看到這種情況的記憶體回收:

 1 import java.io.IOException;
 2 
 3 public class GarbageTest {
 4     public static void main(String[] args) throws IOException {
 5         try {
 6             gcTest();
 7         } catch (IOException e) {
 8             e.printStackTrace();
 9         }
10 
11         System.out.println("has exited gcTest!");
12         System.in.read();
13         System.in.read();
14         System.out.println("out begin gc!");
15 
16         for (int i = 0; i < 100; i++) {
17             System.gc();
18             System.in.read();
19             System.in.read();
20         }
21     }
22 
23     private static void gcTest() throws IOException {
24 
25         System.in.read();
26         System.in.read();
27 
28         Person p1 = new Person();
29         System.in.read();
30         System.in.read();
31 
32         Person p2 = new Person();
33         p1.setMate(p2);
34         p2.setMate(p1);
35 
36         System.out.println("before exit gctest!");
37         System.in.read();
38         System.in.read();
39 
40         System.gc();
41         System.out.println("exit gctest!");
42     }
43 
44     private static class Person {
45         byte[] data = new byte[20000000];
46         Person mate = null;
47 
48         public void setMate(Person other) {
49             mate = other;
50         }
51     }
52 }

java中的記憶體洩露的情況:長生命週期的物件持有短生命週期物件的引用就很可能發生記憶體洩露,儘管短生命週期物件已經不再需要,但是因為長生命週期物件持有它的引用而導致不能被回收,這就是java中記憶體洩露的發生場景,通俗地說,就是程式設計師可能建立了一個物件,以後一直不再使用這個物件,這個物件卻一直被引用,即這個物件無用但是卻無法被垃圾回收器回收的,這就是java中可能出現記憶體洩露的情況,例如,快取系統,我們載入了一個物件放在快取中(例如放在一個全域性map物件中),然後一直不再使用它,這個物件一直被快取引用,但卻不再被使用。

檢查java中的記憶體洩露,一定要讓程式將各種分支情況都完整執行到程式結束,然後看某個物件是否被使用過,如果沒有,則才能判定這個物件屬於記憶體洩露。

如果一個外部類的例項物件的方法返回了一個內部類的例項物件,這個內部類物件被長期引用了,即使那個外部類例項物件不再被使用,但由於內部類持久外部類的例項物件,這個外部類物件將不會被垃圾回收,這也會造成記憶體洩露。

下面內容來自於網上(主要特點就是清空堆疊中的某個元素,並不是徹底把它從陣列中拿掉,而是把儲存的總數減少,本人寫得可以比這個好,在拿掉某個元素時,順便也讓它從陣列中消失,將那個元素所在的位置的值設定為null即可):

我實在想不到比那個堆疊更經典的例子了,以致於我還要引用別人的例子,下面的例子不是我想到的,是書上看到的,當然如果沒有在書上看到,可能過一段時間我自己也想的到,可是那時我說是我自己想到的也沒有人相信的。

  

 1 import java.util.EmptyStackException;
 2 
 3 public class Stack {
 4     private Object[] elements = new Object[10];
 5     private int size = 0;
 6 
 7     public void push(Object e) {
 8         ensureCapacity();
 9         elements[size++] = e;
10     }
11 
12     public Object pop() {
13         if (size == 0)
14             throw new EmptyStackException();
15         return elements[--size];
16     }
17 
18     private void ensureCapacity() {
19         if (elements.length == size) {
20             Object[] oldElements = elements;
21             elements = new Object[2 * elements.length + 1];
22             System.arraycopy(oldElements, 0, elements, 0, size);
23         }
24     }
25 }

    上面的原理應該很簡單,假如堆疊加了10個元素,然後全部彈出來,雖然堆疊是空的,沒有我們要的東西,但是這是個物件是無法回收的,這個才符合了記憶體洩露的兩個條件:無用,無法回收。

    但是就是存在這樣的東西也不一定會導致什麼樣的後果,如果這個堆疊用的比較少,也就浪費了幾個K記憶體而已,反正我們的記憶體都上G了,哪裡會有什麼影響,再說這個東西很快就會被回收的,有什麼關係。下面看兩個例子。

    例子1

 1 import java.util.Stack;
 2 
 3 public class Bad {
 4     public static Stack s = new Stack();
 5     static {
 6         s.push(new Object());
 7         s.pop(); // 這裡有一個物件發生記憶體洩露
 8         s.push(new Object()); // 上面的物件可以被回收了,等於是自愈了
 9     }
10 }

    因為是static,就一直存在到程式退出,但是我們也可以看到它有自愈功能,就是說如果你的Stack最多有100個物件,那麼最多也就只有100個物件無法被回收其實這個應該很容易理解,Stack內部持有100個引用,最壞的情況就是他們都是無用的,因為我們一旦放新的進取,以前的引用自然消失!

  記憶體洩露的另外一種情況:當一個物件被儲存進HashSet集合中以後,就不能修改這個物件中的那些參與計算雜湊值的欄位了,否則,物件修改後的雜湊值與最初儲存進HashSet集合中時的雜湊值就不同了,在這種情況下,即使在contains方法使用該物件的當前引用作為的引數去HashSet集合中檢索物件,也將返回找不到物件的結果,這也會導致無法從HashSet集合中單獨刪除當前物件,造成記憶體洩露。

82、能不能自己寫個類,也叫java.lang.String?

可以,但在應用的時候,需要用自己的類載入器去載入,否則,系統的類載入器永遠只是去載入jre.jar包中的那個java.lang.String。由於在tomcat的web應用程式中,都是由webapp自己的類載入器先自己載入WEB-INF/classess目錄中的類,然後才委託上級的類載入器載入,如果我們在tomcat的web應用程式中寫一個java.lang.String,這時候Servlet程式載入的就是我們自己寫的java.lang.String,但是這麼幹就會出很多潛在的問題,原來所有用了java.lang.String類的都將出現問題。 

雖然java提供了endorsed技術,可以覆蓋jdk中的某些類,具體做法是….。但是,能夠被覆蓋的類是有限制範圍,反正不包括java.lang這樣的包中的類。

(下面的例如主要是便於大家學習理解只用,不要作為答案的一部分,否則,人家懷疑是題目洩露了)例如,執行下面的程式:

1 public class String {
2 
3     public static void main(String[] args) {
4 
5         System.out.println("string");
6 
7     }
8 }

報告的錯誤如下:

1 java.lang.NoSuchMethodError:main
2 
3 Exception in thread"main"

這是因為載入了jre自帶的java.lang.String,而該類中沒有main方法。

83. Java程式碼查錯

1.

1 abstract class Name {
2     private String name;
3 
4     public abstract boolean isStupidName(String name){};
5 }

大俠們,這有何錯誤?
答案: 錯。abstract method必須以分號結尾,且不帶花括號。
2.

1 public class Something {
2     void doSomething() {
3         private String s = "";
4         int l = s.length();
5     }
6 }

有錯嗎?
答案: 錯。區域性變數前不能放置任何訪問修飾符 (private,public,和protected)。final可以用來修飾區域性變數
(final如同abstract和strictfp,都是非訪問修飾符,strictfp只能修飾class和method而非variable)。
3.

1 abstract class Something {
2     private abstract String doSomething();
3 }

這好像沒什麼錯吧?
答案: 錯。abstract的methods不能以private修飾。abstract的methods就是讓子類implement(實現)具體細節的,怎麼可以用private把abstract
method封鎖起來呢? (同理,abstract method前不能加final)。
4.

1 public class Something {
2     public int addOne(final int x) {
3         return ++x;
4     }
5 }

這個比較明顯。
答案: 錯。int x被修飾成final,意味著x不能在addOne method中被修改。
5.

 1 public class Something {
 2     public static void main(String[] args) {
 3         Other o = new Other();
 4         new Something().addOne(o);
 5     }
 6 
 7     public void addOne(final Other o) {
 8         o.i++;
 9     }
10 }
11 
12 class Other {
13     public int i;
14 }

和上面的很相似,都是關於final的問題,這有錯嗎?
答案: 正確。在addOne method中,引數o被修飾成final。如果在addOne method裡我們修改了o的reference
(比如: o = new Other();),那麼如同上例這題也是錯的。但這裡修改的是o的member vairable
(成員變數),而o的reference並沒有改變。
6.

1 class Something {
2     int i;
3 
4     public void doSomething() {
5         System.out.println("i = " + i);
6     }
7 }

有什麼錯呢? 看不出來啊。
答案: 正確。輸出的是"i = 0"。int i屬於instant variable (例項變數,或叫成員變數)。instant variable有default value。int的default value是0。
7.

1 class Something {
2     final int i;
3 
4     public void doSomething() {
5         System.out.println("i = " + i);
6     }
7 }

和上面一題只有一個地方不同,就是多了一個final。這難道就錯了嗎?
答案: 錯。final int i是個final的instant variable (例項變數,或叫成員變數)。final的instant variable沒有default value,必須在constructor (構造器)結束之前被賦予一個明確的值。可以修改為"final int i =0;"。
8.

 1 public class Something {
 2     public static void main(String[] args) {
 3         Something s = new Something();
 4         System.out.println("s.doSomething() returns " + doSomething());
 5     }
 6 
 7     public String doSomething() {
 8         return "Do something ...";
 9     }
10 }

看上去很完美。
答案: 錯。看上去在main裡call doSomething沒有什麼問題,畢竟兩個methods都在同一個class裡。但仔細看,main是static的。static method不能直接call non-staticmethods。可改成"System.out.println("s.doSomething()returns " + s.doSomething());"。同理,static method不能訪問non-static instant variable。
9.
此處,Something類的檔名叫OtherThing.java

1 class Something {
2     private static void main(String[] something_to_do) {
3         System.out.println("Dosomething ...");
4     }
5 }

這個好像很明顯。
答案: 正確。從來沒有人說過Java的Class名字必須和其檔名相同。但public class的名字必須和檔名相同。
10.

 1 interface A {
 2     int x = 0;
 3 }
 4 
 5 class B {
 6     int x = 1;
 7 }
 8 
 9 class C extends B implements A {
10     public void pX() {
11         System.out.println(x);
12     }
13 
14     public static void main(String[] args) {
15         new C().pX();
16     }
17 }

答案:錯誤。在編譯時會發生錯誤(錯誤描述不同的JVM有不同的資訊,意思就是未明確的x呼叫,兩個x都匹配(就象在同時import java.util和java.sql兩個包時直接宣告Date一樣)。對於父類的變數,可以用super.x來明確,而介面的屬性預設隱含為 public static final.所以可以通過A.x來明確。
11.

 1 interface Playable {
 2     void play();
 3 }
 4 
 5 interface Bounceable {
 6     void play();
 7 }
 8 
 9 interface Rollable extends Playable, Bounceable {
10     Ball ball = new Ball("PingPang");
11 }
12 
13 class Ball implements Rollable {
14     private String name;
15 
16     public String getName() {
17         return name;
18     }
19 
20     public Ball(String name) {
21         this.name = name;
22     }
23 
24     public void play() {
25         ball = new Ball("Football");
26         System.out.println(ball.getName());
27     }
28 }

這個錯誤不容易發現。
答案: 錯。"interfaceRollable extends Playable, Bounceable"沒有問題。interface可繼承多個interfaces,所以這裡沒錯。問題出在interface Rollable裡的"Ball ball = newBall("PingPang");"。任何在interface裡宣告的interface variable (介面變數,也可稱成員變數),預設為public static final。也就是說"Ball ball = new Ball("PingPang");"實際上是"public staticfinal Ball ball = new Ball("PingPang");"。在Ball類的Play()方法中,"ball = newBall("Football");"改變了ball的reference,而這裡的ball來自Rollable interface,Rollable interface裡的ball是public static final的,final的object是不能被改變reference的。因此編譯器將在"ball = newBall("Football");"這裡顯示有錯。

二. 演算法與程式設計

1、編寫一個程式,將a.txt檔案中的單詞與b.txt檔案中的單詞交替合併到c.txt檔案中,a.txt檔案中的單詞用回車符分隔,b.txt檔案中用回車或空格進行分隔。

答:

 

 1 import java.io.File;
 2 import java.io.FileReader;
 3 import java.io.FileWriter;
 4 
 5 public class MainClass {
 6 
 7     public static void main(String[] args) throws Exception {
 8         FileManager a = new FileManager("a.txt", new char[] { '\n' });
 9 
10         FileManager b = new FileManager("b.txt", new char[] { '\n', ' ' });
11 
12         FileWriter c = new FileWriter("c.txt");
13 
14         String aWord = null;
15 
16         String bWord = null;
17 
18         while ((aWord = a.nextWord()) != null) {
19             c.write(aWord + "\n");
20             bWord = b.nextWord();
21             if (bWord != null)
22                 c.write(bWord + "\n");
23         }
24         while ((bWord = b.nextWord()) != null) {
25             c.write(bWord + "\n");
26         }
27         c.close();
28     }
29 }
30 
31 class FileManager {
32     String[] words = null;
33     int pos = 0;
34 
35     public FileManager(String filename, char[] seperators) throws Exception {
36 
37         File f = new File(filename);
38 
39         FileReader reader = new FileReader(f);
40 
41         char[] buf = new char[(int) f.length()];
42 
43         int len = reader.read(buf);
44 
45         String results = new String(buf, 0, len);
46 
47         String regex = null;
48 
49         if (seperators.length > 1) {
50             regex = "" + seperators[0] + "|" + seperators[1];
51         } else {
52             regex = "" + seperators[0];
53         }
54         words = results.split(regex);
55     }
56 
57     public String nextWord() {
58         if (pos == words.length)
59             return null;
60         return words[pos++];
61     }
62 }

2、編寫一個程式,將d:\java目錄下的所有.java檔案複製到d:\jad目錄下,並將原來檔案的副檔名從.java改為.jad。

(大家正在做上面這道題,網上遲到的朋友也請做做這道題,找工作必須能編寫這些簡單問題的程式碼!)

答:listFiles方法接受一個FileFilter物件,這個FileFilter物件就是過慮的策略物件,不同的人提供不同的FileFilter實現,即提供了不同的過濾策略。

 1 import java.io.File;
 2 import java.io.FileInputStream;
 3 import java.io.FileOutputStream;
 4 import java.io.FilenameFilter;
 5 import java.io.InputStream;
 6 import java.io.OutputStream;
 7 
 8 public class Jad2Java {
 9 
10     public static void main(String[] args) throws Exception {
11 
12         File srcDir = new File("java");
13 
14         if (!(srcDir.exists() && srcDir.isDirectory()))
15             throw newException("目錄不存在");
16 
17         File[] files = srcDir.listFiles(new FilenameFilter() {
18             public boolean accept(File dir, String name) {
19                 return name.endsWith(".java");
20             }
21         });
22 
23         System.out.println(files.length);
24         File destDir = new File("jad");
25 
26         if (!destDir.exists())
27             destDir.mkdir();
28 
29         for (File f : files) {
30             FileInputStream fis = new FileInputStream(f);
31             String destFileName = f.getName().replaceAll("\\.java$", ".jad");
32             FileOutputStream fos = new FileOutputStream(new File(destDir, destFileName));
33             copy(fis, fos);
34 
35             fis.close();
36             fos.close();
37         }
38     }
39 
40     private static void copy(InputStream ips, OutputStream ops) throws Exception {
41 
42         int len = 0;
43         byte[] buf = new byte[1024];
44 
45         while ((len = ips.read(buf)) != -1) {
46             ops.write(buf, 0, len);
47         }
48     }
49 }

由本題總結的思想及策略模式的解析:

1.

 1 import java.io.File;
 2 import java.io.FileFilter;
 3 import java.util.Arrays;
 4 
 5 class jad2java {
 6 
 7     // 1. 得到某個目錄下的所有的java檔案集合
 8 
 9         // 1.1 得到目錄 File srcDir =new File("d:\\java");
10     
11         // 1.2 得到目錄下的所有java檔案:File[]files = srcDir.listFiles(new MyFileFilter());
12     
13         // 1.3 只想得到.java的檔案:class MyFileFilter implememyts FileFilter{
14 
15     public boolean accept(Filepathname){
16             returnpathname.getName().endsWith(".java");
17            }
18 
19     // 2.將每個檔案複製到另外一個目錄,並改副檔名
20 
21         // 2.1 得到目標目錄,如果目標目錄不存在,則建立之
22     
23         // 2.2 根據原始檔名得到目標檔名,注意要用正規表示式,注意.的轉義。
24     
25         // 2.3 根據表示目錄的File和目標檔名的字串,得到表示目標檔案的File。
26 
27             // 要在硬碟中準確地建立出一個檔案,需要知道檔名和檔案的目錄。
28     
29         // 2.4 將原始檔的流拷貝成目標檔案流,拷貝方法獨立成為一個方法,方法的引數採用抽象流的形式。
30 
31             // 方法接受的引數型別儘量面向父類,越抽象越好,這樣適應面更寬廣。
32         
33             // 分析listFiles方法內部的策略模式實現原理
34 
35     File[] listFiles(FileFilter filter) {
36         File[] files = listFiles(filter);
37         // Arraylist acceptedFilesList = newArrayList();
38         File[] acceptedFiles = new File[files.length];
39         int pos = 0;
40         for (File file : files) {
41             boolean accepted = filter.accept(file);
42             if (accepted) {
43                 // acceptedFilesList.add(file);
44                 acceptedFiles[pos++] = file;
45             }
46         }
47         Arrays.copyOf(acceptedFiles, pos);
48         // return(File[])accpetedFilesList.toArray();
49     }
50 }

3、編寫一個擷取字串的函式,輸入為一個字串和位元組數,輸出為按位元組擷取的字串,但要保證漢字不被擷取半個,如“我ABC”,4,應該擷取“我AB”,輸入“我ABC漢DEF”,6,應該輸出“我ABC”,而不是“我ABC+漢的半個”。

答:

首先要了解中文字元有多種編碼及各種編碼的特徵。

假設n為要擷取的位元組數。

 1 public class jad2Java {
 2     public static void main(String[] args)throws Exception{
 3 
 4         String str = "我a愛中華abc我愛榮耀def";
 5 //        String str = "我ABC漢";
 6         int num =trimGBK(str.getBytes("GBK"),5);
 7         
 8         System.out.println(str.substring(0,num));
 9     }
10 
11     public static int trimGBK(byte[] buf, int n) {
12         
13         int num = 0;
14         boolean bChineseFirstHalf = false;
15 
16         for (int i = 0; i < n; i++) {
17             if (buf[i] < 0 && !bChineseFirstHalf) {
18                 bChineseFirstHalf = true;
19             } else {
20                 num++;
21                 bChineseFirstHalf = false;
22             }
23         }
24         return num;
25     }
26 }

4、有一個字串,其中包含中文字元、英文字元和數字字元,請統計和列印出各個字元的個數。

答:哈哈,其實包含中文字元、英文字元、數字字元原來是出題者放的煙霧彈。

 1 String content = "中國aadf的111薩bbb菲的zz薩菲";
 2 
 3 HashMap<Character, Integer> map = new HashMap<Character, Integer>();
 4 
 5 for (int i = 0; i < content.length(); i++) {
 6     char c = content.charAt(i);
 7 
 8     Integer num = (Integer) map.get(c);
 9 
10     if (num == null)
11         num = 1;
12     else
13         num = num + 1;
14     map.put(c, num);
15 }
16 
17 for (Map.Entry<Character, Integer> entry : map.entrySet()) {
18     System.out.println(entry.getKey() + ":" + entry.getValue());
19 }

估計是當初面試的那個學員表述不清楚,問題很可能是:

如果一串字元如"aaaabbc中國1512"要分別統計英文字元的數量,中文字元的數量,和數字字元的數量,假設字元中沒有中文字元、英文字元、數字字元之外的其他特殊字元。

 1 int engishCount = 0;
 2 int chineseCount = 0;
 3 int digitCount = 0;
 4 String str = "";
 5 for (int i = 0; i < str.length(); i++) {
 6     char ch = str.charAt(i);
 7     if (ch >= '0' && ch <= '9') {
 8         digitCount++;
 9     } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
10         engishCount++;
11     } else {
12         chineseCount++;
13     }
14 }
15 System.out.println("………");
16 }

5、說明生活中遇到的二叉樹,用java實現二叉樹

這是組合設計模式。

我有很多個(假設10萬個)資料要儲存起來,以後還需要從儲存的這些資料中檢索是否存在某個資料,(我想說出二叉樹的好處,該怎麼說呢?那就是說別人的缺點),假如存在陣列中,那麼,碰巧要找的數字位於99999那個地方,那查詢的速度將很慢,因為要從第1個依次往後取,取出來後進行比較。平衡二叉樹(構建平衡二叉樹需要先排序,我們這裡就不作考慮了)可以很好地解決這個問題,但二叉樹的遍歷(前序,中序,後序)效率要比陣列低很多,原理如下圖:

程式碼如下:

 1 public class Node {
 2 
 3     public int value;
 4     public Node left;
 5     public Node right;
 6 
 7     public void store(int value) {
 8         if (value < this.value) {
 9             if (left == null) {
10                 left = new Node();
11                 left.value = value;
12             } else {
13                 left.store(value);
14             }
15         } else if (value > this.value) {
16             if (right == null) {
17                 right = new Node();
18                 right.value = value;
19             } else {
20                 right.store(value);
21             }
22         }
23     }
24 
25     public boolean find(int value) {
26         System.out.println("happen " + this.value);
27         if (value == this.value) {
28             return true;
29         } else if (value > this.value) {
30             if (right == null)
31                 return false;
32             return right.find(value);
33         } else {
34             if (left == null)
35                 return false;
36             return left.find(value);
37         }
38     }
39 
40     public void preList() {
41         System.out.print(this.value + ",");
42         if (left != null)
43             left.preList();
44         if (right != null)
45             right.preList();
46     }
47 
48     public void middleList() {
49         if (left != null)
50             left.preList();
51         System.out.print(this.value + ",");
52         if (right != null)
53             right.preList();
54     }
55 
56     public void afterList() {
57         if (left != null)
58             left.preList();
59         if (right != null)
60             right.preList();
61         System.out.print(this.value + ",");
62     }
63 
64     public static void main(String[] args) {
65         int[] data = new int[20];
66         for (int i = 0; i < data.length; i++) {
67             data[i] = (int) (Math.random() * 100) + 1;
68             System.out.print(data[i] + ",");
69         }
70         System.out.println();
71 
72         Node root = new Node();
73         root.value = data[0];
74 
75         for (int i = 1; i < data.length; i++) {
76             root.store(data[i]);
77         }
78 
79         root.find(data[19]);
80         root.preList();
81 
82         System.out.println();
83         root.middleList();
84 
85         System.out.println();
86         root.afterList();
87     }
88 
89 }

-----------------又一次臨場寫的程式碼---------------------------

 1 import java.util.Arrays;
 2 import java.util.Iterator;
 3 
 4 public class Node {
 5 
 6     private Node left;
 7     private Node right;
 8     private int value;
 9 
10     // private int num;
11 
12     public Node(int value) {
13         this.value = value;
14     }
15 
16     public void add(int value) {
17         if (value > this.value) {
18             if (right != null)
19                 right.add(value);
20             else {
21                 Node node = new Node(value);
22                 right = node;
23             }
24         } else {
25             if (left != null)
26                 left.add(value);
27             else {
28                 Node node = new Node(value);
29                 left = node;
30             }
31         }
32     }
33 
34     public boolean find(int value) {
35         if (value == this.value)
36             return true;
37         else if (value > this.value) {
38             if (right == null)
39                 return false;
40             else
41                 return right.find(value);
42         } else {
43             if (left == null)
44                 return false;
45             else
46                 return left.find(value);
47         }
48     }
49 
50     public void display() {
51         System.out.println(value);
52         if (left != null)
53             left.display();
54         if (right != null)
55             right.display();
56     }
57 
58     /* public Iterator iterator(){} */
59 
60     public static void main(String[] args) {
61         int[] values = new int[8];
62         for (int i = 0; i < 8; i++) {
63             int num = (int) (Math.random() * 15);
64             // System.out.println(num);
65             // if(Arrays.binarySearch(values, num)<0)
66             if (!contains(values, num))
67                 values[i] = num;
68             else
69                 i--;
70         }
71         System.out.println(Arrays.toString(values));
72         Node root = new Node(values[0]);
73         for (int i = 1; i < values.length; i++) {
74             root.add(values[i]);
75         }
76         System.out.println(root.find(13));
77         root.display();
78     }
79 
80     public static boolean contains(int[] arr, int value) {
81         int i = 0;
82         for (; i < arr.length; i++) {
83             if (arr[i] == value)
84                 return true;
85         }
86         return false;
87     }
88 }

6、從類似如下的文字檔案中讀取出所有的姓名,並列印出重複的姓名和重複的次數,並按重複次數排序:

1,張三,28

2,李四,35

3,張三,28

4,王五,35

5,張三,28

6,李四,35

7,趙六,28

8,田七,35

程式程式碼如下(答題要博得用人單位的喜歡,包名用該公司,面試前就提前查好該公司的網址,如果查不到,現場問也是可以的。還要加上實現思路的註釋):

  1 import java.io.BufferedReader;
  2 import java.io.IOException;
  3 import java.io.InputStream;
  4 import java.io.InputStreamReader;
  5 import java.util.Comparator;
  6 import java.util.HashMap;
  7 import java.util.Iterator;
  8 import java.util.Map;
  9 import java.util.TreeSet;
 10 
 11 public class GetNameTest {
 12 
 13     public static void main(String[] args) {
 14         // InputStream ips
 15         // =GetNameTest.class.getResourceAsStream("/com/huawei/interview/info.txt");
 16         // 用上一行註釋的程式碼和下一行的程式碼都可以,因為info.txt與GetNameTest類在同一包下面,所以,可以用下面的相對路徑形式
 17 
 18         Map results = new HashMap();
 19         InputStream ips = GetNameTest.class.getResourceAsStream("info.txt");
 20         BufferedReader in = new BufferedReader(new InputStreamReader(ips));
 21         String line = null;
 22         try {
 23             while ((line = in.readLine()) != null) {
 24                 dealLine(line, results);
 25             }
 26             sortResults(results);
 27         } catch (IOException e) {
 28             e.printStackTrace();
 29         }
 30     }
 31 
 32     static class User {
 33         public String name;
 34         public Integer value;
 35 
 36         public User(String name, Integer value) {
 37             this.name = name;
 38             this.value = value;
 39         }
 40 
 41         @Override
 42         public boolean equals(Object obj) {
 43             // 下面的程式碼沒有執行,說明往treeset中增加資料時,不會使用到equals方法。
 44             boolean result = super.equals(obj);
 45             System.out.println(result);
 46             return result;
 47         }
 48     }
 49 
 50     private static void sortResults(Map results) {
 51 
 52         TreeSet sortedResults = new TreeSet(new Comparator() {
 53             public int compare(Object o1, Object o2) {
 54                 User user1 = (User) o1;
 55                 User user2 = (User) o2;
 56 
 57                 /*
 58                  * 如果compareTo返回結果0,則認為兩個物件相等,新的物件不會增加到集合中去
 59                  * 所以,不能直接用下面的程式碼,否則,那些個數相同的其他姓名就列印不出來。
 60                  */
 61 
 62                 // return user1.value-user2.value;
 63                 // returnuser1.value<user2.value?-1:user1.value==user2.value?0:1;
 64 
 65                 if (user1.value < user2.value) {
 66                     return -1;
 67                 } else if (user1.value > user2.value) {
 68                     return 1;
 69                 } else {
 70                     return user1.name.compareTo(user2.name);
 71                 }
 72             }
 73         });
 74         Iterator iterator = results.keySet().iterator();
 75         while (iterator.hasNext()) {
 76             String name = (String) iterator.next();
 77             Integer value = (Integer) results.get(name);
 78             if (value > 1) {
 79                 sortedResults.add(new User(name, value));
 80             }
 81         }
 82         printResults(sortedResults);
 83     }
 84 
 85     private static void printResults(TreeSet sortedResults) {
 86         Iterator iterator = sortedResults.iterator();
 87         while (iterator.hasNext()) {
 88             User user = (User) iterator.next();
 89             System.out.println(user.name + ":" + user.value);
 90         }
 91     }
 92 
 93     public static void dealLine(String line, Map map) {
 94         if (!"".equals(line.trim())) {
 95             String[] results = line.split(",");
 96             if (results.length == 3) {
 97                 String name = results[1];
 98                 Integer value = (Integer) map.get(name);
 99                 if (value == null)
100                     value = 0;
101                 map.put(name, value + 1);
102             }
103         }
104     }
105 }

7、寫一個Singleton出來。

第一種:飽漢模式

 1 public class SingleTon {
 2 
 3     private SingleTon() {
 4     }
 5 
 6     // 例項化放在靜態程式碼塊裡可提高程式的執行效率,但也可能更佔用空間
 7     private final static SingleTon instance = new SingleTon();
 8 
 9     public static SingleTon getInstance() {
10         return instance;
11     }
12 }

第二種:飢漢模式

 1 public class SingleTon {
 2 
 3     private SingleTon() {
 4     }
 5 
 6     private static SingleTon instance = null;//new SingleTon();
 7 
 8     public static synchronized SingleTon getInstance(){
 9 
10        if(instance == null)
11            instance = new SingleTon();
12 
13        return instance;
14     }
15 }

第三種:用列舉

1 public enum SingleTon {
2     ONE;
3 }

第三:更實際的應用(在什麼情況用單例)

 1 public class SingleTon {
 2 
 3     // 下面是該類自身的業務功能程式碼
 4     private int count = 0;
 5 
 6     public synchronized int getSequence() {
 7         return ++count;
 8     }
 9 
10     // 下面是把該類變成單例的程式碼
11     private SingleTon() {
12     }
13 
14     private final static SingleTon instance = new SingleTon();
15 
16     public static SingleTon getInstance() {
17         return instance;
18     }
19 }

第四:

1 public class MemoryDao{
2     private HashMap map = new HashMap();
3 
4     public void add(Student stu1) {
5         map.put(SequenceGenerator.getInstance().getSequence(), stu1);
6     }
7     // 把MemoryDao變成單例
8 }

Singleton模式主要作用是保證在Java應用程式中,一個類Class只有一個例項存在。

一般Singleton模式通常有幾種種形式:

第一種形式: 定義一個類,它的建構函式為private的,它有一個static的private的該類變數,在類初始化時例項話,通過一個public的getInstance方法獲取對它的引用,繼而呼叫其中的方法。

 1 public class Singleton {
 2 
 3     private Singleton() {
 4     }
 5 
 6     // 在自己內部定義自己一個例項,是不是很奇怪?
 7     // 注意這是private只供內部呼叫
 8     private static Singleton instance = new Singleton();
 9 
10     // 這裡提供了一個供外部訪問本class的靜態方法,可以直接訪問
11     public static Singleton getInstance() {
12         return instance;
13     }
14 }

第二種形式:

 1 public class Singleton {
 2 
 3     private static Singleton instance = null;
 4 
 5     public static synchronized Singleton getInstance() {
 6 
 7         // 這個方法比上面有所改進,不用每次都進行生成物件,只是第一次
 8         // 使用時生成例項,提高了效率!
 9         if (instance == null)
10             instance = new Singleton();
11         return instance;
12     }
13 }

其他形式:

定義一個類,它的建構函式為private的,所有方法為static的。

一般認為第一種形式要更加安全些

8、遞迴演算法題1

一個整數,大於0,不用迴圈和本地變數,按照n,2n,4n,8n的順序遞增,當值大於5000時,把值按照指定順序輸出來。
例:n=1237
則輸出為:
1237,
2474,
4948,
9896,
9896,
4948,
2474,
1237,

提示:寫程式時,先致謝按遞增方式的程式碼,寫好遞增的以後,再增加考慮遞減部分。

1 public static void doubleNum(int n){
2    System.out.println(n);
3    if(n<=5000)
4        doubleNum(n*2);
5    System.out.println(n);     
6 }

9、遞迴演算法題2

第1個人10,第2個比第1個人大2歲,依次遞推,請用遞迴方式計算出第8個人多大?

 1 import java.util.Date;
 2 
 3 public class A1 {
 4     public static void main(String[] args) {
 5         System.out.println(computeAge(8));
 6     }
 7 
 8     public static int computeAge(int n) {
 9         if (n == 1)
10             return 10;
11         return computeAge(n - 1) + 2;
12     }
13 
14     public static void toBinary(int n, StringBuffer result) {
15         if (n / 2 != 0)
16             toBinary(n / 2, result);
17         result.append(n % 2);
18     }
19 }

10、排序都有哪幾種方法?請列舉。用JAVA實現一個快速排序。

 本人只研究過氣泡排序、選擇排序和快速排序,下面是快速排序的程式碼:

 1 public class QuickSort {
 2     /**
 3      * 快速排序
 4      * 
 5      * @param strDate
 6      * @param left
 7      * @param right
 8      */
 9     public void quickSort(String[] strDate, int left, int right) {
10         String middle, tempDate;
11         int i, j;
12         i = left;
13         j = right;
14         middle = strDate[(i + j) / 2];
15         do {
16             while (strDate[i].compareTo(middle) < 0 && i < right)
17                 i++; // 找出左邊比中間值大的數
18             while (strDate[j].compareTo(middle) > 0 && j > left)
19                 j--; // 找出右邊比中間值小的數
20             if (i <= j) { // 將左邊大的數和右邊小的數進行替換
21                 tempDate = strDate[i];
22                 strDate[i] = strDate[j];
23                 strDate[j] = tempDate;
24                 i++;
25                 j--;
26             }
27         } while (i <= j); // 當兩者交錯時停止
28 
29         if (i < right) {
30             quickSort(strDate, i, right);//
31         }
32         if (j > left) {
33             quickSort(strDate, left, j);
34         }
35     }
36 
37     public static void main(String[] args) {
38         String[] strVoid = new String[] { "11", "66", "22", "0", "55", "22", "0", "32" };
39         QuickSort sort = new QuickSort();
40         sort.quickSort(strVoid, 0, strVoid.length - 1);
41         for (int i = 0; i < strVoid.length; i++) {
42             System.out.println(strVoid[i] + " ");
43         }
44     }
45 }

11、有陣列a[n],用java程式碼將陣列元素順序顛倒

 1 //用下面的也可以
 2 //for(int i=0,intj=a.length-1;i<j;i++,j--) 是否等效於 for(inti=0;i<a.length/2;i++)呢?
 3 
 4 import java.util.Arrays;
 5 
 6 public class SwapDemo {
 7 
 8     public static void main(String[] args) {
 9         int[] a = new int[] { (int) (Math.random() * 1000), (int) (Math.random() * 1000), (int) (Math.random() * 1000),
10                 (int) (Math.random() * 1000), (int) (Math.random() * 1000) };
11         System.out.println(a);
12         System.out.println(Arrays.toString(a));
13         swap(a);
14         System.out.println(Arrays.toString(a));
15     }
16 
17     public static void swap(int a[]) {
18         int len = a.length;
19         for (int i = 0; i < len / 2; i++) {
20             int tmp = a[i];
21             a[i] = a[len - 1 - i];
22             a[len - 1 - i] = tmp;
23         }
24     }
25 }

12.金額轉換,阿拉伯數字的金額轉換成中國傳統的形式如:(¥1011)->(一千零一拾一元整)輸出。

去零的程式碼:

 1 return sb.reverse().toString().replaceAll("零[拾佰仟]","零").replaceAll("零+萬","萬").replaceAll("零+元","元").replaceAll("零+","零");
 2 
 3 public class RenMingBi {
 4 
 5     private static final char[] data = new char[] { '零', '壹', '貳', '叄', '肆', '伍', '陸', '柒', '捌', '玖' };
 6     private static final char[] units = new char[] { '元', '拾', '佰', '仟', '萬', '拾', '佰', '仟', '億' };
 7 
 8     public static void main(String[] args) {
 9         System.out.println(convert(135689123));
10     }
11 
12     public static String convert(int money) {
13         StringBuffer sbf = new StringBuffer();
14         int unit = 0;
15         while (money != 0) {
16             sbf.insert(0, units[unit++]);
17             int number = money % 10;
18             sbf.insert(0, data[number]);
19             money /= 10;
20         }
21         return sbf.toString();
22     }
23 }

三. html&JavaScript&ajax部分

1. 判斷第二個日期比第一個日期大

       如何用指令碼判斷使用者輸入的的字串是下面的時間格式2004-11-21 必須要保證使用者的輸入是此格式,並且是時間,比如說月份不大於12等等,另外我需要使用者輸入兩個,並且後一個要比前一個晚,只允許用JAVASCRIPT,請詳細幫助作答,,

//這裡可用正規表示式判斷提前判斷一下格式,然後按下提取各時間欄位內容

<scripttype="text/javascript">

   window.onload = function()

   {

        //這麼寫是為了實現js程式碼與html程式碼的分離,當我修改js時,不能影響html程式碼。

        document.getElementById("frm1").onsubmit=

               function(){

                      var d1 = this.d1.value;

                      var d2 = this.d2.value;

                      if(!verifyDate (d1)){alert("第一個日期格式不對");return false;}

                      if(!verifyDate (d2)){alert("第二個日期格式不對");return false;}

                      if(!compareDate(d1,d2)){alert("第二個日期比第一日期小");return false;}                  

               };

        }

       

        function compareDate(d1,d2)

        {

               var arrayD1 =d1.split("-");

               var date1 = newDate(arrayD1[0],arrayD1[1],arrayD1[2]);

               var arrayD2 =d2.split("-");

               var date2 = newDate(arrayD2[0],arrayD2[1],arrayD2[2]); 

               if(date1 > date2) returnfalse;       

               return true;

        }

       

        function verifyDate(d)

        {

               var datePattern =/^\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2]\d|3[0-1])$/;

               return datePattern.test(d);

        }

</script>

 

<formid="frm1" action="xxx.html">

<inputtype="text" name="d1" />

<inputtype="text" name="d2" />

<inputtype="submit"/>

</form>

2. 用table顯示n條記錄,每3行換一次顏色,即1,2,3用紅色字型,4,5,6用綠色字型,7,8,9用紅顏色字型。

<body>

<tableid="tbl">

   <tr><td>1</td></tr>

   <tr><td>2</td></tr>

   <tr><td>3</td></tr>

   <tr><td>4</td></tr>

   <tr><td>5</td></tr>

   <tr><td>6</td></tr>

   <tr><td>7</td></tr>

   <tr><td>8</td></tr>

   <tr><td>9</td></tr>

   <tr><td>10</td></tr>

</table>

</body>

<script type="text/javascript">

   window.onload=function()

        {

               var tbl =document.getElementById("tbl");

               rows =tbl.getElementsByTagName("tr");

               for(i=0;i<rows.length;i++)

               {

                      var j = parseInt(i/3);

                      if(j%2==0)rows[i].style.backgroundColor="#f00";

                      else rows[i].style.backgroundColor="#0f0";

               }

        }

</script>

3、HTML 的 form 提交之前如何驗證數值文字框的內容全部為數字? 否則的話提示使用者並終止提交?

<form onsubmit=’returnchkForm(this)’>

<inputtype="text" name="d1"/>

<input type="submit"/>

</form>

<script type=”text/javascript”/>   

function chkForm(this)

       {

              var value = thist.d1.value;

              var len = value.length;

              for(var i=0;i<len;i++)

              {

                     if(value.charAt(i)>"9"|| value.charAt(i)<"0")

                     {

                            alert("含有非數字字元");

                            return false;

                     }

              }

              return true;

       }

</script>

 

4、請寫出用於校驗HTML文字框中輸入的內容全部為數字的javascript程式碼

<inputtype="text" id="d1" onblur=" chkNumber (this)"/>

<script type=”text/javascript”/>   

functionchkNumber(eleText)

 

       {

              var value = eleText.value;

              var len = value.length;

              for(var i=0;i<len;i++)

              {

                     if(value.charAt(i)>"9"|| value.charAt(i)<"0")

                     {

                            alert("含有非數字字元");

                            eleText.focus();

                            break;

                     }

              }

       }

</script>

除了寫完程式碼,還應該在網頁上寫出實驗步驟和在程式碼中加入實現思路,讓面試官一看就明白你的意圖和檢查你的結果。

 

5、說說你用過那些ajax技術和框架,說說它們的區別

 

四. Java web部分

1、Tomcat的優化經驗

答:去掉對web.xml的監視,把jsp提前編輯成Servlet。

有富餘實體記憶體的情況,加大tomcat使用的jvm的記憶體

 

 

2、HTTP請求的GET與POST方式的區別

答:servlet有良好的生存期的定義,包括載入和例項化、初始化、處理請求以及服務結束。這個生存期由javax.servlet.Servlet介面的init,service和destroy方法表達。

3、解釋一下什麼是servlet;

答:servlet有良好的生存期的定義,包括載入和例項化、初始化、處理請求以及服務結束。這個生存期由javax.servlet.Servlet介面的init,service和destroy方法表達。

4、說一說Servlet的生命週期?

答:servlet有良好的生存期的定義,包括載入和例項化、初始化、處理請求以及服務結束。這個生存期由javax.servlet.Servlet介面的init,service和destroy方法表達。

 

Servlet被伺服器例項化後,容器執行其init方法,請求到達時執行其service方法,service方法自動派遣執行與請求對應的doXXX方法(doGet,doPost)等,當伺服器決定將例項銷燬的時候呼叫其destroy方法。

web容器載入servlet,生命週期開始。通過呼叫servlet的init()方法進行servlet的初始化。通過呼叫service()方法實現,根據請求的不同呼叫不同的do***()方法。結束服務,web容器呼叫servlet的destroy()方法。

 

5、Servlet的基本架構

public classServletName extends HttpServlet {

public voiddoPost(HttpServletRequest request, HttpServletResponse response) throws

ServletException,IOException {

}

public voiddoGet(HttpServletRequest request, HttpServletResponse response) throws

ServletException,IOException {

}

}

6、SERVLET API中forward() 與redirect()的區別?

答:前者僅是容器中控制權的轉向,在客戶端瀏覽器位址列中不會顯示出轉向後的地址;後者則是完全的跳轉,瀏覽器將會得到跳轉的地址,並重新傳送請求連結。這樣,從瀏覽器的位址列中可以看到跳轉後的連結地址。所以,前者更加高效,在前者可以滿足需要時,儘量使用forward()方法,並且,這樣也有助於隱藏實際的連結。在有些情況下,比如,需要跳轉到一個其它伺服器上的資源,則必須使用

sendRedirect()方法。

 

7、什麼情況下呼叫doGet()和doPost()?

Jsp頁面中的FORM標籤裡的method屬性為get時呼叫doGet(),為post時呼叫doPost()。

 

8、Request物件的主要方法:

setAttribute(Stringname,Object):設定名字為name的request的引數值

getAttribute(Stringname):返回由name指定的屬性值

getAttributeNames():返回request物件所有屬性的名字集合,結果是一個列舉的例項

getCookies():返回客戶端的所有Cookie物件,結果是一個Cookie陣列

getCharacterEncoding():返回請求中的字元編碼方式

getContentLength():返回請求的Body的長度

getHeader(Stringname):獲得HTTP協議定義的檔案頭資訊

getHeaders(Stringname):返回指定名字的request Header的所有值,結果是一個列舉的例項

getHeaderNames():返回所以request Header的名字,結果是一個列舉的例項

getInputStream():返回請求的輸入流,用於獲得請求中的資料

getMethod():獲得客戶端向伺服器端傳送資料的方法

getParameter(Stringname):獲得客戶端傳送給伺服器端的有name指定的引數值

getParameterNames():獲得客戶端傳送給伺服器端的所有引數的名字,結果是一個列舉的例項

getParametervalues(Stringname):獲得有name指定的引數的所有值

getProtocol():獲取客戶端向伺服器端傳送資料所依據的協議名稱

getQueryString():獲得查詢字串

getRequestURI():獲取發出請求字串的客戶端地址

getRemoteAddr():獲取客戶端的IP地址

getRemoteHost():獲取客戶端的名字

getSession([Booleancreate]):返回和請求相關Session

getServerName():獲取伺服器的名字

getServletPath():獲取客戶端所請求的指令碼檔案的路徑

getServerPort():獲取伺服器的埠號

removeAttribute(Stringname):刪除請求中的一個屬性

 

 

 

9、forward 和redirect的區別

forward是伺服器請求資源,伺服器直接訪問目標地址的URL,把那個URL的響應內容讀取過來,然後把這些內容再發給瀏覽器,瀏覽器根本不知道伺服器傳送的內容是從哪兒來的,所以它的位址列中還是原來的地址。

   redirect就是服務端根據邏輯,傳送一個狀態碼,告訴瀏覽器重新去請求那個地址,一般來說瀏覽器會用剛才請求的所有引數重新請求,所以session,request引數都可以獲取。

10、request.getAttribute() 和 request.getParameter() 有何區別?

11. jsp有哪些內建物件?作用分別是什麼? 分別有什麼方法?

答:JSP共有以下9個內建的物件:

request 使用者端請求,此請求會包含來自GET/POST請求的引數

response 網頁傳回使用者端的迴應

pageContext 網頁的屬性是在這裡管理

session 與請求有關的會話期

application servlet 正在執行的內容

out 用來傳送回應的輸出

config servlet的構架部件

page JSP網頁本身

exception 針對錯誤網頁,未捕捉的例外

 

request表示HttpServletRequest物件。它包含了有關瀏覽器請求的資訊,並且提供了幾個用於獲取cookie, header, 和session資料的有用的方法。

   response表示HttpServletResponse物件,並提供了幾個用於設定送回瀏覽器的響應的方法(如cookies,頭資訊等)

   out物件是javax.jsp.JspWriter的一個例項,並提供了幾個方法使你能用於向瀏覽器回送輸出結果。

   pageContext表示一個javax.servlet.jsp.PageContext物件。它是用於方便存取各種範圍的名字空間、servlet相關的物件的API,並且包裝了通用的servlet相關功能的方法。

   session表示一個請求的javax.servlet.http.HttpSession物件。Session可以存貯使用者的狀態資訊

   applicaton 表示一個javax.servle.ServletContext物件。這有助於查詢有關servlet引擎和servlet環境的資訊

   config表示一個javax.servlet.ServletConfig物件。該物件用於存取servlet例項的初始化引數。

   page表示從該頁面產生的一個servlet例項

 

12. jsp有哪些動作?作用分別是什麼?

(這個問題似乎不重要,不明白為何有此題)

答:JSP共有以下6種基本動作

jsp:include:在頁面被請求的時候引入一個檔案。

jsp:useBean:尋找或者例項化一個JavaBean。

jsp:setProperty:設定JavaBean的屬性。

jsp:getProperty:輸出某個JavaBean的屬性。

jsp:forward:把請求轉到一個新的頁面。

jsp:plugin:根據瀏覽器型別為Java外掛生成OBJECT或EMBED標記

13、JSP的常用指令

isErrorPage(是否能使用Exception物件),isELIgnored(是否忽略表示式)

 

14. JSP中動態INCLUDE與靜態INCLUDE的區別?

答:動態INCLUDE用jsp:include動作實現

<jsp:includepage=included.jsp flush=true />它總是會檢查所含檔案中的變化,適合用於包含動態頁面,並且可以帶引數靜態INCLUDE用include偽碼實現,定不會檢查所含檔案的變化,適用於包含靜態頁面 <%@ include file=included.htm %>

 

15、兩種跳轉方式分別是什麼?有什麼區別?

(下面的回答嚴重錯誤,應該是想問forward和sendRedirect 的區別,畢竟出題的人不是專業搞文字藝術的人,可能表達能力並不見得很強,用詞不一定精準,加之其自身的技術面也可能存在一些問題,不一定真正將他的意思表達清楚了,嚴格意思上來講,一些題目可能根本就無人能答,所以,答題時要掌握主動,只要把自己知道的表達清楚就夠了,而不要去推敲原始題目的具體含義是什麼,不要一味想著是在答題)

答:有兩種,分別為:

<jsp:includepage=included.jsp flush=true>

<jsp:forward page=nextpage.jsp/>

前者頁面不會轉向include所指的頁面,只是顯示該頁的結果,主頁面還是原來的頁面。執行完後還會回來,相當於函式呼叫。並且可以帶引數.後者完全轉向新頁面,不會再回來。相當於goto 語句。

 

16、頁面間物件傳遞的方法

request,session,application,cookie等

17、JSP和Servlet有哪些相同點和不同點,他們之間的聯絡是什麼?

JSP是Servlet技術的擴充套件,本質上是Servlet的簡易方式,更強調應用的外表表達。JSP編譯後是"類servlet"。Servlet和JSP最主要的不同點在於,Servlet的應用邏輯是在Java檔案中,並且完全從表示層中的HTML裡分離開來。而JSP的情況是Java和HTML可以組合成一個副檔名為.jsp的檔案。JSP側重於檢視,Servlet主要用於控制邏輯。

 

18、MVC的各個部分都有那些技術來實現?如何實現?

答:MVC是Model-View-Controller的簡寫。Model代表的是應用的業務邏輯(通過JavaBean,EJB元件實現), View 是應用的表示面(由JSP頁面產生),Controller 是提供應用的處理過程控制(一般是一個Servlet),通過這種設計模型把應用邏輯,處理過程和顯示邏輯分成不同的元件實現。這些元件可以進行互動和重用。

 

19、我們在web應用開發過程中經常遇到輸出某種編碼的字元,如iso8859-1等,如何輸出一個某種編碼的字串?

 Public String translate (String str) {

   String tempStr = "";

   try {

     tempStr = newString(str.getBytes("ISO-8859-1"), "GBK");

     tempStr = tempStr.trim();

   }

   catch (Exception e) {

     System.err.println(e.getMessage());

   }

   return tempStr;

 }

20.現在輸入n個數字,以逗號,分開;然後可選擇升或者降序排序;按提交鍵就在另一頁面顯示按什麼排序,結果為,提供reset

五. 資料庫部分

1、用兩種方式根據部門號從高到低,工資從低到高列出每個員工的資訊。

employee:

     eid,ename,salary,deptid;

 select * from employee order by deptiddesc,salary

 

 

2、列出各個部門中工資高於本部門的平均工資的員工數和部門號,並按部門號排序

建立表:

       mysql> create table employee921(idint primary key auto_increment,name varchar(5

0),salarybigint,deptid int);

 

插入實驗資料:

mysql> insert intoemployee921 values(null,'zs',1000,1),(null,'ls',1100,1),(null

,'ww',1100,1),(null,'zl',900,1),(null,'zl',1000,2), (null,'zl',900,2) ,(null,'z

l',1000,2) ,(null,'zl',1100,2);

 

編寫sql語句:

 

()select avg(salary) from employee921 group bydeptid;

()mysql> selectemployee921.id,employee921.name,employee921.salary,employee921.dep

tid tid from  employee921 where salary > (selectavg(salary) from employee921 where deptid = tid);

   效率低的一個語句,僅供學習參考使用(在groupby之後不能使用where,只能使用having,在groupby之前可以使用where,即表示對過濾後的結果分組):

mysql> selectemployee921.id,employee921.name,employee921.salary,employee921.dep

tid tid from  employee921 where salary > (selectavg(salary) from employee921 group by deptid having deptid = tid);

()select count(*) ,tid

       from (

              selectemployee921.id,employee921.name,employee921.salary,employee921.deptid tid

              from      employee921

              where salary >

                    (select avg(salary) from employee921where  deptid = tid)

       ) as t

       group by tid ;

 

另外一種方式:關聯查詢

selecta.ename,a.salary,a.deptid

 from emp a,

    (select deptd,avg(salary) avgsal from empgroup by deptid ) b

 where a.deptid=b.deptid anda.salary>b.avgsal;

3、儲存過程與觸發器必須講,經常被面試到?

create procedureinsert_Student (_name varchar(50),_age int ,out _id int)

begin

       insert into studentvalue(null,_name,_age);

       select max(stuId) into _id from student;

end;

 

callinsert_Student('wfz',23,@id);

select @id;

 

mysql> createtrigger update_Student BEFORE update on student FOR EACH ROW

-> select * from student;

觸發器不允許返回結果

 

create trigger update_Student BEFORE update on studentFOR EACH ROW 

insert into student value(null,'zxx',28);

mysql的觸發器目前不能對當前表進行操作

 

create trigger update_Student BEFORE update on studentFOR EACH ROW 

delete from articles where id=8;

這個例子不是很好,最好是用刪除一個使用者時,順帶刪除該使用者的所有帖子

這裡要注意使用OLD.id

 

觸發器用處還是很多的,比如校內網、開心網、Facebook,你發一個日誌,自動通知好友,其實就是在增加日誌時做一個後觸發,再向通知表中寫入條目。因為觸發器效率高。而UCH沒有用觸發器,效率和資料處理能力都很低。

儲存過程的實驗步驟:

mysql> delimiter |

mysql> create procedure insertArticle_Procedure(pTitle varchar(50),pBid int,out

 pId int)

    -> begin

    -> insertinto article1 value(null,pTitle,pBid);

    -> selectmax(id) into pId from article1;

    -> end;

    -> |

Query OK, 0 rows affected (0.05 sec)

 

mysql> call insertArticle_Procedure('傳智播客',1,@pid);

    -> |

Query OK, 0 rows affected (0.00 sec)

 

mysql> delimiter ;

mysql> select @pid;

+------+

| @pid |

+------+

| 3    |

+------+

1 row in set (0.00 sec)

 

mysql> select * from article1;

+----+--------------+------+

| id | title       | bid  |

+----+--------------+------+

| 1  | test         | 1   |

| 2  | chuanzhiboke| 1    |

| 3  | 傳智播客     | 1   |

+----+--------------+------+

3 rows in set (0.00 sec)

 

觸發器的實驗步驟:

create table board1(id int primary keyauto_increment,name varchar(50),ar

ticleCount int);

 

create table article1(id int primary keyauto_increment,title varchar(50)

,bid int references board1(id));

 

delimiter |

 

create trigger insertArticle_Trigger after insert onarticle1 for each ro

w begin

    -> updateboard1 set articleCount=articleCount+1 where id= NEW.bid;

    -> end;

    -> |

 

delimiter ;

 

insert into board1 value (null,'test',0);

 

insert into article1 value(null,'test',1);

還有,每插入一個帖子,都希望將版面表中的最後發帖時間,帖子總數字段進行同步更新,用觸發器做效率就很高。下次課設計這樣一個案例,寫觸發器時,對於最後發帖時間可能需要用declare方式宣告一個變數,或者是用NEW.posttime來生成。

 

4、資料庫三正規化是什麼?

第一正規化(1NF):欄位具有原子性,不可再分。所有關係型資料庫系統都滿足第一正規化)

       資料庫表中的欄位都是單一屬性的,不可再分。例如,姓名欄位,其中的姓和名必須作為一個整體,無法區分哪部分是姓,哪部分是名,如果要區分出姓和名,必須設計成兩個獨立的欄位。

 

  第二正規化(2NF):

第二正規化(2NF)是在第一正規化(1NF)的基礎上建立起來的,即滿足第二正規化(2NF)必須先滿足第一正規化(1NF)。

要求資料庫表中的每個例項或行必須可以被惟一地區分。通常需要為表加上一個列,以儲存各個例項的惟一標識。這個惟一屬性列被稱為主關鍵字或主鍵。

 

第二正規化(2NF)要求實體的屬性完全依賴於主關鍵字。所謂完全依賴是指不能存在僅依賴主關鍵字一部分的屬性,如果存在,那麼這個屬性和主關鍵字的這一部分應該分離出來形成一個新的實體,新實體與原實體之間是一對多的關係。為實現區分通常需要為表加上一個列,以儲存各個例項的惟一標識。簡而言之,第二正規化就是非主屬性非部分依賴於主關鍵字。

  

 第三正規化的要求如下:

滿足第三正規化(3NF)必須先滿足第二正規化(2NF)。簡而言之,第三正規化(3NF)要求一個資料庫表中不包含已在其它表中已包含的非主關鍵字資訊。

所以第三正規化具有如下特徵:
         1,每一列只有一個值 
         2,每一行都能區分。 
         3,每一個表都不包含其他表已經包含的非主關鍵字資訊。

例如,帖子表中只能出現發帖人的id,而不能出現發帖人的id,還同時出現發帖人姓名,否則,只要出現同一發帖人id的所有記錄,它們中的姓名部分都必須嚴格保持一致,這就是資料冗餘。

 

5、說出一些資料庫優化方面的經驗?

用PreparedStatement 一般來說比Statement效能高:一個sql 發給伺服器去執行,涉及步驟:語法檢查、語義分析,編譯,快取

“inert into uservalues(1,1,1)”-à二進位制

“inert into uservalues(2,2,2)”-à二進位制

“inert into uservalues(?,?,?)”-à二進位制

 

 

 

有外來鍵約束會影響插入和刪除效能,如果程式能夠保證資料的完整性,那在設計資料庫時就去掉外來鍵。(比喻:就好比免檢產品,就是為了提高效率,充分相信產品的製造商)

(對於hibernate來說,就應該有一個變化:empleyee->Deptment物件,現在設計時就成了employeeàdeptid)

 

看mysql幫助文件子查詢章節的最後部分,例如,根據掃描的原理,下面的子查詢語句要比第二條關聯查詢的效率高:

1.  select e.name,e.salary wheree.managerid=(select id from employee where name='zxx');

 

2.   select e.name,e.salary,m.name,m.salary fromemployees e,employees m where

 e.managerid = m.id and m.name='zxx';

 

表中允許適當冗餘,譬如,主題帖的回覆數量和最後回覆時間等

將姓名和密碼單獨從使用者表中獨立出來。這可以是非常好的一對一的案例喲!

 

sql語句全部大寫,特別是列名和表名都大寫。特別是sql命令的快取功能,更加需要統一大小寫,sql語句à發給oracle伺服器à語法檢查和編譯成為內部指令à快取和執行指令。根據快取的特點,不要拼湊條件,而是用?和PreparedStatment

 

還有索引對查詢效能的改進也是值得關注的。

 

備註:下面是關於效能的討論舉例

 

4航班3個城市

 

m*n

 

select * fromflight,city where flight.startcityid=city.cityid and city.name='beijing';

 

m + n

 

 

select * from flightwhere startcityid = (select cityid from city where cityname='beijing');

 

selectflight.id,'beijing',flight.flightTime from flight where startcityid = (selectcityid from city where cityname='beijing')

6、union和union all有什麼不同?

假設我們有一個表Student,包括以下欄位與資料:

drop table student;

create table student
(
id int primary key,
name nvarchar2(50) not null,
score number not null
);

insert into studentvalues(1,'Aaron',78);
insert into student values(2,'Bill',76);
insert into student values(3,'Cindy',89);
insert into student values(4,'Damon',90);
insert into student values(5,'Ella',73);
insert into student values(6,'Frado',61);
insert into student values(7,'Gill',99);
insert into student values(8,'Hellen',56);
insert into student values(9,'Ivan',93);
insert into student values(10,'Jay',90);

commit;

Union和UnionAll的區別。

select *
from student
where id < 4

union

select *
from student
where id > 2 and id < 6

結果將是

1   Aaron    78
2    Bill    76
3    Cindy    89
4    Damon    90
5    Ella    73

如果換成Union All連線兩個結果集,則返回結果是:

1   Aaron    78
2    Bill    76
3    Cindy    89
3    Cindy    89
4    Damon    90
5    Ella    73

可以看到,Union和Union All的區別之一在於對重複結果的處理。

 

UNION在進行錶連結後會篩選掉重複的記錄,所以在錶連結後會對所產生的結果集進行排序運算,刪除重複的記錄再返回結果。實際大部分應用中是不會產生重複的記錄,最常見的是過程表與歷史表UNION。如:
select * from gc_dfys
union
select * from ls_jg_dfys
  這個SQL在執行時先取出兩個表的結果,再用排序空間進行排序刪除重複的記錄,最後返回結果集,如果表資料量大的話可能會導致用磁碟進行排序。
 而UNION ALL只是簡單的將兩個結果合併後就返回。這樣,如果返回的兩個結果集中有重複的資料,那麼返回的結果集就會包含重複的資料了。
 從效率上說,UNION ALL 要比UNION快很多,所以,如果可以確認合併的兩個結果集中不包含重複的資料的話,那麼就使用UNION ALL,

7.分頁語句

取出sql表中第31到40的記錄(以自動增長ID為主鍵)

sql server方案1:

    selecttop 10 * from t where id not in (select top 30 id from t order by id ) orde byid

sql server方案2:

    selecttop 10 * from t where id in (select top 40 id from t order by id) order by iddesc

 

mysql方案:select * from t order by idlimit 30,10

 

oracle方案:select* from (select rownum r,* from t where r<=40) where r>30

 

--------------------待整理進去的內容-------------------------------------

pageSize=20;

pageNo = 5;

 

1.分頁技術1(直接利用sql語句進行分頁,效率最高和最推薦的)

 

mysql:sql ="select * from articles limit " + (pageNo-1)*pageSize + ","+ pageSize;

oracle: sql ="select * from " +

                                                        "(selectrownum r,* from " +

                                                               "(select* from articles order by postime desc)" +

                                                        "whererownum<= " + pageNo*pageSize +") tmp " +

                                                 "wherer>" + (pageNo-1)*pageSize;

註釋:第7行保證rownum的順序是確定的,因為oracle的索引會造成rownum返回不同的值

簡洋提示:沒有order by時,rownum按順序輸出,一旦有了order by,rownum不按順序輸出了,這說明rownum是排序前的編號。如果對order by從句中的欄位建立了索引,那麼,rownum也是按順序輸出的,因為這時候生成原始的查詢結果集時會參照索引表的順序來構建。

 

sqlserver:sql ="select top 10 * from id not id(select top " + (pageNo-1)*pageSize +"id from articles)"

 

DataSource ds = newInitialContext().lookup(jndiurl);

Connection cn =ds.getConnection();

//"select * fromuser where id=?"  --->binarydirective

PreparedStatementpstmt = cn.prepareSatement(sql);

ResultSet rs =pstmt.executeQuery()

while(rs.next())

{

       out.println(rs.getString(1));

}

 

2.不可滾動的遊標

pageSize=20;

pageNo = 5;

cn = null

stmt = null;

rs = null;

try

{

sqlserver:sql ="select  * from articles";

 

DataSource ds = newInitialContext().lookup(jndiurl);

Connection cn =ds.getConnection();

//"select * fromuser where id=?"  --->binarydirective

PreparedStatementpstmt = cn.prepareSatement(sql);

ResultSet rs = pstmt.executeQuery()

for(intj=0;j<(pageNo-1)*pageSize;j++)

{

       rs.next();

}

 

int i=0;

 

while(rs.next()&& i<10)

{

       i++;

       out.println(rs.getString(1));

}

}

cacth(){}

finnaly

{

       if(rs!=null)try{rs.close();}catch(Exceptione){}

       if(stm.........

       if(cn............

}

 

3.可滾動的遊標

pageSize=20;

pageNo = 5;

cn = null

stmt = null;

rs = null;

try

{

sqlserver:sql ="select  * from articles";

 

DataSource ds = newInitialContext().lookup(jndiurl);

Connection cn =ds.getConnection();

//"select * fromuser where id=?"  --->binarydirective

PreparedStatementpstmt = cn.prepareSatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,...);

//根據上面這行程式碼的異常SQLFeatureNotSupportedException,就可判斷驅動是否支援可滾動遊標

 

ResultSet rs =pstmt.executeQuery()

rs.absolute((pageNo-1)*pageSize)

int i=0;

while(rs.next()&& i<10)

{

       i++;

       out.println(rs.getString(1));

}

}

cacth(){}

finnaly

{

       if(rs!=null)try{rs.close();}catch(Exceptione){}

       if(stm.........

       if(cn............

}

8.用一條SQL語句查詢出每門課都大於80分的學生姓名 

name   kecheng   fenshu 
張三    語文      81
張三    數學      75
李四    語文      76
李四    數學      90
王五    語文      81
王五    數學      100
王五    英語      90

準備資料的sql程式碼:

create table score(id int primary key auto_increment,namevarchar(20),subject varchar(20),score int);

insert into score values

(null,'張三','語文',81),

(null,'張三','數學',75),

(null,'李四','語文',76),

(null,'李四','數學',90),

(null,'王五','語文',81),

(null,'王五','數學',100),

(null,'王五 ','英語',90);

 

提示:當百思不得其解時,請理想思維,把小變成大做,把大變成小做,

 

答案:
A: select distinct name from score  where  name not in (selectdistinct name from score where score<=80)

 

B:select distincename t1 from score where 80< all (select score from score where name=t1);

 

9.所有部門之間的比賽組合

一個叫department的表,裡面只有一個欄位name,一共有4條紀錄,分別是a,b,c,d,對應四個球對,現在四個球對進行比賽,用一條sql語句顯示所有可能的比賽組合.

答:select a.name,b.name 
from team a, team b 
where a.name < b.name

 

10.每個月份的發生額都比101科目多的科目

請用SQL語句實現:從TestDB資料表中查詢出所有月份的發生額都比101科目相應月份的發生額高的科目。請注意:TestDB中有很多科目,都有1-12月份的發生額。
AccID:科目程式碼,Occmonth:發生額月份,DebitOccur:發生額。
資料庫名:JcyAudit,資料集:Select * from TestDB

準備資料的sql程式碼:

drop table if exists TestDB;

create table TestDB(id int primary key auto_increment,AccIDvarchar(20), Occmonth date, DebitOccur bigint);

insert into TestDB values

(null,'101','1988-1-1',100),

(null,'101','1988-2-1',110),

(null,'101','1988-3-1',120),

(null,'101','1988-4-1',100),

(null,'101','1988-5-1',100),

(null,'101','1988-6-1',100),

(null,'101','1988-7-1',100),

(null,'101','1988-8-1',100);

--複製上面的資料,故意把第一個月份的發生額數字改小一點

insert into TestDB values

(null,'102','1988-1-1',90),

(null,'102','1988-2-1',110),

(null,'102','1988-3-1',120),

(null,'102','1988-4-1',100),

(null,'102','1988-5-1',100),

(null,'102','1988-6-1',100),

(null,'102','1988-7-1',100),

(null,'102','1988-8-1',100);

--複製最上面的資料,故意把所有發生額數字改大一點

insert into TestDB values

(null,'103','1988-1-1',150),

(null,'103','1988-2-1',160),

(null,'103','1988-3-1',180),

(null,'103','1988-4-1',120),

(null,'103','1988-5-1',120),

(null,'103','1988-6-1',120),

(null,'103','1988-7-1',120),

(null,'103','1988-8-1',120);

--複製最上面的資料,故意把所有發生額數字改大一點

insert into TestDB values

(null,'104','1988-1-1',130),

(null,'104','1988-2-1',130),

(null,'104','1988-3-1',140),

(null,'104','1988-4-1',150),

(null,'104','1988-5-1',160),

(null,'104','1988-6-1',170),

(null,'104','1988-7-1',180),

(null,'104','1988-8-1',140);

--複製最上面的資料,故意把第二個月份的發生額數字改小一點

insert into TestDB values

(null,'105','1988-1-1',100),

(null,'105','1988-2-1',80),

(null,'105','1988-3-1',120),

(null,'105','1988-4-1',100),

(null,'105','1988-5-1',100),

(null,'105','1988-6-1',100),

(null,'105','1988-7-1',100),

(null,'105','1988-8-1',100);

答案:
select distinct AccID from TestDB

where AccID not in

       (selectTestDB.AccIDfrom TestDB,

               (select * from TestDB where AccID='101') asdb101

       whereTestDB.Occmonth=db101.Occmonth and TestDB.DebitOccur<=db101.DebitOccur

       );

 

11.統計每年每月的資訊

year  monthamount
1991   1     1.1
1991   2     1.2
1991   3     1.3
1991   4     1.4
1992   1     2.1
1992   2     2.2
1992   3     2.3
1992   4     2.4
查成這樣一個結果
year m1  m2  m3  m4
1991 1.1 1.2 1.3 1.4
1992 2.1 2.2 2.3 2.4 

提示:這個與工資條非常類似,與學生的科目成績也很相似。

 

準備sql語句:

drop table if existssales;

create table sales(idint auto_increment primary key,year varchar(10), month varchar(10), amountfloat(2,1));

insert into salesvalues

(null,'1991','1',1.1),

(null,'1991','2',1.2),

(null,'1991','3',1.3),

(null,'1991','4',1.4),

(null,'1992','1',2.1),

(null,'1992','2',2.2),

(null,'1992','3',2.3),

(null,'1992','4',2.4);


答案一、
select sales.year ,

(select t.amount fromsales t where t.month='1' and t.year= sales.year) '1',

(select t.amount fromsales t where t.month='1' and t.year= sales.year) '2',

(select t.amount fromsales t where t.month='1' and t.year= sales.year) '3',

(select t.amount fromsales t where t.month='1' and t.year= sales.year) as '4'

from sales  group by year;

 

12.顯示文章標題,發帖人、最後回覆時間

表:id,title,postuser,postdate,parentid

準備sql語句:

drop table if exists articles;

create table articles(id int auto_increment primary key,titlevarchar(50), postuser varchar(10), postdate datetime,parentid int referencesarticles(id));

insert into articles values

(null,'第一條','張三','1998-10-10 12:32:32',null),

(null,'第二條','張三','1998-10-10 12:34:32',null),

(null,'第一條回覆1','李四','1998-10-10 12:35:32',1),

(null,'第二條回覆1','李四','1998-10-10 12:36:32',2),

(null,'第一條回覆2','王五','1998-10-10 12:37:32',1),

(null,'第一條回覆3','李四','1998-10-10 12:38:32',1),

(null,'第二條回覆2','李四','1998-10-10 12:39:32',2),

(null,'第一條回覆4','王五','1998-10-10 12:39:40',1);

 

答案:

select a.title,a.postuser,

       (selectmax(postdate) from articles where parentid=a.id) reply

from articles a where a.parentid is null;

 

註釋:子查詢可以用在選擇列中,也可用於where的比較條件中,還可以用於from從句中。

13.刪除除了id號不同,其他都相同的學生冗餘資訊

2.學生表如下:
id號   學號   姓名課程編號課程名稱分數
1        2005001  張三 0001      數學   69
2        2005002  李四 0001      數學   89
3        2005001  張三 0001      數學   69
A: delete from tablename where id號 not in(select min(id號)from tablename group by 學號,姓名,課程編號,課程名稱,分數)

實驗:

create tablestudent2(id int auto_increment primary key,code varchar(20),name varchar(20));

insert into student2values(null,'2005001','張三'),(null,'2005002','李四'),(null,'2005001','張三');

 

//如下語句,mysql報告錯誤,可能刪除依賴後面統計語句,而刪除又導致統計語句結果不一致。

 

delete from student2where id not in(select min(id) from student2 group by name);

//但是,如下語句沒有問題:

select *  from student2 where id not in(select min(id)from student2 group by name);

//於是,我想先把分組的結果做成虛表,然後從虛表中選出結果,最後再將結果作為刪除的條件資料。

delete from student2where id not in(select mid from (select min(id) mid

from student2 groupby name) as t);

或者:

delete from student2where id not in(select min(id) from (select * from s

tudent2) as t groupby t.name);

14.航空網的幾個航班查詢題:

表結構如下:

flight{flightID,StartCityID,endCityID,StartTime}

city{cityID,CityName)

實驗環境:

create tablecity(cityID int auto_increment primary key,cityName varchar(20));

create table flight(flightID int auto_increment primary key,

       StartCityID int references city(cityID),

       endCityID int references city(cityID),

       StartTime timestamp);

//航班本來應該沒有日期部分才好,但是下面的題目當中涉及到了日期

insert into cityvalues(null,'北京'),(null,'上海'),(null,'廣州');

insert into flightvalues

       (null,1,2,'9:37:23'),(null,1,3,'9:37:23'),(null,1,2,'10:37:23'),(null,2,3,'10:37:23');

 

 

1、查詢起飛城市是北京的所有航班,按到達城市的名字排序

 

 

參與運算的列是我起碼能夠顯示出來的那些列,但最終我不一定把它們顯示出來。各個表組合出來的中間結果欄位中必須包含所有運算的欄位。

 

  select * from flight f,city c

       where f.endcityid = c.cityid andstartcityid =

       (select c1.cityid from city c1 wherec1.cityname = "北京")

       order by c.cityname asc;

 

mysql> selectflight.flightid,'北京' startcity, e.cityname from flight,city e wh

ereflight.endcityid=e.cityid and flight.startcityid=(select cityid from city wh

ere cityname='北京');

 

mysql> selectflight.flightid,s.cityname,e.cityname from flight,city s,city e wh

ere flight.startcityid=s.cityidand s.cityname='北京' and flight.endCityId=e.cit

yID order bye.cityName desc;

 

 

2、查詢北京到上海的所有航班紀錄(起飛城市,到達城市,起飛時間,航班號)

selectc1.CityName,c2.CityName,f.StartTime,f.flightID

from city c1,cityc2,flight f

wheref.StartCityID=c1.cityID

andf.endCityID=c2.cityID

and c1.cityName='北京'

and c2.cityName='上海'

3、查詢具體某一天(2005-5-8)的北京到上海的的航班次數

select count(*) from

(selectc1.CityName,c2.CityName,f.StartTime,f.flightID

from city c1,cityc2,flight f

wheref.StartCityID=c1.cityID

and f.endCityID=c2.cityID

and c1.cityName='北京'

and c2.cityName='上海'

and 查幫助獲得的某個日期處理函式(startTime) like '2005-5-8%'

 

mysql中提取日期部分進行比較的示例程式碼如下:

select * from flightwhere date_format(starttime,'%Y-%m-%d')='1998-01-02'

15.查出比經理薪水還高的員工資訊:

Drop table if notexists employees;

create tableemployees(id int primary key auto_increment,name varchar(50)

,salary int,managerid int references employees(id));

insert into employeesvalues (null,' lhm',10000,null), (null,' zxx',15000,1

),(null,'flx',9000,1),(null,'tg',10000,2),(null,'wzg',10000,3);

 

Wzg大於flx,lhm大於zxx

 

解題思路:

     根據sql語句的查詢特點,是逐行進行運算,不可能兩行同時參與運算。

涉及了員工薪水和經理薪水,所有,一行記錄要同時包含兩個薪水,所有想到要把這個表自關聯組合一下。

     首先要組合出一個包含有各個員工及該員工的經理資訊的長記錄,譬如,左半部分是員工,右半部分是經理。而迪卡爾積會組合出很多垃圾資訊,先去除這些垃圾資訊。

 

select e.* fromemployees e,employees m where e.managerid=m.id and e.sala

ry>m.salary;

16、求出小於45歲的各個老師所帶的大於12歲的學生人數

資料庫中有3個表 teacher 表,student表,tea_stu關係表。
teacher 表 teaID name age 
student 表 stuID name age 
teacher_student表 teaID stuID 
要求用一條sql查詢出這樣的結果 
1.顯示的欄位要有老師name, age 每個老師所帶的學生人數 
2 只列出老師age為40以下,學生age為12以上的記錄

預備知識:

      1.sql語句是對每一條記錄依次處理,條件為真則執行動作(select,insert,delete,update)

       2.只要是迪卡爾積,就會產生“垃圾”資訊,所以,只要迪卡爾積了,我們首先就要想到清除“垃圾”資訊

實驗準備:

       drop table if existstea_stu;

       drop table if existsteacher;

       drop table if existsstudent;

      create table teacher(teaIDint primary key,name varchar(50),age int);

      create tablestudent(stuID int primary key,name varchar(50),age int);

      create tabletea_stu(teaID int references teacher(teaID),stuID int referencesstudent(stuID));

insertinto teacher values(1,'zxx',45), (2,'lhm',25) , (3,'wzg',26) , (4,'tg',27);

insertinto student values(1,'wy',11), (2,'dh',25) , (3,'ysq',26) , (4,'mxc',27);

insertinto tea_stu values(1,1), (1,2), (1,3);

insertinto tea_stu values(2,2), (2,3), (2,4);

 insert into tea_stu values(3,3), (3,4), (3,1);

insertinto tea_stu values(4,4), (4,1), (4,2) , (4,3);

 

結果:2à3,3à2,4à3

 

解題思路:(真實面試答題時,也要寫出每個分析步驟,如果紙張不夠,就找別人要)

1要會統計分組資訊,統計資訊放在中間表中:

selectteaid,count(*) from tea_stu group by teaid;

 

2接著其實應該是篩除掉小於12歲的學生,然後再進行統計,中間表必須與student關聯才能得到12歲以下學生和把該學生記錄從中間表中剔除,程式碼是:

selecttea_stu.teaid,count(*) total from student,tea_stu

wherestudent.stuid=tea_stu.stuid and student.age>12 group by tea_stu.teaid

 

3.接著把上面的結果做成虛表與teacher進行關聯,並篩除大於45的老師

selectteacher.teaid,teacher.name,total from teacher ,(select tea_stu.tea

id,count(*)total from student,tea_stu where student.stuid=tea_stu.stuid and stu

dent.age>12group by tea_stu.teaid) as tea_stu2 whereteacher.teaid=tea_stu2.tea

id andteacher.age<45;

 

 

17.求出發帖最多的人:

selectauthorid,count(*) total from articles

group by authorid

having total=

(select max(total2) from (select count(*) total2 fromarticles group by authorid) as t);

 

selectt.authorid,max(t.total) from

(selectauthorid,count(*) total from articles )as t

這條語句不行,因為max只有一列,不能與其他列混淆。

 

selectauthorid,count(*) total from articles

group by authoridhaving total=max(total)也不行。

 

18、一個使用者表中有一個積分欄位,假如資料庫中有100多萬個使用者,若要在每年第一天凌晨將積分清零,你將考慮什麼,你將想什麼辦法解決?

alter table dropcolumn score;

alter table addcolunm score int;

可能會很快,但是需要試驗,試驗不能拿真實的環境來操刀,並且要注意,

這樣的操作時無法回滾的,在我的印象中,只有inert update delete等DML語句才能回滾,

對於create table,drop table ,alter table等DDL語句是不能回滾。

 

 

解決方案一,update user set score=0;

解決方案二,假設上面的程式碼要執行好長時間,超出我們的容忍範圍,那我就alter table user drop column score;alter tableuser add column score int。

 

下面程式碼實現每年的那個凌晨時刻進行清零。

Runnable runnable =

       new Runnable(){

              public void run(){

                     clearDb();

                     schedule(this,new Date(newDate().getYear()+1,0,0));

                     }           

                     };

 

schedule(runnable,

       new Date(new Date().getYear()+1,0,1));

 

19、一個使用者具有多個角色,請查詢出該表中具有該使用者的所有角色的其他使用者。

select count(*) asnum,tb.id

from

 tb,

 (select role from tb where id=xxx) as t1

where

 tb.role = t1.role and tb.id != t1.id

group by tb.id

having

       num = select count(role) from tb whereid=xxx;

20. xxx公司的sql面試

Table EMPLOYEES Structure:

EMPLOYEE_ID      NUMBER       Primary Key,

FIRST_NAME       VARCHAR2(25),

LAST_NAME       VARCHAR2(25),

Salary number(8,2),

HiredDate DATE,

Departmentid number(2)

TableDepartmentsStructure:

Departmentid number(2)        Primary Key,

DepartmentName  VARCHAR2(25).

 

 (2)基於上述EMPLOYEES表寫出查詢:寫出僱用日期在今年的,或者工資在[1000,2000]之間的,或者員工姓名(last_name)以’Obama’打頭的所有員工,列出這些員工的全部個人資訊。(4分)

select * from employees

where Year(hiredDate) =Year(date())

       or (salary between 1000 and 200)

       or left(last_name,3)='abc';

 

(3) 基於上述EMPLOYEES表寫出查詢:查出部門平均工資大於1800元的部門的所有員工,列出這些員工的全部個人資訊。(4分)

mysql> selectid,name,salary,deptid did from employee1 where (select avg(salary)

 from employee1 where deptid = did) > 1800;

 

(4) 基於上述EMPLOYEES表寫出查詢:查出個人工資高於其所在部門平均工資的員工,列出這些員工的全部個人資訊及該員工工資高出部門平均工資百分比。(5分)

select employee1.*,(employee1.salary-t.avgSalary)*100/employee1.salary

from employee1,

       (select deptid,avg(salary) avgSalary from employee1 group bydeptid) as t

where employee1.deptid =t.deptid and employee1.salary>t.avgSalary;

 

21、註冊Jdbc驅動程式的三種方式

 

22、用JDBC如何呼叫儲存過程

程式碼如下:

package com.huawei.interview.lym;

 

import java.sql.CallableStatement;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.sql.Types;

 

public class JdbcTest {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       // TODO Auto-generated method stub

       Connection cn = null;

       CallableStatement cstmt = null;   

       try {

           //這裡最好不要這麼幹,因為驅動名寫死在程式中了

           Class.forName("com.mysql.jdbc.Driver");

           //實際專案中,這裡應用DataSource資料,如果用框架,

           //這個資料來源不需要我們編碼建立,我們只需Datasource ds = context.lookup()

           //cn = ds.getConnection();        

           cn = DriverManager.getConnection("jdbc:mysql:///test","root","root");

           cstmt = cn.prepareCall("{callinsert_Student(?,?,?)}");

           cstmt.registerOutParameter(3,Types.INTEGER);

           cstmt.setString(1, "wangwu");

         &nbsnbsp; cstmt.setInt(2, 25);

           cstmt.execute();

           //get第幾個,不同的資料庫不一樣,建議不寫

           System.out.println(cstmt.getString(3));

       } catch (Exception e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       }

       finally

       {

 

           /*try{cstmt.close();}catch(Exception e){}

           try{cn.close();}catch(Exception e){}*/

           try {

              if(cstmt != null)

                  cstmt.close();

              if(cn != null)             

                  cn.close();

           } catch (SQLException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

           }

       }

    }

23、JDBC中的PreparedStatement相比Statement的好處

答:一個sql命令發給伺服器去執行的步驟為:語法檢查,語義分析,編譯成內部指令,快取指令,執行指令等過程。

select * from studentwhere id =3----快取--àxxxxx二進位制命令

select * from studentwhere id =3----直接取-àxxxxx二進位制命令

select * from studentwhere id =4--- -à會怎麼幹?

如果當初是select * from student where id =?--- -à又會怎麼幹?

 上面說的是效能提高

可以防止sql注入。

24. 寫一個用jdbc連線並訪問oracle資料的程式程式碼

25、Class.forName的作用?為什麼要用?

答:按引數中指定的字串形式的類名去搜尋並載入相應的類,如果該類位元組碼已經被載入過,則返回代表該位元組碼的Class例項物件,否則,按類載入器的委託機制去搜尋和載入該類,如果所有的類載入器都無法載入到該類,則丟擲ClassNotFoundException。載入完這個Class位元組碼後,接著就可以使用Class位元組碼的newInstance方法去建立該類的例項物件了。

有時候,我們程式中所有使用的具體類名在設計時(即開發時)無法確定,只有程式執行時才能確定,這時候就需要使用Class.forName去動態載入該類,這個類名通常是在配置檔案中配置的,例如,spring的ioc中每次依賴注入的具體類就是這樣配置的,jdbc的驅動類名通常也是通過配置檔案來配置的,以便在產品交付使用後不用修改源程式就可以更換驅動類名。

26、大資料量下的分頁解決方法。

答:最好的辦法是利用sql語句進行分頁,這樣每次查詢出的結果集中就只包含某頁的資料內容。再sql語句無法實現分頁的情況下,可以考慮對大的結果集通過遊標定位方式來獲取某頁的資料。

sql語句分頁,不同的資料庫下的分頁方案各不一樣,下面是主流的三種資料庫的分頁sql:

sql server:

       String sql =

       "select top " + pageSize +" * from students where id not in" +

 

 "(select top " + pageSize *(pageNumber-1) + " id from students order by id)" +

 

 "order by id";

 

mysql:

 

       String sql =

       "select * from students order by idlimit " + pageSize*(pageNumber-1) + "," + pageSize;

      

oracle:

 

       String sql =

        "select * from " + 

        (select *,rownum rid from (select * fromstudents order by postime desc) where rid<=" + pagesize*pagenumber +") as t" +

        "where t>" +pageSize*(pageNumber-1);

27、用 JDBC 查詢學生成績單, 把主要程式碼寫出來(考試概率極大).

Connection cn = null;

PreparedStatementpstmt =null;

Resultset rs = null;

try

{

       Class.forname(driveClassName);

       cn = DriverManager.getConnection(url,username,password);

       pstmt = cn.prepareStatement(“select  score.* from score ,student “ +

              “where score.stuId = student.idand student.name = ?”);

       pstmt.setString(1,studentName);

       Resultset rs = pstmt.executeQuery();

       while(rs.next())

       {

              system.out.println(rs.getInt(“subject”)  +  “    ” + rs.getFloat(“score”) );

       }

}catch(Exceptione){e.printStackTrace();}

finally

{

       if(rs != null) try{ rs.close()}catch(exception e){}

       if(pstmt != null)try{pstmt.close()}catch(exception e){}

       if(cn != null) try{ cn.close()}catch(exception e){}

}

 

 

28、這段程式碼有什麼不足之處?

try {
Connection conn = ...;
Statement stmt = ...;

ResultSet rs = stmt.executeQuery("select * fromtable1");

while(rs.next()) {

}
} catch(Exception ex) {
}

答:沒有finally語句來關閉各個物件,另外,使用finally之後,要把變數的定義放在try語句塊的外面,以便在try語句塊之外的finally塊中仍可以訪問這些變數。

 

29、說出資料連線池的工作機制是什麼?

J2EE伺服器啟動時會建立一定數量的池連線,並一直維持不少於此數目的池連線。客戶端程式需要連線時,池驅動程式會返回一個未使用的池連線並將其表記為忙。如果當前沒有空閒連線,池驅動程式就新建一定數量的連線,新建連線的數量有配置引數決定。當使用的池連線呼叫完成後,池驅動程式將此連線表記為空閒,其他呼叫就可以使用這個連線。

實現方式,返回的Connection是原始Connection的代理,代理Connection的close方法不是真正關連線,而是把它代理的Connection物件還回到連線池中。

 

30、為什麼要用 ORM?  和 JDBC 有何不一樣?

orm是一種思想,就是把object轉變成資料庫中的記錄,或者把資料庫中的記錄轉變成objecdt,我們可以用jdbc來實現這種思想,其實,如果我們的專案是嚴格按照oop方式編寫的話,我們的jdbc程式不管是有意還是無意,就已經在實現orm的工作了。

現在有許多orm工具,它們底層呼叫jdbc來實現了orm工作,我們直接使用這些工具,就省去了直接使用jdbc的繁瑣細節,提高了開發效率,現在用的較多的orm工具是hibernate。也聽說一些其他orm工具,如toplink,ojb等。

六. XML部分

1、xml有哪些解析技術?區別是什麼?

答:有DOM,SAX,STAX等

DOM:處理大型檔案時其效能下降的非常厲害。這個問題是由DOM的樹結構所造成的,這種結構佔用的記憶體較多,而且DOM必須在解析檔案之前把整個文件裝入記憶體,適合對XML的隨機訪問SAX:不現於DOM,SAX是事件驅動型的XML解析方式。它順序讀取XML檔案,不需要一次全部裝載整個檔案。當遇到像檔案開頭,文件結束,或者標籤開頭與標籤結束時,它會觸發一個事件,使用者通過在其回撥事件中寫入處理程式碼來處理XML檔案,適合對XML的順序訪問

STAX:Streaming APIfor XML (StAX)

講解這些區別是不需要特別去比較,就像說傳智播客與其他培訓機構的區別時,我們只需說清楚傳智播客有什麼特點和優點就行了,這就已經間接回答了彼此的區別。

 

2、你在專案中用到了xml技術的哪些方面?如何實現的?

答:用到了資料存貯,資訊配置兩方面。在做資料交換平臺時,將不能資料來源的資料組裝成XML檔案,然後將XML檔案壓縮打包加密後通過網路傳送給接收者,接收解密與解壓縮後再同XML檔案中還原相關資訊進行處理。在做軟體配置時,利用XML可以很方便的進行,軟體的各種配置引數都存貯在XML檔案中。

3、用jdom解析xml檔案時如何解決中文問題?如何解析?

答:看如下程式碼,用編碼方式加以解決 
package test; 
import java.io.*; 
public class DOMTest 

private String inFile = "c:\\people.xml" 
private String outFile = "c:\\people.xml" 
public static void main(String args[]) 

new DOMTest(); 

public DOMTest() 

try 

javax.xml.parsers.DocumentBuilder builder =

javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder();
org.w3c.dom.Document doc = builder.newDocument(); 
org.w3c.dom.Element root = doc.createElement("老師");
org.w3c.dom.Element wang = doc.createElement("王");
org.w3c.dom.Element liu = doc.createElement("劉");
wang.appendChild(doc.createTextNode("我是王老師")); 
root.appendChild(wang); 
doc.appendChild(root); 
javax.xml.transform.Transformer transformer = 
javax.xml.transform.TransformerFactory.newInstance().newTransformer(); 
transformer.setOutputProperty(javax.xml.transform.OutputKeys.ENCODING,"gb2312"); 
transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT,"yes");

transformer.transform(newjavax.xml.transform.dom.DOMSource(doc), 
new

javax.xml.transform.stream.StreamResult(outFile));

catch (Exception e) 

System.out.println (e.getMessage()); 


}

4、程式設計用JAVA解析XML的方式.

答:用SAX方式解析XML,XML檔案如下:

<?xml version=1.0encoding=gb2312?>

<person>

<name>王小明</name>

<college>資訊學院</college>

<telephone>6258113</telephone>

<notes>男,1955年生,博士,95年調入海南大學</notes>

</person>

事件回撥類SAXHandler.java

import java.io.*;

importjava.util.Hashtable;

import org.xml.sax.*;

public classSAXHandler extends HandlerBase

{

private Hashtabletable = new Hashtable();

private StringcurrentElement = null;

private StringcurrentValue = null;

public voidsetTable(Hashtable table)

{

this.table = table;

}

public HashtablegetTable()

{

return table;

}

public voidstartElement(String tag, AttributeList attrs)

throws SAXException

{

currentElement = tag;

}

public voidcharacters(char[] ch, int start, int length)

throws SAXException

{

currentValue = newString(ch, start, length);

}

public voidendElement(String name) throws SAXException

{

if(currentElement.equals(name))

table.put(currentElement,currentValue);

}

 

}

JSP內容顯示原始碼,SaxXml.jsp:

<HTML>

<HEAD>

<TITLE>剖析XML檔案people.xml</TITLE>

</HEAD>

<BODY>

<%@ pageerrorPage=ErrPage.jsp

contentType=text/html;charset=GB2312%>

<%@ pageimport=java.io.* %>

<%@ page import=java.util.Hashtable%>

<%@ pageimport=org.w3c.dom.* %>

<%@ pageimport=org.xml.sax.* %>

<%@ pageimport=javax.xml.parsers.SAXParserFactory %>

<%@ pageimport=javax.xml.parsers.SAXParser %>

<%@ pageimport=SAXHandler %>

<%

File file = new File(c:\people.xml);

FileReader reader =new FileReader(file);

Parser parser;

SAXParserFactory spf= SAXParserFactory.newInstance();

SAXParser sp =spf.newSAXParser();

SAXHandler handler =new SAXHandler();

sp.parse(newInputSource(reader), handler);

Hashtable hashTable =handler.getTable();

out.println(<TABLEBORDER=2><CAPTION>教師資訊表</CAPTION>);

out.println(<TR><TD>姓名</TD>+ <TD> +

(String)hashTable.get(newString(name)) + </TD></TR>);

out.println(<TR><TD>學院</TD>+ <TD> +

(String)hashTable.get(newString(college))+</TD></TR>);

out.println(<TR><TD>電話</TD>+ <TD> +

(String)hashTable.get(newString(telephone)) + </TD></TR>);

out.println(<TR><TD>備註</TD>+ <TD> +

(String)hashTable.get(newString(notes)) + </TD></TR>);

out.println(</TABLE>);

%>

</BODY>

</HTML>

5、XML文件定義有幾種形式?它們之間有何本質區別?解析XML文件有哪幾種方式?

a: 兩種形式dtd  schema,b: 本質區別:schema本身是xml的,可以被XML解析器解析(這也是從DTD上發展schema的根本目的),c:有DOM,SAX,STAX等

   DOM:處理大型檔案時其效能下降的非常厲害。這個問題是由DOM的樹結構所造成的,這種結構佔用的記憶體較多,而且DOM必須在解析檔案之前把整個文件裝入記憶體,適合對XML的隨機訪問

SAX:不現於DOM,SAX是事件驅動型的XML解析方式。它順序讀取XML檔案,不需要一次全部裝載整個檔案。當遇到像檔案開頭,文件結束,或者標籤開頭與標籤結束時,它會觸發一個事件,使用者通過在其回撥事件中寫入處理程式碼來處理XML檔案,適合對XML的順序訪問

   STAX:Streaming API for XML (StAX)

 

七. 流行的框架與新技術

 

1、談談你對Struts的理解。

答:

1. struts是一個按MVC模式設計的Web層框架,其實它就是一個大大的servlet,這個Servlet名為ActionServlet,或是ActionServlet的子類。我們可以在web.xml檔案中將符合某種特徵的所有請求交給這個Servlet處理,這個Servlet再參照一個配置檔案(通常為/WEB-INF/struts-config.xml)將各個請求分別分配給不同的action去處理。

一個擴充套件知識點:struts的配置檔案可以有多個,可以按模組配置各自的配置檔案,這樣可以防止配置檔案的過度膨脹;

2.ActionServlet把請求交給action去處理之前,會將請求引數封裝成一個formbean物件(就是一個java類,這個類中的每個屬性對應一個請求引數),封裝成一個什麼樣的formbean物件呢?看配置檔案。

3.要說明的是, ActionServlet把formbean物件傳遞給action的execute方法之前,可能會呼叫formbean的validate方法進行校驗,只有校驗通過後才將這個formbean物件傳遞給action的execute方法,否則,它將返回一個錯誤頁面,這個錯誤頁面由input屬性指定,(看配置檔案)作者為什麼將這裡命名為input屬性,而不是error屬性,我們後面結合實際的執行效果進行分析。

4.action執行完後要返回顯示的結果檢視,這個結果檢視是用一個ActionForward物件來表示的,actionforward物件通過struts-config.xml配置檔案中的配置關聯到某個jsp頁面,因為程式中使用的是在struts-config.xml配置檔案為jsp頁面設定的邏輯名,這樣可以實現action程式程式碼與返回的jsp頁面名稱的解耦。

 

你對struts可能還有自己的應用方面的經驗,那也要一併說出來。

2、談談你對Hibernate的理解。

答:

1. 物件導向設計的軟體內部執行過程可以理解成就是在不斷建立各種新物件、建立物件之間的關係,呼叫物件的方法來改變各個物件的狀態和物件消亡的過程,不管程式執行的過程和操作怎麼樣,本質上都是要得到一個結果,程式上一個時刻和下一個時刻的執行結果的差異就表現在記憶體中的物件狀態發生了變化。

2.為了在關機和記憶體空間不夠的狀況下,保持程式的執行狀態,需要將記憶體中的物件狀態儲存到持久化裝置和從持久化裝置中恢復出物件的狀態,通常都是儲存到關聯式資料庫來儲存大量物件資訊。從Java程式的執行功能上來講,儲存物件狀態的功能相比系統執行的其他功能來說,應該是一個很不起眼的附屬功能,java採用jdbc來實現這個功能,這個不起眼的功能卻要編寫大量的程式碼,而做的事情僅僅是儲存物件和恢復物件,並且那些大量的jdbc程式碼並沒有什麼技術含量,基本上是採用一套例行公事的標準程式碼模板來編寫,是一種苦活和重複性的工作。

3.通過資料庫儲存java程式執行時產生的物件和恢復物件,其實就是實現了java物件與關聯式資料庫記錄的對映關係,稱為ORM(即ObjectRelation Mapping),人們可以通過封裝JDBC程式碼來實現了這種功能,封裝出來的產品稱之為ORM框架,Hibernate就是其中的一種流行ORM框架。使用Hibernate框架,不用寫JDBC程式碼,僅僅是呼叫一個save方法,就可以將物件儲存到關聯式資料庫中,僅僅是呼叫一個get方法,就可以從資料庫中載入出一個物件。

4.使用Hibernate的基本流程是:配置Configuration物件、產生SessionFactory、建立session物件,啟動事務,完成CRUD操作,提交事務,關閉session。

5.使用Hibernate時,先要配置hibernate.cfg.xml檔案,其中配置資料庫連線資訊和方言等,還要為每個實體配置相應的hbm.xml檔案,hibernate.cfg.xml檔案中需要登記每個hbm.xml檔案。

6.在應用Hibernate時,重點要了解Session的快取原理,級聯,延遲載入和hql查詢。

3、AOP的作用。

4、你對Spring的理解。

1.Spring實現了工廠模式的工廠類(在這裡有必要解釋清楚什麼是工廠模式),這個類名為BeanFactory(實際上是一個介面),在程式中通常BeanFactory的子類ApplicationContext。Spring相當於一個大的工廠類,在其配置檔案中通過<bean>元素配置用於建立例項物件的類名和例項物件的屬性。

2. Spring提供了對IOC良好支援,IOC是一種程式設計思想,是一種架構藝術,利用這種思想可以很好地實現模組之間的解耦。IOC也稱為DI(DepencyInjection),什麼叫依賴注入呢?

譬如,Class Programmer

{

       Computer computer = null;

       public void code()

       {

              //Computer computer = newIBMComputer();

              //Computer computer =beanfacotry.getComputer();

              computer.write();

       }

       public void setComputer(Computercomputer)

       {

              this.computer = computer;

       }

}
另外兩種方式都由依賴,第一個直接依賴於目標類,第二個把依賴轉移到工廠上,第三個徹底與目標和工廠解耦了。在spring的配置檔案中配置片段如下:

<bean id=”computer”class=”cn.itcast.interview.Computer”>

</bean>

 

<bean id=”programmer”class=”cn.itcast.interview.Programmer”>

       <property name=”computer”  ref=”computer”></property>

</bean>

3. Spring提供了對AOP技術的良好封裝, AOP稱為面向切面程式設計,就是系統中有很多各不相干的類的方法,在這些眾多方法中要加入某種系統功能的程式碼,例如,加入日誌,加入許可權判斷,加入異常處理,這種應用稱為AOP。實現AOP功能採用的是代理技術,客戶端程式不再呼叫目標,而呼叫代理類,代理類與目標類對外具有相同的方法宣告,有兩種方式可以實現相同的方法宣告,一是實現相同的介面,二是作為目標的子類在,JDK中採用Proxy類產生動態代理的方式為某個介面生成實現類,如果要為某個類生成子類,則可以用CGLI B。在生成的代理類的方法中加入系統功能和呼叫目標類的相應方法,系統功能的代理以Advice物件進行提供,顯然要建立出代理物件,至少需要目標類和Advice類。spring提供了這種支援,只需要在spring配置檔案中配置這兩個元素即可實現代理和aop功能,例如,

<bean id=”proxy”type=”org.spring.framework.aop.ProxyBeanFactory”>

       <property name=”target” ref=””></property>

       <property name=”advisor” ref=””></property>

 

</bean>

 

5、談談Struts中的Action servlet。

6、Struts優缺點
優點:
 1. 實現MVC模式,結構清晰,使開發者只關注業務邏輯的實現.

2.有豐富的tag可以用 ,Struts的標記庫(Taglib),如能靈活動用,則能大大提高開發效率

3. 頁面導航

       使系統的脈絡更加清晰。通過一個配置檔案,即可把握整個系統各部分之間的聯絡,這對於後期的維護有著莫大的好處。尤其是當另一批開發者接手這個專案時,這種優勢體現得更加明顯。

4. 提供Exception處理機制 .

5. 資料庫連結池管理

6. 支援I18N

缺點

一、   轉到展示層時,需要配置forward,如果有十個展示層的jsp,需要配置十次struts,而且還不包括有時候目錄、檔案變更,需要重新修改forward,注意,每次修改配置之後,要求重新部署整個專案,而tomcate這樣的伺服器,還必須重新啟動伺服器

二、   二、 Struts 的Action必需是thread-safe方式,它僅僅允許一個例項去處理所有的請求。所以action用到的所有的資源都必需統一同步,這個就引起了執行緒安全的問題。

三、    測試不方便. Struts的每個Action都同Web層耦合在一起,這樣它的測試依賴於Web容器,單元測試也很難實現。不過有一個Junit的擴充套件工具Struts TestCase可以實現它的單元測試。

四、    型別的轉換. Struts的FormBean把所有的資料都作為String型別,它可以使用工具Commons-Beanutils進行型別轉化。但它的轉化都是在Class級別,而且轉化的型別是不可配置的。型別轉化時的錯誤資訊返回給使用者也是非常困難的。

五、   對Servlet的依賴性過強. Struts處理Action時必需要依賴ServletRequest 和ServletResponse,所有它擺脫不了Servlet容器。

六、    前端表示式語言方面.Struts整合了JSTL,所以它主要使用JSTL的表示式語言來獲取資料。可是JSTL的表示式語言在Collection和索引屬性方面處理顯得很弱。

七、    對Action執行的控制困難. Struts建立一個Action,如果想控制它的執行順序將會非常困難。甚至你要重新去寫Servlet來實現你的這個功能需求。

八、    對Action 執行前和後的處理. Struts處理Action的時候是基於class的hierarchies,很難在action處理前和後進行操作。

九、    對事件支援不夠. 在struts中,實際是一個表單Form對應一個Action類(或DispatchAction),換一句話說:在Struts中實際是一個表單只能對應一個事件,struts這種事件方式稱為application event,application event和component event相比是一種粗粒度的事件

 

 

7、STRUTS的應用(如STRUTS架構)

Struts是採用JavaServlet/JavaServer Pages技術,開發Web應用程式的開放原始碼的framework。採用Struts能開發出基於MVC(Model-View-Controller)設計模式的應用構架。 Struts有如下的主要功能:一.包含一個controllerservlet,能將使用者的請求傳送到相應的Action物件。二.JSP自由tag庫,並且在controller servlet中提供關聯支援,幫助開發員建立互動式表單應用。三.提供了一系列實用物件:XML處理、通過Java reflection APIs自動處理JavaBeans屬性、國際化的提示和訊息。

 

8、說說struts1與struts2的區別。

1.都是MVC的WEB框架,

2 struts1的老牌框架,應用很廣泛,有很好的群眾基礎,使用它開發風險很小,成本更低!struts2雖然基於這個框架,但是應用群眾並多,相對不成熟,未知的風險和變化很多,開發人員相對不好招,使用它開發專案的風險係數更大,用人成本更高!

3.struts2畢竟是站在前輩的基礎設計出來,它會改善和完善struts1中的一些缺陷,struts1中一些懸而未決問題在struts2得到了解決。

4.struts1的前端控制器是一個Servlet,名稱為ActionServlet,struts2的前端控制器是一個filter,在struts2.0中叫FilterDispatcher,在struts2.1中叫StrutsPrepareAndExecuteFilter。

5.struts1的action需要繼承Action類,struts2的action可以不繼承任何類;struts1對同一個路徑的所有請求共享一個Action例項,struts2對同一個路徑的每個請求分別使用一個獨立Action例項物件,所有對於struts2的Action不用考慮執行緒安全問題。

6.在struts1中使用formbean封裝請求引數,在struts2中直接使用action的屬性來封裝請求引數。

7.struts1中的多個業務方法放在一個Action中時(即繼承DispatchAction時),要麼都校驗,要麼都不校驗;對於struts2,可以指定只對某個方法進行校驗,當一個Action繼承了ActionSupport且在這個類中只編寫了validateXxx()方法,那麼則只對Xxx()方法進行校驗。

 

(一個請求來了的執行流程進行分析,struts2是自動支援分模組開發,並可以不同模組設定不同的url字首,這是通過package的namespace來實現的;struts2是支援多種型別的檢視;struts2的檢視地址可以是動態的,即檢視的名稱是支援變數方式的,舉例,論壇發帖失敗後回來還要傳遞boardid。檢視內容顯示方面:它的標籤用ognl,要el強大很多,在國際化方面支援分模組管理,兩個模組用到同樣的key,對應不同的訊息;)

 

       

與Struts1不同,Struts2對使用者的每一次請求都會建立一個Action,所以Struts2中的Action是執行緒安全的。

 

給我印象最深刻的是:struts配置檔案中的redirect檢視的url不能接受引數,而struts2配置檔案中的redirect檢視可以接受引數。

 

 

9、hibernate中的update()和saveOrUpdate()的區別,session的load()和get()的區別。

10、簡述 Hibernate 和 JDBC 的優缺點? 如何書寫一個 one to many 配置檔案.

11、iBatis與Hibernate有什麼不同?

相同點:遮蔽jdbc api的底層訪問細節,使用我們不用與jdbcapi打交道,就可以訪問資料。

jdbc api程式設計流程固定,還將sql語句與java程式碼混雜在了一起,經常需要拼湊sql語句,細節很繁瑣。

ibatis的好處:遮蔽jdbc api的底層訪問細節;將sql語句與java程式碼進行分離;提供了將結果集自動封裝稱為實體物件和物件的集合的功能,queryForList返回物件集合,用queryForObject返回單個物件;提供了自動將實體物件的屬性傳遞給sql語句的引數。

 

Hibernate是一個全自動的orm對映工具,它可以自動生成sql語句,ibatis需要我們自己在xml配置檔案中寫sql語句,hibernate要比ibatis功能負責和強大很多。因為hibernate自動生成sql語句,我們無法控制該語句,我們就無法去寫特定的高效率的sql。對於一些不太複雜的sql查詢,hibernate可以很好幫我們完成,但是,對於特別複雜的查詢,hibernate就很難適應了,這時候用ibatis就是不錯的選擇,因為ibatis還是由我們自己寫sql語句。

 

 

12、寫Hibernate的一對多和多對一雙向關聯的orm配置?

9、hibernate的inverse屬性的作用?

解決方案一,按照Object[]資料取出資料,然後自己組bean

解決方案二,對每個表的bean寫建構函式,比如表一要查出field1,field2兩個欄位,那麼有一個建構函式就是Bean(type1 filed1,type2

field2) ,然後在hql裡面就可以直接生成這個bean了。

 

13、在DAO中如何體現DAO設計模式?

解決方案一,按照Object[]資料取出資料,然後自己組bean

解決方案二,對每個表的bean寫建構函式,比如表一要查出field1,field2兩個欄位,那麼有一個建構函式就是Bean(type1 filed1,type2

field2) ,然後在hql裡面就可以直接生成這個bean了。

 

14、spring+Hibernate中委託方案怎麼配置?

解決方案一,按照Object[]資料取出資料,然後自己組bean

解決方案二,對每個表的bean寫建構函式,比如表一要查出field1,field2兩個欄位,那麼有一個建構函式就是Bean(type1 filed1,type2

field2) ,然後在hql裡面就可以直接生成這個bean了。

 

15、spring+Hibernate中委託方案怎麼配置?

解決方案一,按照Object[]資料取出資料,然後自己組bean

解決方案二,對每個表的bean寫建構函式,比如表一要查出field1,field2兩個欄位,那麼有一個建構函式就是Bean(type1 filed1,type2

field2) ,然後在hql裡面就可以直接生成這個bean了。

 

16.hibernate進行多表查詢每個表中各取幾個欄位,也就是說查詢出來的結果集沒有一個實體類與之對應如何解決;

 

解決方案一,按照Object[]資料取出資料,然後自己組bean

解決方案二,對每個表的bean寫建構函式,比如表一要查出field1,field2兩個欄位,那麼有一個建構函式就是Bean(type1 filed1,type2

field2) ,然後在hql裡面就可以直接生成這個bean了。

17.介紹一下Hibernate的二級快取

按照以下思路來回答:(1)首先說清楚什麼是快取,(2)再說有了hibernate的Session就是一級快取,即有了一級快取,為什麼還要有二級快取,(3)最後再說如何配置Hibernate的二級快取。

(1)快取就是把以前從資料庫中查詢出來和使用過的物件儲存在記憶體中(一個資料結構中),這個資料結構通常是或類似Hashmap,當以後要使用某個物件時,先查詢快取中是否有這個物件,如果有則使用快取中的物件,如果沒有則去查詢資料庫,並將查詢出來的物件儲存在快取中,以便下次使用。下面是快取的虛擬碼:

引出hibernate的第二級快取,用下面的虛擬碼分析了Cache的實現原理

Dao

{

       hashmap map = new map();

       User getUser(integer id)

       {

              User user = map.get(id)

              if(user == null)

              {

                     user = session.get(id);

                     map.put(id,user);

              }

              return user;

       }

}

 

Dao

{

       Cache cache = null

       setCache(Cache cache)

       {

              this.cache = cache

       }

      

       User getUser(int id)

       {

              if(cache!=null)

              {

                     User user = cache.get(id);

                     if(user ==null)

                     {

                            user =session.get(id);

                            cache.put(id,user);

                     }

                     return user;

              }

             

              return session.get(id);

       }

}

(2)Hibernate的Session就是一種快取,我們通常將之稱為Hibernate的一級快取,當想使用session從資料庫中查詢出一個物件時,Session也是先從自己內部檢視是否存在這個物件,存在則直接返回,不存在才去訪問資料庫,並將查詢的結果儲存在自己內部。由於Session代表一次會話過程,一個Session與一個資料庫連線相關連,所以Session最好不要長時間保持開啟,通常僅用於一個事務當中,在事務結束時就應關閉。並且Session是執行緒不安全的,被多個執行緒共享時容易出現問題。通常只有那種全域性意義上的快取才是真正的快取應用,才有較大的快取價值,因此,Hibernate的Session這一級快取的快取作用並不明顯,應用價值不大。Hibernate的二級快取就是要為Hibernate配置一種全域性快取,讓多個執行緒和多個事務都可以共享這個快取。我們希望的是一個人使用過,其他人也可以使用,session沒有這種效果。

(3)二級快取是獨立於Hibernate的軟體部件,屬於第三方的產品,多個廠商和組織都提供有快取產品,例如,EHCache和OSCache等等。在Hibernate中使用二級快取,首先就要在hibernate.cfg.xml配置檔案中配置使用哪個廠家的快取產品,接著需要配置該快取產品自己的配置檔案,最後要配置Hibernate中的哪些實體物件要納入到二級快取的管理中。明白了二級快取原理和有了這個思路後,很容易配置起Hibernate的二級快取。擴充套件知識:一個SessionFactory可以關聯一個二級快取,也即一個二級快取只能負責快取一個資料庫中的資料,當使用Hibernate 的二級快取後,注意不要有其他的應用或SessionFactory來更改當前資料庫中的資料,這樣快取的資料就會與資料庫中的實際資料不一致。

 

18、Spring 的依賴注入是什麼意思? 給一個 Bean 的 message 屬性, 字串型別, 注入值為 "Hello" 的 XML 配置檔案該怎麼寫?

 

19、Jdo是什麼?

JDO是Java物件持久化的新的規範,為java data object的簡稱,也是一個用於存取某種資料倉儲中的物件的標準化API。JDO提供了透明的物件儲存,因此對開發人員來說,儲存資料物件完全不需要額外的程式碼(如JDBC API的使用)。這些繁瑣的例行工作已經轉移到JDO產品提供商身上,使開發人員解脫出來,從而集中時間和精力在業務邏輯上。另外,JDO很靈活,因為它可以在任何資料底層上執行。JDBC只是面向關聯式資料庫(RDBMS)JDO更通用,提供到任何資料底層的儲存功能,比如關聯式資料庫、檔案、XML以及物件資料庫(ODBMS)等等,使得應用可移植性更強。

 

20、什麼是spring的IOC  AOP

21、STRUTS的工作流程!

22、spring 與EJB的區別!!

 

八. 軟體工程與設計模式

1、UML方面

標準建模語言UML。用例圖,靜態圖(包括類圖、物件圖和包圖),行為圖,互動圖(順序圖,合作圖),實現圖。

2、j2ee常用的設計模式?說明工廠模式。

總共23種,分為三大類:建立型,結構型,行為型

我只記得其中常用的6、7種,分別是:

建立型(工廠、工廠方法、抽象工廠、單例)

結構型(包裝、介面卡,組合,代理)

行為(觀察者,模版,策略)

然後再針對你熟悉的模式談談你的理解即可。  

 

Java中的23種設計模式:

Factory(工廠模式),      Builder(建造模式),       FactoryMethod(工廠方法模式),

Prototype(原始模型模式),Singleton(單例模式),   Facade(門面模式),

Adapter(介面卡模式),    Bridge(橋樑模式),        Composite(合成模式),

Decorator(裝飾模式),    Flyweight(享元模式),     Proxy(代理模式),

Command(命令模式),      Interpreter(直譯器模式), Visitor(訪問者模式),

Iterator(迭代子模式),   Mediator(調停者模式),    Memento(備忘錄模式),

Observer(觀察者模式),   State(狀態模式),         Strategy(策略模式),

Template Method(模板方法模式), Chain Of Responsibleity(責任鏈模式)

工廠模式:工廠模式是一種經常被使用到的模式,根據工廠模式實現的類可以根據提供的資料生成一組類中某一個類的例項,通常這一組類有一個公共的抽象父類並且實現了相同的方法,但是這些方法針對不同的資料進行了不同的操作。首先需要定義一個基類,該類的子類通過不同的方法實現了基類中的方法。然後需要定義一個工廠類,工廠類可以根據條件生成不同的子類例項。當得到子類的例項後,開發人員可以呼叫基類中的方法而不必考慮到底返回的是哪一個子類的例項。

3、開發中都用到了那些設計模式?用在什麼場合?

每個模式都描述了一個在我們的環境中不斷出現的問題,然後描述了該問題的解決方案的核心。通過這種方式,你可以無數次地使用那些已有的解決方案,無需在重複相同的工作。主要用到了MVC的設計模式。用來開發JSP/Servlet或者J2EE的相關應用。簡單工廠模式等。

九. j2ee部分

1、BS與CS的聯絡與區別。

C/S是Client/Server的縮寫。伺服器通常採用高效能的PC、工作站或小型機,並採用大型資料庫系統,如Oracle、Sybase、InFORMix或SQL Server。客戶端需要安裝專用的客戶端軟體。

B/S是Brower/Server的縮寫,客戶機上只要安裝一個瀏覽器(Browser),如Netscape Navigator或InternetExplorer,伺服器安裝Oracle、Sybase、InFORMix或SQL Server等資料庫。在這種結構下,使用者介面完全通過WWW瀏覽器實現,一部分事務邏輯在前端實現,但是主要事務邏輯在伺服器端實現。瀏覽器通過Web Server 同資料庫進行資料互動。

C/S 與B/S 區別:

1.硬體環境不同:

C/S 一般建立在專用的網路上, 小範圍裡的網路環境, 區域網之間再通過專門伺服器提供連線和資料交換服務.

B/S 建立在廣域網之上的, 不必是專門的網路硬體環境,例與電話上網, 租用裝置. 資訊自己管理. 有比C/S更強的適應範圍, 一般只要有作業系統和瀏覽器就行

2.對安全要求不同

C/S 一般面向相對固定的使用者群, 對資訊保安的控制能力很強. 一般高度機密的資訊系統採用C/S 結構適宜. 可以通過B/S釋出部分可公開資訊.

B/S 建立在廣域網之上, 對安全的控制能力相對弱, 可能面向不可知的使用者。

3.對程式架構不同

C/S 程式可以更加註重流程, 可以對許可權多層次校驗, 對系統執行速度可以較少考慮.

B/S 對安全以及訪問速度的多重的考慮, 建立在需要更加優化的基礎之上. 比C/S有更高的要求 B/S結構的程式架構是發展的趨勢, 從MS的.Net系列的BizTalk2000 Exchange 2000等, 全面支援網路的構件搭建的系統.SUN 和IBM推的JavaBean 構件技術等,使 B/S更加成熟.

4.軟體重用不同

C/S 程式可以不可避免的整體性考慮, 構件的重用性不如在B/S要求下的構件的重用性好.

B/S 對的多重結構,要求構件相對獨立的功能. 能夠相對較好的重用.就入買來的餐桌可以再利用,而不是做在牆上的石頭桌子

5.系統維護不同  

C/S 程式由於整體性, 必須整體考察, 處理出現的問題以及系統升級. 升級難. 可能是再做一個全新的系統

B/S 構件組成,方面構件個別的更換,實現系統的無縫升級. 系統維護開銷減到最小.使用者從網上自己下載安裝就可以實現升級.

6.處理問題不同

C/S 程式可以處理使用者面固定, 並且在相同區域, 安全要求高需求, 與作業系統相關. 應該都是相同的系統

B/S 建立在廣域網上, 面向不同的使用者群, 分散地域, 這是C/S無法作到的. 與作業系統平臺關係最小.

7.使用者介面不同

C/S 多是建立的Window平臺上,表現方法有限,對程式設計師普遍要求較高

B/S 建立在瀏覽器上, 有更加豐富和生動的表現方式與使用者交流. 並且大部分難度減低,減低開發成本.

8.資訊流不同

C/S 程式一般是典型的中央集權的機械式處理,互動性相對低

B/S 資訊流向可變化, B-B B-CB-G等資訊、流向的變化, 更像交易中心。

2、應用伺服器與WEB SERVER的區別?

應用伺服器:Weblogic、Tomcat、Jboss

WEB SERVER:IIS、Apache

3、應用伺服器有那些?

BEA WebLogic Server,IBMWebSphere Application Server,Oracle9i Application Server,jBoss,Tomcat

 

4、J2EE是什麼?

答:Je22是Sun公司提出的多層(multi-diered),分散式(distributed),基於元件(component-base)的企業級應用模型(enterpriese application model).在這樣的一個應用系統中,可按照功能劃分為不同的元件,這些元件又可在不同計算機上,並且處於相應的層次(tier)中。所屬層次包括客戶層(clietntier)元件,web層和元件,Business層和元件,企業資訊系統(EIS)層。

 

一個另類的回答:j2ee就是增刪改查。

5、J2EE是技術還是平臺還是框架?什麼是J2EE

   J2EE本身是一個標準,一個為企業分散式應用的開發提供的標準平臺。

   J2EE也是一個框架,包括JDBC、JNDI、RMI、JMS、EJB、JTA等技術。

6、請對以下在J2EE中常用的名詞進行解釋(或簡單描述)

web容器:給處於其中的應用程式元件(JSP,SERVLET)提供一個環境,使JSP,SERVLET直接更容器中的環境變數介面互動,不必關注其它系統問題。主要有WEB伺服器來實現。例如:TOMCAT,WEBLOGIC,WEBSPHERE等。該容器提供的介面嚴格遵守J2EE規範中的WEB APPLICATION 標準。我們把遵守以上標準的WEB伺服器就叫做J2EE中的WEB容器。

EJB容器:Enterprisejava bean 容器。更具有行業領域特色。他提供給執行在其中的元件EJB各種管理功能。只要滿足J2EE規範的EJB放入該容器,馬上就會被容器進行高效率的管理。並且可以通過現成的介面來獲得系統級別的服務。例如郵件服務、事務管理。

JNDI:(JavaNaming & Directory Interface)JAVA命名目錄服務。主要提供的功能是:提供一個目錄系統,讓其它各地的應用程式在其上面留下自己的索引,從而滿足快速查詢和定位分散式應用程式的功能。

JMS:(JavaMessage Service)JAVA訊息服務。主要實現各個應用程式之間的通訊。包括點對點和廣播。

JTA:(JavaTransaction API)JAVA事務服務。提供各種分散式事務服務。應用程式只需呼叫其提供的介面即可。

JAF:(JavaAction FrameWork)JAVA安全認證框架。提供一些安全控制方面的框架。讓開發者通過各種部署和自定義實現自己的個性安全控制策略。

RMI/IIOP:(RemoteMethod Invocation /internet物件請求中介協議)他們主要用於通過遠端呼叫服務。例如,遠端有一臺計算機上執行一個程式,它提供股票分析服務,我們可以在本地計算機上實現對其直接呼叫。當然這是要通過一定的規範才能在異構的系統之間進行通訊。RMI是JAVA特有的。

7、如何給weblogic指定大小的記憶體?

(這個問題不作具體回答,列出來只是告訴讀者可能會遇到什麼問題,你不需要面面俱到,什麼都精通。)

 

在啟動Weblogic的指令碼中(位於所在Domian對應伺服器目錄下的startServerName),增加setMEM_ARGS=-Xms32m -Xmx200m,可以調整最小記憶體為32M,最大200M

8、如何設定的weblogic的熱啟動模式(開發模式)與產品釋出模式?

可以在管理控制檯中修改對應伺服器的啟動模式為開發或產品模式之一。或者修改服務的啟動檔案或者commenv檔案,增加setPRODUCTION_MODE=true。

9、如何啟動時不需輸入使用者名稱與密碼?

修改服務啟動檔案,增加 WLS_USER和WLS_PW項。也可以在boot.properties檔案中增加加密過的使用者名稱和密碼.

10、在weblogic管理制臺中對一個應用域(或者說是一個網站,Domain)進行jms及ejb或連線池等相關資訊進行配置後,實際儲存在什麼檔案中?

儲存在此Domain的config.xml檔案中,它是伺服器的核心配置檔案。

11、說說weblogic中一個Domain的預設目錄結構?比如要將一個簡單的helloWorld.jsp放入何目錄下,然的在瀏覽器上就可打入http://主機:埠號//helloword.jsp就可以看到執行結果了? 又比如這其中用到了一個自己寫的javaBean該如何辦?

Domain目錄伺服器目錄applications,將應用目錄放在此目錄下將可以作為應用訪問,如果是Web應用,應用目錄需要滿足Web應用目錄要求,jsp檔案可以直接放在應用目錄中,Javabean需要放在應用目錄的WEB-INF目錄的classes目錄中,設定伺服器的預設應用將可以實現在瀏覽器上無需輸入應用名。

12、在weblogic中釋出ejb需涉及到哪些配置檔案

不同型別的EJB涉及的配置檔案不同,都涉及到的配置檔案包括ejb-jar.xml,weblogic-ejb-jar.xmlCMP實體Bean一般還需要weblogic-cmp-rdbms-jar.xml

13、如何在weblogic中進行ssl配置與客戶端的認證配置或說說j2ee(標準)進行ssl的配置?

預設安裝中使用DemoIdentity.jks和DemoTrust.jks  KeyStore實現SSL,需要配置伺服器使用Enable SSL,配置其埠,在產品模式下需要從CA獲取私有金鑰和數字證照,建立identity和trustkeystore,裝載獲得的金鑰和數字證照。可以配置此SSL連線是單向還是雙向的。

14、如何檢視在weblogic中已經發布的EJB?

可以使用管理控制檯,在它的Deployment中可以檢視所有已釋出的EJB

十. EBJ部分

1、EJB是基於哪些技術實現的?並說出SessionBean和EntityBean的區別,StatefulBean和StatelessBean的區別。

   EJB包括Session Bean、EntityBean、Message Driven Bean,基於JNDI、RMI、JAT等技術實現。

SessionBean在J2EE應用程式中被用來完成一些伺服器端的業務操作,例如訪問資料庫、呼叫其他EJB元件。EntityBean被用來代表應用系統中用到的資料。

對於客戶機,SessionBean是一種非永續性物件,它實現某些在伺服器上執行的業務邏輯。

對於客戶機,EntityBean是一種永續性物件,它代表一個儲存在永續性儲存器中的實體的物件檢視,或是一個由現有企業應用程式實現的實體。

Session Bean 還可以再細分為 Stateful Session Bean 與 StatelessSession Bean ,這兩種的 Session Bean都可以將系統邏輯放在method之中執行,不同的是 Stateful Session Bean 可以記錄呼叫者的狀態,因此通常來說,一個使用者會有一個相對應的 Stateful Session Bean 的實體。StatelessSession Bean 雖然也是邏輯元件,但是他卻不負責記錄使用者狀態,也就是說當使用者呼叫Stateless Session Bean 的時候,EJBContainer 並不會找尋特定的 Stateless Session Bean 的實體來執行這個 method。換言之,很可能數個使用者在執行某個 Stateless Session Bean 的methods 時,會是同一個 Bean 的 Instance 在執行。從記憶體方面來看,Stateful Session Bean 與 StatelessSession Bean 比較, Stateful Session Bean 會消耗J2EE Server 較多的記憶體,然而 Stateful Session Bean 的優勢卻在於他可以維持使用者的狀態。

 

2、簡要講一下 EJB 的 7 個 Transaction Level?

3、EJB與JAVA BEAN的區別?

Java Bean 是可複用的元件,對Java Bean並沒有嚴格的規範,理論上講,任何一個Java類都可以是一個Bean。但通常情況下,由於JavaBean是被容器所建立(如Tomcat)的,所以Java Bean應具有一個無參的構造器,另外,通常Java Bean還要實現Serializable介面用於實現Bean的永續性。Java Bean實際上相當於微軟COM模型中的本地程式內COM元件,它是不能被跨程式訪問的。Enterprise Java Bean 相當於DCOM,即分散式元件。它是基於Java的遠端方法呼叫(RMI)技術的,所以EJB可以被遠端訪問(跨程式、跨計算機)。但EJB必須被佈署在諸如Webspere、WebLogic這樣的容器中,EJB客戶從不直接訪問真正的EJB元件,而是通過其容器訪問。EJB容器是EJB元件的代理,EJB元件由容器所建立和管理。客戶通過容器來訪問真正的EJB元件。

4、EJB包括(SessionBean,EntityBean)說出他們的生命週期,及如何管理事務的?

SessionBean:StatelessSession Bean 的生命週期是由容器決定的,當客戶機發出請求要建立一個Bean的例項時,EJB容器不一定要建立一個新的Bean的例項供客戶機呼叫,而是隨便找一個現有的例項提供給客戶機。當客戶機第一次呼叫一個Stateful Session Bean 時,容器必須立即在伺服器中建立一個新的Bean例項,並關聯到客戶機上,以後此客戶機呼叫Stateful Session Bean 的方法時容器會把呼叫分派到與此客戶機相關聯的Bean例項。

EntityBean:EntityBeans能存活相對較長的時間,並且狀態是持續的。只要資料庫中的資料存在,Entity beans就一直存活。而不是按照應用程式或者服務程式來說的。即使EJB容器崩潰了,Entity beans也是存活的。Entity Beans生命週期能夠被容器或者 Beans自己管理。

EJB通過以下技術管理實務:物件管理組織(OMG)的物件實務服務(OTS),Sun Microsystems的TransactionService(JTS)、Java TransactionAPI(JTA),開發組(X/Open)的XA介面。

5、EJB容器提供的服務

主要提供宣告週期管理、程式碼產生、持續性管理、安全、事務管理、鎖和併發行管理等服務。

 

6、EJB的啟用機制

以Stateful Session Bean 為例:其Cache大小決定了記憶體中可以同時存在的Bean例項的數量,根據MRU或NRU演算法,例項在啟用和去啟用狀態之間遷移,啟用機制是當客戶端呼叫某個EJB例項業務方法時,如果對應EJBObject發現自己沒有繫結對應的Bean例項則從其去啟用Bean儲存中(通過序列化機制儲存例項)回覆(啟用)此例項。狀態變遷前會呼叫對應的ejbActive和ejbPassivate方法。

7、EJB的幾種型別

會話(Session)Bean ,實體(Entity)Bean訊息驅動的(Message Driven)Bean

會話Bean又可分為有狀態(Stateful)和無狀態(Stateless)兩種

實體Bean可分為Bean管理的持續性(BMP)和容器管理的持續性(CMP)兩種

8、客服端呼叫EJB物件的幾個基本步驟

設定JNDI服務工廠以及JNDI服務地址系統屬性,查詢Home介面,從Home介面呼叫Create方法建立Remote介面,通過Remote介面呼叫其業務方法。

十一. webservice部分

1、WEB SERVICE名詞解釋。JSWDL開發包的介紹。JAXP、JAXM的解釋。SOAP、UDDI,WSDL解釋。

Web ServiceWebService是基於網路的、分散式的模組化元件,它執行特定的任務,遵守具體的技術規範,這些規範使得Web Service能與其他相容的元件進行互操作。

JAXP(Java API forXML Parsing) 定義了在Java中使用DOM, SAX, XSLT的通用的介面。這樣在你的程式中你只要使用這些通用的介面,當你需要改變具體的實現時候也不需要修改程式碼。

JAXM(Java API forXML Messaging) 是為SOAP通訊提供訪問方法和傳輸機制的API。

WSDL是一種XML 格式,用於將網路服務描述為一組端點,這些端點對包含面向文件資訊或程式導向資訊的訊息進行操作。這種格式首先對操作和訊息進行抽象描述,然後將其繫結到具體的網路協議和訊息格式上以定義端點。相關的具體端點即組合成為抽象端點(服務)。

SOAP即簡單物件訪問協議(Simple Object Access Protocol),它是用於交換XML編碼資訊的輕量級協議。

UDDI 的目的是為電子商務建立標準;UDDI是一套基於Web的、分散式的、為WebService提供的、資訊註冊中心的實現標準規範,同時也包含一組使企業能將自身提供的Web Service註冊,以使別的企業能夠發現的訪問協議的實現標準。

2、CORBA是什麼?用途是什麼?

CORBA 標準是公共物件請求代理結構(Common Object Request Broker Architecture),由物件管理組織 (Object Management Group,縮寫為 OMG)標準化。它的組成是介面定義語言(IDL), 語言繫結(binding:也譯為聯編)和允許應用程式間互操作的協議。其目的為:用不同的程式設計語言書寫在不同的程式中執行,為不同的作業系統開發。

 

 

3. Linux

4、LINUX下執行緒,GDI類的解釋。

LINUX實現的就是基於核心輕量級程式的"一對一"執行緒模型,一個執行緒實體對應一個核心輕量級程式,而執行緒之間的管理在核外函式庫中實現。

GDI類為影象裝置程式設計介面類庫。

 

5. 問得稀裡糊塗的題

6、四種會話跟蹤技術

會話作用域ServletsJSP 頁面描述

page否是代表與一個頁面相關的物件和屬性。一個頁面由一個編譯好的 Java servlet 類(可以帶有任何的 include 指令,但是沒有include 動作)表示。這既包括 servlet 又包括被編譯成 servlet 的JSP 頁面

request是是代表與 Web 客戶機發出的一個請求相關的物件和屬性。一個請求可能跨越多個頁面,涉及多個 Web 元件(由於 forward指令和include 動作的關係)

session是是代表與用於某個 Web 客戶機的一個使用者體驗相關的物件和屬性。一個 Web 會話可以也經常會跨越多個客戶機請求

application是是代表與整個 Web 應用程式相關的物件和屬性。這實質上是跨越整個 Web 應用程式,包括多個頁面、請求和會話的一個全域性作用域

7、簡述邏輯操作(&,|,^)與條件操作(&&,||)的區別。

區別主要答兩點:a.條件操作只能操作布林型的,而邏輯操作不僅可以操作布林型,而且可以運算元值型

b.邏輯操作不會產生短路

 

十二. 其他

1、請用英文簡單介紹一下自己.

4、WEBSERVICE名詞解釋。JSWDL開發包的介紹。JAXP、JAXM的解釋。SOAP、UDDI,WSDL解釋。

2、請把http://tomcat.apache.org/ 首頁的這一段話用中文翻譯一下?

ApacheTomcat is the servlet container that is used in the official ReferenceImplementation for the Java Servlet andJavaServerPages technologies. The Java Servlet and JavaServer Pagesspecifications are developed by Sun under theJavaCommunity Process.

Apache Tomcat is developed in an open and participatoryenvironment and released under the Apache Software License. Apache Tomcat isintended to be a collaboration of the best-of-breed developers from around theworld. We invite you to participate in this open development project. To learnmore about getting involved, click here.

ApacheTomcat powers numerous large-scale, mission-critical web applications across adiverse range of industries and organizations. Some of these users and theirstories are listed on the PoweredBy wiki page.

3、美資軟體公司JAVA工程師電話面試題目

1. Talk about overriding, overloading.
2. Talk about JAVA design patterns you known.
3. Talk about the difference between LinkList, ArrayList and Victor.
4. Talk about the difference between an Abstract class and an Interface.
5. Class a = new Class(); Class b = new Class();
 if(a == b) returns true or false, why?
6. Why we use StringBuffer when concatenating strings?
7. Try to explain Singleton to us? Is it thread safe? If no, how to make itthread safe?
8. Try to explain Ioc?
9. How to set many-to-many relationship in Hibernate?
10. Talk about the difference between INNER JOIN and LFET JOIN.
11. Why we use index in database? How many indexes is the maximum in one tableas your suggestion?
12. When ‘Final’ is used in class, method and property, what dose it mean?
13. Do you have any experience on XML? Talk about any XML tool youused ,e.g. JAXB, JAXG.
14. Do you have any experience on Linux?
15. In OOD what is the reason when you create a Sequence diagram?

 1,堆和棧的區別,有一個64k的字串,是放到堆上,還是放到棧上,為什麼?

2,什麼時候用到介面,什麼時候用到抽象類,二者區別

3,有一個100萬的陣列,裡邊有兩個市重複的,如何設計演算法找到。

4,設計資料庫時,n維,如何設計。

例如[省份][城市][網咖],這是三維關係,它的表也應該有三個,網咖有外來鍵引用城市,城市有外來鍵應用省份,這個規律就是下層的要有一外來鍵去引用上層。

相關文章