java面試資料2

 

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

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

2、Java有沒有goto?

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

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

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

        &&還具有短路的功能,即如果第一個表達式爲false,則不再計算第二個表達式,例如,對於if(str!= null&& !str.equals(s))表達式,當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語句,即可跳出外層循環。

例如:

for(int i=0;i<10;i++){

   for(intj=0;j<10;j++){

       System.out.println(“i=” + i + “,j=” + j);

       if(j == 5) break ok;

   }

}

        另外,我個人通常並不使用標號這種方式,而是讓外層的循環條件表達式的結果可以受到裏層循環體代碼的控制,例如,要在二維數組中查找到某個數字。

 

int arr[][] ={{1,2,3},{4,5,6,7},{9}};

boolean found = false;

for(int i=0;i<arr.length&&!found;i++)       {

        for(intj=0;j<arr[i].length;j++){

              System.out.println(“i=” + i + “,j=” + j);

              if(arr[i][j] ==5) {

                      found =true;

                      break;

              }

        }

}

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

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

switch語句能否作用在String上說錯了,Java1.7之後已經支持這種寫法了!

 

6、short s1= 1; s1 = (s1+1是int類型,而等號左邊的是short類型,所以需要強轉)1 + 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、使用final關鍵字修飾一個變量時,是引用不能變,還是引用的對象不能變?

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

 finalStringBuffer a=new StringBuffer("immutable");

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

a=new StringBuffer("");

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

a.append(" broken!");

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

public void method(final  StringBuffer param){

}

實際上,這是辦不到的,在該方法內部仍然可以增加如下代碼來修改參數對象:

        param.append("a");

 

10,靜態變量和實例變量的區別?

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

        在程序運行時的區別:實例變量屬於某個對象的屬性,必須創建了實例對象,其中的實例變量纔會被分配空間,才能使用這個實例變量。靜態變量不屬於某個實例對象,而是屬於類,所以也稱爲類變量,只要程序加載了類的字節碼,不用創建任何實例對象,靜態變量就會被分配空間,靜態變量就可以被使用了。總之,實例變量必須創建對象後纔可以通過這個對象來使用,靜態變量則可以直接使用類名來引用。

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

public class VariantTest{

        publicstatic int staticVar = 0;

        publicint instanceVar = 0;

        publicVariantTest(){

              staticVar++;

              instanceVar++;

              System.out.println(staticVar +instanceVar);

        }

}

 

11、是否可以從一個static方法內部發出對非static方法的調用?

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

 

12、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中還定義了表示整數的最大值和最小值的常量。

 

13、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。

這裏有一些筆誤,floor的英文意義是地板,該方法就表示向下取整,Math.floor(11.6)的結果爲11,Math.floor(-11.6)的結果是-12;

 

 

14、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,那麼就不能在子類對其進行重載,如果定義的話,也只是定義了一個新方法,而不會達到重載的效果。

 

 

15、接口是否可繼承接口?抽象類是否可實現(implements)接口?抽象類是否可繼承具體類(concreteclass)?抽象類中是否可以有靜態的main方法?

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

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

        只要記住抽象類與普通類的唯一區別就是不能創建實例對象和允許有abstract方法。

 

16、Java中實現多態的機制是什麼?

        靠的是父類或接口定義的引用變量可以指向子類或具體實現類的實例對象,而程序調用的方法在運行期才動態綁定,就是引用變量所指向的具體實例對象的方法,也就是內存里正在運行的那個對象的方法,而不是引用變量的類型中定義的方法。

 

17、abstractclass和interface語法上有什麼區別?

 

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

2.抽象類中可以有普通成員變量,接口中沒有普通成員變量

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

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

eclipse下不報錯,但應該也不行),但接口中的抽象方法只能是public類型的,並且默認即爲public abstract類型。

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

6. 抽象類和接口中都可以包含靜態成員變量,抽象類中的靜態成員變量的訪問類型可以任意,但接口中定義的變量只能是publicstatic final類型,並且默認即爲publicstatic final類型。

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

 

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

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

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

private native void open(Stringname) throwsFileNotFoundException;

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

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

 

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

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

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

class Outer

{

static int x;

static class Inner

    {

        voidtest()

        {

              syso(x);

        }

    }

}

 

20、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引用變量進行初始化,把它設置爲初始值,應當這樣做:

public class Demo {

private String s;

...

public Demo {

s = "Initial Value";

}

...

}

而非

s = new String("Initial Value");

後者每次都會調用構造器,生成新對象,性能低下且內存開銷大,並且沒有意義,因爲String對象不可改變,所以對於內容相同的字符串,只要一個String對象來表示就可以了。也就說,多次調用上面的構造器創建多個對象,他們的            String類型屬性s都指向同一個對象。

上面的結論還基於這樣一個事實:對於字符串常量,如果內容相同,Java認爲它們代表同一個String對象。而用關鍵字new調用構造器,總是會創建一個新的對象,無論內容是否相同。

        至於爲什麼要把String類設計成不可變類,是它的用途決定的。其實不只String,很多Java標準類庫中的類都是不可變的。在開發一個系統的時候,我們有時候也需要設計不可變類,來傳遞一組相關的值,這也是面向對象思想的體現。不可變類有一些優點,比如因爲它的對象是隻讀的,所以多線程併發訪問也不會有任何問題。當然也有一些缺點,比如每個不同的狀態都要一個對象來代表,可能會造成性能上的問題。所以Java標準類庫還提供了一個可變版本,即StringBuffer。

 

21、ArrayList和Vector的區別

        這兩個類都實現了List接口(List接口繼承了Collection接口),他們都是有序集合,即存儲在這兩個集合中的元素的位置都是有順序的,相當於一種動態的數組,我們以後可以按位置索引號取出某個元素,並且其中的數據是允許重複的,這是與HashSet之類的集合的最大不同處,HashSet之類的集合不可以按索引號去檢索其中的元素,也不允許有重複的元素。

         ArrayList與Vector的區別主要包括兩個方面:.

(1)同步性:

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

(2)數據增長:

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

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

 

22、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引進的Map interface的一個實現。

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

     就HashMap與HashTable主要從三方面來說。

        一.歷史原因:Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現

        二.同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的

        三.值:只有HashMap可以讓你將空值作爲一個表的條目的key或value

 

23、List和 Map區別?

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

 

24、List,Set, Map是否繼承自Collection接口?

   List,Set是,Map不是

 

25、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(Obje)方法時,每次加入的對象就像火車站買票有排隊順序一樣,按先來後到的順序排序。有時候,也可以插隊,即調用add(intindex,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可多值。

 

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

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

        LinkedList也是線程不安全的,LinkedList提供了一些方法,使得LinkedList可以被當作堆棧和隊列來使用。

 

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

Vector newVector = new Vector();

For (int i=0;i<vector.size();i++)

{

Object obj = vector.get(i);

       if(!newVector.contains(obj);

             newVector.add(obj);

}

還有一種簡單的方式,利用了Set不允許重複元素:

HashSetset = new HashSet(vector);

 

28、Collection和Collections的區別。

        Collection是集合類的上級接口,繼承他的接口主要有Set和List.

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

 

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

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

        ==和equal區別也是考爛了的題,這裏說一下:

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

        equals方法是用於比較兩個獨立對象的內容是否相同,就好比去比較兩個人的長相是否相同,它比較的兩個對象是獨立的。

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

 

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

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

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

        它們都有增刪改查的方法。

        對於set,大概的方法是add,remove, contains等

        對於map,大概的方法就是put,remove,contains等

        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,這個自由發揮,也不是考記方法的能力,這些編程過程中會有提示,結合他們三者的不同說一下用法就行。

31、String s = new String("xyz");創建了幾個StringObject?是否可以繼承String類?

        兩個或一個都有可能,”xyz”對應一個對象,這個對象放在字符串常量緩衝區,常量”xyz”不管出現多少遍,都是緩衝區中的那一個。NewString每寫一遍,就創建一個新的對象,它使用常量”xyz”對象的內容來創建出一個新String對象。如果以前就用過’xyz’,那麼這裏就不會創建”xyz”了,直接從緩衝區拿,這時創建了一個StringObject;但如果以前沒有用過"xyz",那麼此時就會創建一個對象並放入緩衝區,這種情況它創建兩個對象。至於String類是否繼承,答案是否定的,因爲String默認final修飾,是不可繼承的。

 

32、String和StringBuffer的區別

        JAVA平臺提供了兩個類:String和StringBuffer,它們可以儲存和操作字符串,即包含多個字符的字符數據。這個String類提供了數值不可改變的字符串。而這個StringBuffer類提供的字符串可以進行修改。當你知道字符數據要改變的時候你就可以使用StringBuffer。典型地,你可以使用StringBuffers來動態構造字符數據。

 

33、下面這條語句一共創建了多少個對象:String s="a"+"b"+"c"+"d";

對於如下代碼:

String s1 = "a";

String s2 = s1 + "b";

String s3 = "a" + "b";

System.out.println(s2 == "ab");

System.out.println(s3 == "ab");

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

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

          String s ="a" + "b" +"c" + "d";

          System.out.println(s== "abcd");

最終打印的結果應該爲true。

 

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

        我們知道finally{}中的語句是一定會執行的,那麼這個可能正常脫口而出就是return之前,return之後可能就出了這個方法了,鬼知道跑哪裏去了,但更準確的應該是在return中間執行,請看下面程序代碼的運行結果:

public classTest {

    public static void main(String[]args) {

       System.out.println(newTest().test());;

    }

    static int test()

    {

       intx = 1;

       try

       {

          returnx;

       }

       finally

       {

          ++x;

       }

    }

}

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

1

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

 

35、final, finally, finalize的區別。

        final 用於聲明屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承。內部類要訪問局部變量,局部變量必須定義成final類型。

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

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

 

36、運行時異常與一般異常有何異同?

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

 

37、error和exception有什麼區別?

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

 

38、簡單說說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異常。

 

39、Java 中堆和棧有什麼區別?

        JVM 中堆和棧屬於不同的內存區域,使用目的也不同。棧常用於保存方法幀和局部變量,而對象總是在堆上分配。棧通常都比堆小,也不會在多個線程之間共享,而堆被整個 JVM 的所有線程共享。

        棧:在函數中定義的一些基本類型的變量和對象的引用變量都是在函數的棧內存中分配,當在一段代碼塊定義一個變量時,Java 就在棧中爲這個變量分配內存空間,當超過變量的作用域後,Java 會自動釋放掉爲該變量分配的內存空間,該內存空間可以立即被另作它用。

        堆:堆內存用來存放由 new 創建的對象和數組,在堆中分配的內存,由 Java 虛擬機的自動垃圾回收器來管理。在堆中產生了一個數組或者對象之後,還可以在棧中定義一個特殊的變量,讓棧中的這個變量的取值等於數組或對象在堆內存中的首地址,棧中的這個變量就成了數組或對象的引用變量,以後就可以在程序中使用棧中的引用變量來訪問堆中的數組或者對象,引用變量就相當於是爲數組或者對象起的一個名稱。

 

40、能將 int 強制轉換爲 byte 類型的變量嗎?如果該值大於 byte 類型的範圍,將會出現什麼現象?

        我們可以做強制轉換,但是 Java 中 int 是 32 位的,而 byte 是 8 位的,所以,如果強制轉化,int 類型的高 24 位將會被丟棄,因爲byte 類型的範圍是從 -128 到 128。這裏筆誤:-128到127

41、a.hashCode() 有什麼用?與 a.equals(b) 有什麼關係?

        hashCode() 方法對應對象整型的 hash 值。它常用於基於 hash 的集合類,如 Hashtable、HashMap、LinkedHashMap等等。它與 equals() 方法關係特別緊密。根據 Java 規範,兩個使用 equal() 方法來判斷相等的對象,必須具有相同的 hash code。

 

42、字節流與字符流的區別

       要把一段二進制數據數據逐一輸出到某個設備中,或者從某個設備中逐一讀取一段二進制數據,不管輸入輸出設備是什麼,我們要用統一的方式來完成這些操作,用一種抽象的方式進行描述,這個抽象描述方式起名爲IO流,對應的抽象類爲OutputStream和InputStream,不同的實現類就代表不同的輸入和輸出設備,它們都是針對字節進行操作的。

       計算機中的一切最終都是二進制的字節形式存在。對於經常用到的中文字符,首先要得到其對應的字節,然後將字節寫入到輸出流。讀取時,首先讀到的是字節,可是我們要把它顯示爲字符,我們需要將字節轉換成字符。由於這樣的需求很廣泛,Java專門提供了字符流包裝類。

      底層設備永遠只接受字節數據,有時候要寫字符串到底層設備,需要將字符串轉成字節再進行寫入。字符流是字節流的包裝,字符流則是直接接受字符串,它內部將串轉成字節,再寫入底層設備,這爲我們向IO設備寫入或讀取字符串提供了一點點方便。

      字符向字節轉換時,要注意編碼的問題,因爲字符串轉成字節數組,其實是轉成該字符的某種編碼的字節形式,讀取也是反之的道理。

 

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

        我們有時候將一個java對象變成字節流的形式傳出去或者從一個字節流中恢復成一個java對象,例如,要將java對象存儲到硬盤或者傳送給網絡上的其他計算機,這個過程我們可以自己寫代碼去把一個java對象變成某個格式的字節流再傳輸。

        但是,jre本身就提供了這種支持,我們可以調用OutputStream的writeObject方法來做,如果要讓java幫我們做,要被傳輸的對象必須實現serializable接口,這樣,javac編譯時就會進行特殊處理,編譯的類纔可以被writeObject方法操作,這就是所謂的序列化。需要被序列化的類必須實現Serializable接口,該接口是一個mini接口,其中沒有需要實現方法,implements Serializable只是爲了標註該對象是可被序列化的。

        例如,在web開發中,如果對象被保存在了Session中,tomcat在重啓時要把Session對象序列化到硬盤,這個對象就必須實現Serializable接口。如果對象要經過分佈式系統進行網絡傳輸,被傳輸的對象就必須實現Serializable接口。

 

44、描述一下JVM加載class文件的原理機制?

        JVM中類的裝載是由ClassLoader和它的子類來實現的,Java ClassLoader是一個重要的Java運行時系統組件。它負責在運行時查找和裝入類文件的類。

 

45、heap和stack有什麼區別。

        java的內存分爲兩類,一類是棧內存,一類是堆內存。棧內存是指程序進入一個方法時,會爲這個方法單獨分配一塊私屬存儲空間,用於存儲這個方法內部的局部變量,當這個方法結束時,分配給這個方法的棧會釋放,這個棧中的變量也將隨之釋放。

        堆是與棧作用不同的內存,一般用於存放不在當前方法棧中的那些數據,例如,使用new創建的對象都放在堆裏,所以,它不會隨方法的結束而消失。方法中的局部變量使用final修飾後,放在堆中,而不是棧中。

 

 

46、GC是什麼?爲什麼要有GC?

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

 

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

        Java語言中一個顯著的特點就是引入了垃圾回收機制,使c++程序員最頭疼的內存管理的問題迎刃而解,它使得Java程序員在編寫程序的時候不再需要考慮內存管理。由於垃圾回收機制,Java中的對象不再有"作用域"的概念,只有對象的引用纔有"作用域"。

        垃圾回收可以有效的防止內存泄露,有效的使用可以使用的內存。垃圾回收器通常是作爲一個單獨的低級別的線程運行,不可預知的情況下對內存堆中已經死亡的或者長時間沒有使用的對象進行清除和回收,程序員不能實時的調用垃圾回收器對某個對象或所有對象進行垃圾回收。

        回收機制有分代複製垃圾回收和標記垃圾回收,增量垃圾回收。

 

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

        對於GC來說,當程序員創建對象時,GC就開始監控這個對象的地址、大小以及使用情況。通常,GC採用有向圖的方式記錄和管理堆(heap)中的所有對象。通過這種方式確定哪些對象是"可達的",哪些對象是"不可達的"。當GC確定一些對象爲"不可達"時,GC就有責任回收這些內存空間。

        程序員可以手動執行System.gc(),通知GC運行,但是Java語言規範並不保證GC一定會執行。

 

49、Java 中,throw 和 throws 有什麼區別

        throw 用於拋出 java.lang.Throwable 類的一個實例化對象,意思是說你可以通過關鍵字 throw 拋出一個Exception,如:

throw new IllegalArgumentException(“XXXXXXXXX″)

        而throws 的作用是作爲方法聲明和簽名的一部分,方法被拋出相應的異常以便調用者能處理。Java 中,任何未處理的受檢查異常強制在 throws 子句中聲明。

 

50,java中會存在內存泄漏嗎,請簡單描述。

        先解釋什麼是內存泄漏:所謂內存泄露就是指一個不再被程序使用的對象或變量一直被佔據在內存中。java中有垃圾回收機制,它可以保證當對象不再被引用的時候,對象將自動被垃圾回收器從內存中清除掉。

        由於Java使用有向圖的方式進行垃圾回收管理,可以消除引用循環的問題,例如有兩個對象,相互引用,只要它們和根進程不可達,那麼GC也是可以回收它們的。

        java中的內存泄露的情況:長生命週期的對象持有短生命週期對象的引用就很可能發生內存泄露,儘管短生命週期對象已經不再需要,但是因爲長生命週期對象持有它的引用而導致不能被回收,這就是java中內存泄露的發生場景,通俗地說,就是程序員可能創建了一個對象,以後一直不再使用這個對象,這個對象卻一直被引用,即這個對象無用但是卻無法被垃圾回收器回收的,這就是java中可能出現內存泄露的情況,例如,緩存系統,我們加載了一個對象放在緩存中(例如放在一個全局map對象中),然後一直不再使用它,這個對象一直被緩存引用,但卻不再被使用。

 

51、說一說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()方法。

 

 

 

52、Servlet API中forward()與redirect()的區別?

 

    1.從地址欄顯示來說

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

        redirect是服務端根據邏輯,發送一個狀態碼,告訴瀏覽器重新去請求那個地址.所以地址欄顯示的是新的URL.所以redirect等於客戶端向服務器端發出兩次request,同時也接受兩次response。

    2.從數據共享來說

        forward:轉發頁面和轉發到的頁面可以共享request裏面的數據.

        redirect:不能共享數據.

        redirect不僅可以重定向到當前應用程序的其他資源,還可以重定向到同一個站點上的其他應用程序中的資源,甚至是使用絕對URL重定向到其他站點的資源.

        forward方法只能在同一個Web應用程序內的資源之間轉發請求.forward 是服務器內部的一種操作.

        redirect 是服務器通知客戶端,讓客戶端重新發起請求.

   所以,你可以說 redirect 是一種間接的請求, 但是你不能說"一個請求是屬於forward還是redirect "

    3.從運用地方來說

        forward:一般用於用戶登陸的時候,根據角色轉發到相應的模塊.

        redirect:一般用於用戶註銷登陸時返回主頁面和跳轉到其它的網站等.

    4.從效率來說

        forward:高.

        redirect:低.

 

 

 

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

 

        1,request.getParameter()取得是通過容器的實現來取得通過類似post,get等方式傳入的數據。

 

            request.setAttribute()和getAttribute()只是在web容器內部流轉,僅僅是請求處理階段。

 

        2,getAttribute是返回對象,getParameter返回字符串

 

        3,getAttribute()一向是和setAttribute()一起使用的,只有先用setAttribute()設置之後,才能夠通過getAttribute()來獲得值,它們傳遞的是Object類型的數據。而且必須在同一個request對象中使用纔有效。,而getParameter()是接收表單的get或者post提交過來的參數

 

 

 

54,jsp靜態包含和動態包含的區別

 

        1、<%@include file="xxx.jsp"%>爲jsp中的編譯指令,其文件的包含是發生在jsp向servlet轉換的時期,而<jsp:include page="xxx.jsp">是jsp中的動作指令,其文件的包含是發生在編譯時期,也就是將java文件編譯爲class文件的時期

 

        2、使用靜態包含只會產生一個class文件,而使用動態包含會產生多個class文件

 

        3、使用靜態包含,包含頁面和被包含頁面的request對象爲同一對象,因爲靜態包含只是將被包含的頁面的內容複製到包含的頁面中去;而動態包含包含頁面和被包含頁面不是同一個頁面,被包含的頁面的request對象可以取到的參數範圍要相對大些,不僅可以取到傳遞到包含頁面的參數,同樣也能取得在包含頁面向下傳遞的參數

 

 

 

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

 

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

 

 

 

 56,jsp有哪些內置對象?作用分別是什麼?

 

        JSP共有以下9個內置的對象:

 

        1,request 用戶端請求,此請求會包含來自GET/POST請求的參數

 

        2,response 網頁傳回用戶端的迴應

 

        3,pageContext 網頁的屬性是在這裏管理

 

        4,session 與請求有關的會話期

 

        5,application servlet 正在執行的內容

 

        6,out 用來傳送回應的輸出

 

        7,config  servlet的構架部件

 

        8,page JSP網頁本身

 

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

 

 

 

57,Http中,get和post方法的區別

 

        1,Get是向服務器發索取數據的一種請求,而Post是向服務器提交數據的一種請求

 

        2,Get是獲取信息,而不是修改信息,類似數據庫查詢功能一樣,數據不會被修改

 

        3,Get請求的參數會跟在url後進行傳遞,請求的數據會附在URL之後,以?分割URL和傳輸數據,參數之間以&相連,%XX中的XX爲該符號以16進製表示的ASCII,如果數據是英文字母/數字,原樣發送,如果是空格,轉換爲+,如果是中文/其他字符,則直接把字符串用BASE64加密。

        4,Get傳輸的數據有大小限制,因爲GET是通過URL提交數據,那麼GET可提交的數據量就跟URL的長度有直接關係了,不同的瀏覽器對URL的長度的限制是不同的。

 

        5,GET請求的數據會被瀏覽器緩存起來,用戶名和密碼將明文出現在URL上,其他人可以查到歷史瀏覽記錄,數據不太安全。

 

在服務器端,用Request.QueryString來獲取Get方式提交來的數據

Post請求則作爲http消息的實際內容發送給web服務器,數據放置在HTML Header內提交,Post沒有限制提交的數據。Post比Get安全,當數據是中文或者不敏感的數據,則用get,因爲使用get,參數會顯示在地址,對於敏感數據和不是中文字符的數據,則用post。

        6,POST表示可能修改變服務器上的資源的請求,在服務器端,用Post方式提交的數據只能用Request.Form來獲取。

 

(僅供參考,如果有更好的回答,歡迎探討)

 

 

 

58,什麼是cookie?Session和cookie有什麼區別?

 

    Cookie是會話技術,將用戶的信息保存到瀏覽器的對象.

 

    區別:

 

        (1)cookie數據存放在客戶的瀏覽器上,session數據放在服務器上

        (2)cookie不是很安全,別人可以分析存放在本地的COOKIE並進行COOKIE欺騙,如果主要考慮到安全應當使用session

        (3)session會在一定時間內保存在服務器上。當訪問增多,會比較佔用你服務器的性能,如果主要考慮到減輕服務器性能方面,應當使用COOKIE

        (4)單個cookie在客戶端的限制是3K,就是說一個站點在客戶端存放的COOKIE不能3K。

 

    結論:

 

        將登陸信息等重要信息存放爲SESSION;其他信息如果需要保留,可以放在COOKIE中。

 

 

 

59,jsp和servlet的區別、共同點、各自應用的範圍?

 

        JSP是Servlet技術的擴展,本質上就是Servlet的簡易方式。JSP編譯後是“類servlet”。

 

        Servlet和JSP最主要的不同點在於:Servlet的應用邏輯是在Java文件中,並且完全從表示層中的HTML裏分離開來。而JSP的情況是Java和HTML可以組合成一個擴展名爲.jsp的文件。

 

        JSP側重於視圖,Servlet主要用於控制邏輯。在struts框架中,JSP位於MVC設計模式的視圖層,而Servlet位於控制層.

 

 

 

60,tomcat容器是如何創建servlet類實例?用到了什麼原理?

        當容器啓動時,會讀取在webapps目錄下所有的web應用中的web.xml文件,然後對xml文件進行解析,並讀取servlet註冊信息。然後,將每個應用中註冊的servlet類都進行加載,並通過反射的方式實例化。(有時候也是在第一次請求時實例化)

        在servlet註冊時加上<load-on-startup>1</load-on-startup>如果爲正數,則在一開始就實例化,如果不寫或爲負數,則第一次請求實例化。

 

61,JDBC訪問數據庫的基本步驟是什麼?

1,加載驅動

2,通過DriverManager對象獲取連接對象Connection

3,通過連接對象獲取會話

4,通過會話進行數據的增刪改查,封裝對象

5,關閉資源

 

 

 

62,說說preparedStatement和Statement的區別

1,效率:預編譯會話比普通會話對象,數據庫系統不會對相同的sql語句不會再次編譯

2,安全性:可以有效的避免sql注入攻擊!sql注入攻擊就是從客戶端輸入一些非法的特殊字符,而使服務器端在構造sql語句的時候仍然能夠正確構造,從而收集程序和服務器的信息和數據。

比如:“select * from t_user where userName = ‘” + userName + “ ’ and password =’” + password + “’”

如果用戶名和密碼輸入的是’1’ or ‘1’=’1’ ;  則生產的sql語句是:

“select * from t_user where userName = ‘1’ or ‘1’ =’1’  and password =’1’  or ‘1’=’1’  這個語句中的where 部分沒有起到對數據篩選的作用。

 

 

 

63,說說事務的概念,在JDBC編程中處理事務的步驟。

1 事務是作爲單個邏輯工作單元執行的一系列操作。

2,一個邏輯工作單元必須有四個屬性,稱爲原子性、一致性、隔離性和持久性 (ACID) 屬性,只有這樣才能成爲一個事務

事務處理步驟:

3,conn.setAutoComit(false);設置提交方式爲手工提交

4,conn.commit()提交事務

5,出現異常,回滾 conn.rollback();

 

 

 

64,數據庫連接池的原理。爲什麼要使用連接池。

1,數據庫連接是一件費時的操作,連接池可以使多個操作共享一個連接。

2,數據庫連接池的基本思想就是爲數據庫連接建立一個“緩衝池”。預先在緩衝池中放入一定數量的連接,當需要建立數據庫連接時,只需從“緩衝池”中取出一個,使用完畢之後再放回去。我們可以通過設定連接池最大連接數來防止系統無盡的與數據庫連接。更爲重要的是我們可以通過連接池的管理機制監視數據庫的連接的數量、使用情況,爲系統開發,測試及性能調整提供依據。

3,使用連接池是爲了提高對數據庫連接資源的管理

 

 

 

65,JDBC的髒讀是什麼?哪種數據庫隔離級別能防止髒讀?

  當我們使用事務時,有可能會出現這樣的情況,有一行數據剛更新,與此同時另一個查詢讀到了這個剛更新的值。這樣就導致了髒讀,因爲更新的數據還沒有進行持久化,更新這行數據的業務可能會進行回滾,這樣這個數據就是無效的。數據庫的TRANSACTIONREADCOMMITTED,TRANSACTIONREPEATABLEREAD,和TRANSACTION_SERIALIZABLE隔離級別可以防止髒讀。

 

 

 

66,什麼是幻讀,哪種隔離級別可以防止幻讀?

  幻讀是指一個事務多次執行一條查詢返回的卻是不同的值。假設一個事務正根據某個條件進行數據查詢,然後另一個事務插入了一行滿足這個查詢條件的數據。之後這個事務再次執行了這條查詢,返回的結果集中會包含剛插入的那條新數據。這行新數據被稱爲幻行,而這種現象就叫做幻讀。

 

  只有TRANSACTION_SERIALIZABLE隔離級別才能防止產生幻讀。

 

 

 

67,JDBC的DriverManager是用來做什麼的?

JDBC的DriverManager是一個工廠類,我們通過它來創建數據庫連接。當JDBC的Driver類被加載進來時,它會自己註冊到DriverManager類裏面

然後我們會把數據庫配置信息傳成DriverManager.getConnection()方法,DriverManager會使用註冊到它裏面的驅動來獲取數據庫連接,並返回給調用的程序。

 

 

 

68,execute,executeQuery,executeUpdate的區別是什麼?

        1,Statement的execute(String query)方法用來執行任意的SQL查詢,如果查詢的結果是一個ResultSet,這個方法就返回true。如果結果不是ResultSet,比如insert或者update查詢,它就會返回false。我們可以通過它的getResultSet方法來獲取ResultSet,或者通過getUpdateCount()方法來獲取更新的記錄條數。

        2,Statement的executeQuery(String query)接口用來執行select查詢,並且返回ResultSet。即使查詢不到記錄返回的ResultSet也不會爲null。我們通常使用executeQuery來執行查詢語句,這樣的話如果傳進來的是insert或者update語句的話,它會拋出錯誤信息爲 “executeQuery method can not be used for update”的java.util.SQLException。 ,

        3,Statement的executeUpdate(String query)方法用來執行insert或者update/delete(DML)語句,或者 什麼也不返回,對於DDL語句,返回值是int類型,如果是DML語句的話,它就是更新的條數,如果是DDL的話,就返回0。

只有當你不確定是什麼語句的時候才應該使用execute()方法,否則應該使用executeQuery或者executeUpdate方法。

 

 

 

69,SQL查詢出來的結果分頁展示一般怎麼做?

 

Oracle:

 

select * from

(select *,rownum as tempid from student )  t

where t.tempid between ” + pageSize*(pageNumber-1) + ” and ” + pageSize*pageNumber

 

MySQL:

   select * from students limit ” + pageSize*(pageNumber-1) + “,” + pageSize;

 

sql server:

   select top ” + pageSize + ” * from students where id not in +

(select top ” + pageSize * (pageNumber-1) +  id from students order by id) +  

“order by id;

 

 

 

70,JDBC的ResultSet是什麼?

在查詢數據庫後會返回一個ResultSet,它就像是查詢結果集的一張數據表。

ResultSet對象維護了一個遊標,指向當前的數據行。開始的時候這個遊標指向的是第一行。如果調用了ResultSet的next()方法遊標會下移一行,如果沒有更多的數據了,next()方法會返回false。可以在for循環中用它來遍歷數據集。

默認的ResultSet是不能更新的,遊標也只能往下移。也就是說你只能從第一行到最後一行遍歷一遍。不過也可以創建可以回滾或者可更新的ResultSet

 

當生成ResultSet的Statement對象要關閉或者重新執行或是獲取下一個ResultSet的時候,ResultSet對象也會自動關閉。

可以通過ResultSet的getter方法,傳入列名或者從1開始的序號來獲取列數據。

71,談談你對Struts的理解。

 

        1. struts是一個按MVC模式設計的Web層框架,其實它就是一個Servlet,這個Servlet名爲ActionServlet,或是ActionServlet的子類。我們可以在web.xml文件中將符合某種特徵的所有請求交給這個Servlet處理,這個Servlet再參照一個配置文件將各個請求分別分配給不同的action去處理。

 

(struts的配置文件可以有多個,可以按模塊配置各自的配置文件,這樣可以防止配置文件的過度膨脹)

 

        2.ActionServlet把請求交給action去處理之前,會將請求參數封裝成一個formbean對象(就是一個java類,這個類中的每個屬性對應一個請求參數),

 

        3.要說明的是, ActionServlet把formbean對象傳遞給action的execute方法之前,可能會調用formbean的validate方法進行校驗,只有校驗通過後纔將這個formbean對象傳遞給action的execute方法,否則,它將返回一個錯誤頁面,這個錯誤頁面由input屬性指定。

 

        4.action執行完後要返回顯示的結果視圖,這個結果視圖是用一個ActionForward對象來表示的,actionForward對象通過struts-config.xml配置文件中的配置關聯到某個jsp頁面,因爲程序中使用的是在struts-config.xml配置文件爲jsp頁面設置的邏輯名,這樣可以實現action程序代碼與返回的jsp頁面名稱的解耦。

 

 (以上,也可以結合自己使用感受談自己的看法)

 

 

 

72、談談你對Hibernate的理解。

 

        1. 面向對象設計的軟件內部運行過程可以理解成就是在不斷創建各種新對象、建立對象之間的關係,調用對象的方法來改變各個對象的狀態和對象消亡的過程,不管程序運行的過程和操作怎麼樣,本質上都是要得到一個結果,程序上一個時刻和下一個時刻的運行結果的差異就表現在內存中的對象狀態發生了變化。

 

        2.爲了在關機和內存空間不夠的狀況下,保持程序的運行狀態,需要將內存中的對象狀態保存到持久化設備和從持久化設備中恢復出對象的狀態,通常都是保存到關係數據庫來保存大量對象信息。從Java程序的運行功能上來講,保存對象狀態的功能相比系統運行的其他功能來說,應該是一個很不起眼的附屬功能,java採用jdbc來實現這個功能,這個不起眼的功能卻要編寫大量的代碼,而做的事情僅僅是保存對象和恢復對象,並且那些大量的jdbc代碼並沒有什麼技術含量,基本上是採用一套例行公事的標準代碼模板來編寫,是一種苦活和重複性的工作。

 

        3.通過數據庫保存java程序運行時產生的對象和恢復對象,其實就是實現了java對象與關係數據庫記錄的映射關係,稱爲ORM(即Object RelationMapping),人們可以通過封裝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查詢。

 

(以上,也可以結合自己使用JDBC時的繁瑣談hibernate的感受)

 

 

 

73,談談你對Spring的理解。

 

        1.Spring是實現了工廠模式的工廠類(在這裏有必要解釋清楚什麼是工廠模式),這個類名爲BeanFactory(實際上是一個接口),在程序中通常BeanFactory的子類ApplicationContext。Spring相當於一個大的工廠類,在其配置文件中通過<bean>元素配置用於創建實例對象的類名和實例對象的屬性。

 

        2. Spring提供了對IOC良好支持,IOC是一種編程思想,是一種架構藝術,利用這種思想可以很好地實現模塊之間的解耦,IOC也稱爲DI(Depency Injection)。

 

        3. Spring提供了對AOP技術的良好封裝, AOP稱爲面向切面編程,就是系統中有很多各不相干的類的方法,在這些衆多方法中要加入某種系統功能的代碼,例如,加入日誌,加入權限判斷,加入異常處理,這種應用稱爲AOP。

 

        實現AOP功能採用的是代理技術,客戶端程序不再調用目標,而調用代理類,代理類與目標類對外具有相同的方法聲明,有兩種方式可以實現相同的方法聲明,一是實現相同的接口,二是作爲目標的子類。

 

        在JDK中採用Proxy類產生動態代理的方式爲某個接口生成實現類,如果要爲某個類生成子類,則可以用CGLI B。在生成的代理類的方法中加入系統功能和調用目標類的相應方法,系統功能的代理以Advice對象進行提供,顯然要創建出代理對象,至少需要目標類和Advice類。spring提供了這種支持,只需要在spring配置文件中配置這兩個元素即可實現代理和aop功能。

 

(以上,也可以結合自己使用感受談自己的看法)

 

 

 

74,談談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相比是一種粗粒度的事件

 

 

 

75,iBatis與Hibernate有什麼不同?

 

        相同點:屏蔽jdbc api的底層訪問細節,使用我們不用與jdbc api打交道,就可以訪問數據。

 

        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語句。

 

76,在hibernate進行多表查詢每個表中各取幾個字段,也就是說查詢出來的結果集沒有一個實體類與之對應如何解決?

 

解決方案一,:按照Object[]數據取出數據,然後自己組bean

 

解決方案二:對每個表的bean寫構造函數,比如表一要查出field1,field2兩個字段,那麼有一個構造函數就是Bean(type1filed1,type2

 

field2) ,然後在hql裏面就可以直接生成這個bean了。

 

 

 

77,介紹一下Hibernate的二級緩存

 

        按照以下思路來回答:

 

        (1)首先說清楚什麼是緩存

 

        (2)再說有了hibernate的Session就是一級緩存,即有了一級緩存,爲什麼還要有二級緩存

 

        (3)最後再說如何配置Hibernate的二級緩存。

 

    1,緩存就是把以前從數據庫中查詢出來和使用過的對象保存在內存中(一個數據結構中),這個數據結構通常是或類似HashMap,當以後要使用某個對象時,先查詢緩存中是否有這個對象,如果有則使用緩存中的對象,如果沒有則去查詢數據庫,並將查詢出來的對象保存在緩存中,以便下次使用。

 

    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來更改當前數據庫中的數據,這樣緩存的數據就會與數據庫中的實際數據不一致。

 

 

 

78,JDO是什麼?

 

        JDO是Java對象持久化的新的規範,爲java data object的簡稱,也是一個用於存取某種數據倉庫中的對象的標準化API。JDO提供了透明的對象存儲,因此對開發人員來說,存儲數據對象完全不需要額外的代碼(如JDBC API的使用)。這些繁瑣的例行工作已經轉移到JDO產品提供商身上,使開發人員解脫出來,從而集中時間和精力在業務邏輯上。另外,JDO很靈活,因爲它可以在任何數據底層上運行。

 

        比較:JDBC只是面向關係數據庫(RDBMS)JDO更通用,提供到任何數據底層的存儲功能,比如關係數據庫、文件、XML以及對象數據庫(ODBMS)等等,使得應用可移植性更強。

 

 

 

79,Hibernate的一對多和多對一雙向關聯的區別??

 

        一對多關聯映射和多對一關聯映射實現的基本原理都是一樣的,既是在多的一端加入一個外鍵指向一的一端外鍵,而主要的區別就是維護端不同。

        它們的區別在於維護的關係不同:

一對多關聯映射是指在加載一的一端數據的同時加載多的一端的數據多對一關聯映射是指在加載多的一端數據的同時加載一的一端的數據。

 

 

 

80,Hibernate是如何延遲加載? 

 

       1. Hibernate2延遲加載實現:a)實體對象 b)集合(Collection)

 

        2. Hibernate3 提供了屬性的延遲加載功能 當Hibernate在查詢數據的時候,數據並沒有存在與內存中,當程序真正對數據的操作時,對象才存在與內存中,就實現了延遲加載,他節省了服務器的內存開銷,從而提高了服務器的性能。

81,使用Spring框架的好處是什麼?

 

        輕量:Spring 是輕量的,基本的版本大約2MB。

 

        控制反轉:Spring通過控制反轉實現了鬆散耦合,對象們給出它們的依賴,而不是創建或查找依賴的對象們。

 

        面向切面的編程(AOP):Spring支持面向切面的編程,並且把應用業務邏輯和系統服務分開。

 

        容器:Spring 包含並管理應用中對象的生命週期和配置。

 

        MVC框架:Spring的WEB框架是個精心設計的框架,是Web框架的一個很好的替代品。

 

        事務管理:Spring 提供一個持續的事務管理接口,可以擴展到上至本地事務下至全局事務(JTA)。

 

        異常處理:Spring 提供方便的API把具體技術相關的異常(比如由JDBC,Hibernate or JDO拋出的)轉化爲一致的unchecked 異常。

 

 

 

82. ApplicationContext通常的實現是什麼?

        FileSystemXmlApplicationContext :此容器從一個XML文件中加載beans的定義,XML Bean 配置文件的全路徑名必須提供給它的構造函數。

 

        ClassPathXmlApplicationContext:此容器也從一個XML文件中加載beans的定義,這裏,你需要正確設置classpath因爲這個容器將在classpath裏找bean配置。

 

        WebXmlApplicationContext:此容器加載一個XML文件,此文件定義了一個WEB應用的所有bean。

 

 

 

83,什麼是Spring的依賴注入?有哪些方法進行依賴注入

        依賴注入,是IOC的一個方面,是個通常的概念,它有多種解釋。這概念是說你不用創建對象,而只需要描述它如何被創建。你不在代碼裏直接組裝你的組件和服務,但是要在配置文件裏描述哪些組件需要哪些服務,之後一個容器(IOC容器)負責把他們組裝起來。

 

        構造器依賴注入:構造器依賴注入通過容器觸發一個類的構造器來實現的,該類有一系列參數,每個參數代表一個對其他類的依賴。

 

        Setter方法注入:Setter方法注入是容器通過調用無參構造器或無參static工廠 方法實例化bean之後,調用該bean的setter方法,即實現了基於setter的依賴注入。

 

 

 

84,什麼是Spring beans?

        Spring beans 是那些形成Spring應用的主幹的java對象。它們被Spring IOC容器初始化,裝配,和管理。這些beans通過容器中配置的元數據創建。比如,以XML文件中<bean/> 的形式定義。

 

        Spring 框架定義的beans都是單件beans。在bean tag中有個屬性”singleton”,如果它被賦爲TRUE,bean 就是單件,否則就是一個 prototype bean。默認是TRUE,所以所有在Spring框架中的beans 缺省都是單件。

 

 

 

85,解釋Spring支持的幾種bean的作用域。

 

        Spring框架支持以下五種bean的作用域:

 

        singleton : bean在每個Spring ioc 容器中只有一個實例。

 

        prototype:一個bean的定義可以有多個實例。

 

        request:每次http請求都會創建一個bean,該作用域僅在基於web的        Spring ApplicationContext情形下有效。

 

        session:在一個HTTP Session中,一個bean定義對應一個實例。該作用域僅在基於web的Spring ApplicationContext情形下有效。

 

        global-session:在一個全局的HTTP Session中,一個bean定義對應一個實例。該作用域僅在基於web的Spring ApplicationContext情形下有效。

 

缺省的Spring bean 的作用域是Singleton.

 

 

 

86,解釋Spring框架中bean的生命週期。

 

        1,Spring容器 從XML 文件中讀取bean的定義,並實例化bean。

 

        2,Spring根據bean的定義填充所有的屬性。

 

        3,如果bean實現了BeanNameAware 接口,Spring 傳遞bean 的ID 到 setBeanName方法。

 

        4,如果Bean 實現了 BeanFactoryAware 接口, Spring傳遞beanfactory 給setBeanFactory 方法。

 

        5,如果有任何與bean相關聯的BeanPostProcessors,Spring會在postProcesserBeforeInitialization()方法內調用它們。

 

        6,如果bean實現IntializingBean了,調用它的afterPropertySet方法,如果bean聲明瞭初始化方法,調用此初始化方法。

 

        7,如果有BeanPostProcessors 和bean 關聯,這些bean的postProcessAfterInitialization() 方法將被調用。

 

       8,如果bean實現了 DisposableBean,它將調用destroy()方法。

 

 

 

87,在 Spring中如何注入一個java集合?

Spring提供以下幾種集合的配置元素:

 

    <list>類型用於注入一列值,允許有相同的值。

 

    <set> 類型用於注入一組值,不允許有相同的值。

 

    <map> 類型用於注入一組鍵值對,鍵和值都可以爲任意類型。

 

    <props>類型用於注入一組鍵值對,鍵和值都只能爲String類型。

 

 

 

88,解釋不同方式的自動裝配 。

有五種自動裝配的方式,用來指導Spring容器用自動裝配方式進行依賴注入。

 

        no:默認的方式是不進行自動裝配,通過顯式設置ref 屬性來進行裝配。

 

        byName:通過參數名 自動裝配,Spring容器在配置文件中發現bean的autowire屬性被設置成byname,之後容器試圖匹配、裝配和該bean的屬性具有相同名字的bean。

 

        byType::通過參數類型自動裝配,Spring容器在配置文件中發現bean的autowire屬性被設置成byType,之後容器試圖匹配、裝配和該bean的屬性具有相同類型的bean。如果有多個bean符合條件,則拋出錯誤。

 

        constructor:這個方式類似於byType, 但是要提供給構造器參數,如果沒有確定的帶參數的構造器參數類型,將會拋出異常。

 

        autodetect:首先嚐試使用constructor來自動裝配,如果無法工作,則使用byType方式。

 

 

 

89,Spring框架的事務管理有哪些優點?

        它爲不同的事務API  如 JTA,JDBC,Hibernate,JPA 和JDO,提供一個不變的編程模式。

 

        它爲編程式事務管理提供了一套簡單的API而不是一些複雜的事務API如

 

        它支持聲明式事務管理。

 

        它和Spring各種數據訪問抽象層很好得集成。

 

 

 

90.什麼是基於Java的Spring註解配置? 給一些註解的例子.

        基於Java的配置,允許你在少量的Java註解的幫助下,進行你的大部分Spring配置而非通過XML文件。

 

        以@Configuration 註解爲例,它用來標記類可以當做一個bean的定義,被Spring IOC容器使用。另一個例子是@Bean註解,它表示此方法將要返回一個對象,作爲一個bean註冊進Spring應用上下文。

91,什麼是ORM?

        對象關係映射(Object-Relational Mapping,簡稱ORM)是一種爲了解決程序的面向對象模型與數據庫的關係模型互不匹配問題的技術;

 

        簡單的說,ORM是通過使用描述對象和數據庫之間映射的元數據(在Java中可以用XML或者是註解),將程序中的對象自動持久化到關係數據庫中或者將關係數據庫表中的行轉換成Java對象,其本質上就是將數據從一種形式轉換到另外一種形式。

 

 

 

92,Hibernate中SessionFactory是線程安全的嗎?Session是線程安全的嗎(兩個線程能夠共享同一個Session嗎)?

        SessionFactory對應Hibernate的一個數據存儲的概念,它是線程安全的,可以被多個線程併發訪問。SessionFactory一般只會在啓動的時候構建。對於應用程序,最好將SessionFactory通過單例模式進行封裝以便於訪問。

 

        Session是一個輕量級非線程安全的對象(線程間不能共享session),它表示與數據庫進行交互的一個工作單元。Session是由SessionFactory創建的,在任務完成之後它會被關閉。Session是持久層服務對外提供的主要接口。

 

        Session會延遲獲取數據庫連接(也就是在需要的時候纔會獲取)。爲了避免創建太多的session,可以使用ThreadLocal將session和當前線程綁定在一起,這樣可以讓同一個線程獲得的總是同一個session。Hibernate 3中SessionFactory的getCurrentSession()方法就可以做到。

 

 

 

93,Session的save()、update()、merge()、lock()、saveOrUpdate()和persist()方法分別是做什麼的?有什麼區別?

        Hibernate的對象有三種狀態:瞬時態(transient)、持久態(persistent)和遊離態(detached)。

 

        瞬時態的實例可以通過調用save()、persist()或者saveOrUpdate()方法變成持久態;

 

        遊離態的實例可以通過調用 update()、saveOrUpdate()、lock()或者replicate()變成持久態。save()和persist()將會引發SQL的INSERT語句,而update()或merge()會引發UPDATE語句。

 

        save()和update()的區別在於一個是將瞬時態對象變成持久態,一個是將遊離態對象變爲持久態。merge()方法可以完成save()和update()方法的功能,它的意圖是將新的狀態合併到已有的持久化對象上或創建新的持久化對象。

 

        對於persist()方法,按照官方文檔的說明:

 

        1、persist()方法把一個瞬時態的實例持久化,但是並不保證標識符被立刻填入到持久化實例中,標識符的填入可能被推遲到flush的時間;

 

        2、persist()方法保證當它在一個事務外部被調用的時候並不觸發一個INSERT語句,當需要封裝一個長會話流程的時候,persist()方法是很有必要的;

 

        3、save()方法不保證第2條,它要返回標識符,所以它會立即執行INSERT語句,不管是在事務內部還是外部。至於lock()方法和update()方法的區別,update()方法是把一個已經更改過的脫管狀態的對象變成持久狀態;lock()方法是把一個沒有更改過的脫管狀態的對象變成持久狀態。

 

 

 

94,闡述Session加載實體對象的過程。

        1、Session在調用數據庫查詢功能之前,首先會在一級緩存中通過實體類型和主鍵進行查找,如果一級緩存查找命中且數據狀態合法,則直接返回;

        2、如果一級緩存沒有命中,接下來Session會在當前NonExists記錄(相當於一個查詢黑名單,如果出現重複的無效查詢可以迅速做出判斷,從而提升性能)中進行查找,如果NonExists中存在同樣的查詢條件,則返回null;

        3、如果一級緩存查詢失敗查詢二級緩存,如果二級緩存命中直接返回;

        4、如果之前的查詢都未命中,則發出SQL語句,如果查詢未發現對應記錄則將此次查詢添加到Session的NonExists中加以記錄,並返回null;

        5、根據映射配置和SQL語句得到ResultSet,並創建對應的實體對象;

        6、將對象納入Session(一級緩存)的管理;

        7、如果有對應的攔截器,則執行攔截器的onLoad方法;

        8、如果開啓並設置了要使用二級緩存,則將數據對象納入二級緩存;

        9、返回數據對象。

 

 

 

95,MyBatis中使用#和$書寫佔位符有什麼區別?

        #將傳入的數據都當成一個字符串,會對傳入的數據自動加上引號;

 

    $將傳入的數據直接顯示生成在SQL中。

 

        注意:使用$佔位符可能會導致SQL注射攻擊,能用#的地方就不要使用$,寫order by子句的時候應該用$而不是#。

 

 

 

96,解釋一下MyBatis中命名空間(namespace)的作用。

        在大型項目中,可能存在大量的SQL語句,這時候爲每個SQL語句起一個唯一的標識(ID)就變得並不容易了。爲了解決這個問題,在MyBatis中,可以爲每個映射文件起一個唯一的命名空間,這樣定義在這個映射文件中的每個SQL語句就成了定義在這個命名空間中的一個ID。只要我們能夠保證每個命名空間中這個ID是唯一的,即使在不同映射文件中的語句ID相同,也不會再產生衝突了。

 

 

 

97、MyBatis中的動態SQL是什麼意思?

        對於一些複雜的查詢,我們可能會指定多個查詢條件,但是這些條件可能存在也可能不存在,如果不使用持久層框架我們可能需要自己拼裝SQL語句,不過MyBatis提供了動態SQL的功能來解決這個問題。MyBatis中用於實現動態SQL的元素主要有:

- if    - choose / when / otherwise    - trim    - where    - set     - foreach

 

用法舉例:

 

   <select id="foo" parameterType="Blog" resultType="Blog">        

   select * from t_blog where 1 = 1

        <if test="title != null">            

           and title = #{title}

        </if>

        <if test="content != null">            

           and content = #{content}

        </if>

        <if test="owner != null">            

           and owner = #{owner}

        </if>

   </select>

 

98,JDBC編程有哪些不足之處,MyBatis是如何解決這些問題的?

        1、JDBC:數據庫鏈接創建、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用數據庫鏈接池可解決此問題。

 

        MyBatis:在SqlMapConfig.xml中配置數據鏈接池,使用連接池管理數據庫鏈接。

 

        2、JDBC:Sql語句寫在代碼中造成代碼不易維護,實際應用sql變化的可能較大,sql變動需要改變java代碼。

 

        MyBatis:將Sql語句配置在XXXXmapper.xml文件中與java代碼分離。

        3、JDBC:向sql語句傳參數麻煩,因爲sql語句的where條件不一定,可能多也可能少,佔位符需要和參數一一對應。

 

        MyBatis: Mybatis自動將java對象映射至sql語句。

        4,JDBC:對結果集解析麻煩,sql變化導致解析代碼變化,且解析前需要遍歷,如果能將數據庫記錄封裝成pojo對象解析比較方便。

 

        MyBatis:Mybatis自動將sql執行結果映射至java對象。

 

 

 

99,MyBatis與Hibernate有哪些不同?

        1、Mybatis和hibernate不同,它不完全是一個ORM框架,因爲MyBatis需要程序員自己編寫Sql語句,不過mybatis可以通過XML或註解方式靈活配置要運行的sql語句,並將java對象和sql語句映射生成最終執行的sql,最後將sql執行的結果再映射生成java對象。           

        2、Mybatis學習門檻低,簡單易學,程序員直接編寫原生態sql,可嚴格控制sql執行性能,靈活度高,非常適合對關係數據模型要求不高的軟件開發,例如互聯網軟件、企業運營類軟件等,因爲這類軟件需求變化頻繁,一但需求變化要求成果輸出迅速。但是靈活的前提是mybatis無法做到數據庫無關性,如果需要實現支持多種數據庫的軟件則需要自定義多套sql映射文件,工作量大。                3、Hibernate對象/關係映射能力強,數據庫無關性好,對於關係模型要求高的軟件(例如需求固定的定製化軟件)如果用hibernate開發可以節省很多代碼,提高效率。但是Hibernate的缺點是學習門檻高,要精通門檻更高,而且怎麼設計O/R映射,在性能和對象模型之間如何權衡,以及怎樣用好Hibernate需要具有很強的經驗和能力才行。           

        總之,按照用戶的需求在有限的資源環境下只要能做出維護性、擴展性良好的軟件架構都是好架構,所以框架只有適合纔是最好。

 

(這裏也可以結合自己的理解說,別說的收不住)

 

 

 

 

100,簡單的說一下MyBatis的一級緩存和二級緩存?

        Mybatis首先去緩存中查詢結果集,如果沒有則查詢數據庫,如果有則從緩存取出返回結果集就不走數據庫。Mybatis內部存儲緩存使用一個HashMap,key爲hashCode+sqlId+Sql語句。value爲從查詢出來映射生成的java對象

        Mybatis的二級緩存即查詢緩存,它的作用域是一個mapper的namespace,即在同一個namespace中查詢sql可以從緩存中獲取數據。二級緩存是可以跨SqlSession的。

 

Java面試題-數據庫篇十一

 

基本表結構:

 

        student(sno,sname,sage,ssex)學生表

        course(cno,cname,tno) 課程表

        sc(sno,cno,score) 成績表

 

        teacher(tno,tname) 教師表

 

 

 

101,查詢課程1的成績比課程2的成績高的所有學生的學號

select a.sno from

(select sno,score from sc where cno=1) a,

(select sno,score from sc where cno=2) b

where a.score>b.score and a.sno=b.sno

 

 

 

102,查詢平均成績大於60分的同學的學號和平均成績

select a.sno as "學號", avg(a.score) as "平均成績"

from

(select sno,score from sc) a

group by sno having avg(a.score)>60

 

 

 

103,查詢所有同學的學號、姓名、選課數、總成績

select a.sno as 學號, b.sname as 姓名,

count(a.cno) as 選課數, sum(a.score) as 總成績

from sc a, student b

where a.sno = b.sno

group by a.sno, b.sname

 

或者:

 

selectstudent.sno as 學號, student.sname as 姓名,

 count(sc.cno) as 選課數, sum(score) as 總成績

from student left Outer join sc on student.sno = sc.sno

group by student.sno, sname

 

104,查詢姓“張”的老師的個數

 

selectcount(distinct(tname)) from teacher where tname like '張%‘

或者:

select tname as "姓名", count(distinct(tname)) as "人數"

from teacher

where tname like'張%'

group by tname

 

 

 

105,查詢沒學過“張三”老師課的同學的學號、姓名

select student.sno,student.sname from student

where sno not in (select distinct(sc.sno) from sc,course,teacher

where sc.cno=course.cno and teacher.tno=course.tno and teacher.tname='張三')

 

 

 

106,查詢同時學過課程1和課程2的同學的學號、姓名

select sno, sname from student

where sno in (select sno from sc where sc.cno = 1)

and sno in (select sno from sc where sc.cno = 2)

或者:

 

selectc.sno, c.sname from

(select sno from sc where sc.cno = 1) a,

(select sno from sc where sc.cno = 2) b,

student c

where a.sno = b.sno and a.sno = c.sno

或者:

 

select student.sno,student.sname from student,sc where student.sno=sc.sno and sc.cno=1

and exists( select * from sc as sc_2 where sc_2.sno=sc.sno and sc_2.cno=2)

 

 

 

107,查詢學過“李四”老師所教所有課程的所有同學的學號、姓名

select a.sno, a.sname from student a, sc b

where a.sno = b.sno and b.cno in

(select c.cno from course c, teacher d where c.tno = d.tno and d.tname = '李四')

 

或者:

 

select a.sno, a.sname from student a, sc b,

(select c.cno from course c, teacher d where c.tno = d.tno and d.tname = '李四') e

where a.sno = b.sno and b.cno = e.cno

 

 

 

108,查詢課程編號1的成績比課程編號2的成績高的所有同學的學號、姓名

select a.sno, a.sname from student a,

(select sno, score from sc where cno = 1) b,

(select sno, score from sc where cno = 2) c

where b.score > c.score and b.sno = c.sno and a.sno = b.sno

 

 

 

109,查詢所有課程成績小於60分的同學的學號、姓名

select sno,sname from student

where sno not in (select distinct sno from sc where score > 60)

 

 

 

110,查詢至少有一門課程與學號爲1的同學所學課程相同的同學的學號和姓名

select distinct a.sno, a.sname

from student a, sc b

where a.sno <> 1 and a.sno=b.sno and

b.cno in (select cno from sc where sno = 1)

 

或者:

 

select s.sno,s.sname

from student s,

(select sc.sno

from sc

where sc.cno in (select sc1.cno from sc sc1 where sc1.sno=1)and sc.sno<>1

group by sc.sno)r1

where r1.sno=s.sno

基本表結構:

 

        student(sno,sname,sage,ssex)學生表

        course(cno,cname,tno) 課程表

        sc(sno,cno,score) 成績表

 

        teacher(tno,tname) 教師表

 

 

 

111、把“sc”表中“王五”所教課的成績都更改爲此課程的平均成績

update sc set score = (select avg(sc_2.score) from sc sc_2 wheresc_2.cno=sc.cno)

from course,teacher where course.cno=sc.cno and course.tno=teacher.tno andteacher.tname='王五'

 

 

112、查詢和編號爲2的同學學習的課程完全相同的其他同學學號和姓名

這一題分兩步查:

 

1,

 

select sno

from sc

where sno <> 2

group by sno

having sum(cno) = (select sum(cno) from sc where sno = 2)

 

2,

select b.sno, b.sname

from sc a, student b

where b.sno <> 2 and a.sno = b.sno

group by b.sno, b.sname

having sum(cno) = (select sum(cno) from sc where sno = 2)

 

113、刪除學習“王五”老師課的sc表記錄

delete sc from course, teacher

where course.cno = sc.cno and course.tno = teacher.tno and tname = '王五'

 

114、向sc表中插入一些記錄,這些記錄要求符合以下條件

將沒有課程3成績同學的該成績補齊, 其成績取所有學生的課程2的平均成績

insert sc select sno, 3, (select avg(score) from sc where cno = 2)

from student

where sno not in (select sno from sc where cno = 3)

 

115、按平平均分從高到低顯示所有學生的如下統計報表:

-- 學號,企業管理,馬克思,UML,數據庫,物理,課程數,平均分

select sno as 學號

,max(case when cno = 1 then score end) AS 企業管理

,max(case when cno = 2 then score end) AS 馬克思

,max(case when cno = 3 then score end) AS UML

,max(case when cno = 4 then score end) AS 數據庫

,max(case when cno = 5 then score end) AS 物理

,count(cno) AS 課程數

,avg(score) AS 平均分

FROM sc

GROUP by sno

ORDER by avg(score) DESC

 

116、查詢各科成績最高分和最低分:

 

以如下形式顯示:課程號,最高分,最低分

select cno as 課程號, max(score) as 最高分, min(score) 最低分

from sc group by cno

 

select  course.cno as '課程號'

,MAX(score) as '最高分'

,MIN(score) as '最低分'

from sc,course

where sc.cno=course.cno

group by course.cno

 

117、按各科平均成績從低到高和及格率的百分數從高到低順序

SELECT t.cno AS 課程號,

max(course.cname)AS 課程名,

isnull(AVG(score),0) AS 平均成績,

100 * SUM(CASE WHEN isnull(score,0)>=60 THEN 1 ELSE 0 END)/count(1) AS 及格率

FROM sc t, course

where t.cno = course.cno

GROUP BY t.cno

ORDER BY 及格率 desc

 

118、查詢如下課程平均成績和及格率的百分數(用"1行"顯示):

 

企業管理(001),馬克思(002),UML (003),數據庫(004)

select

avg(case when cno = 1 then score end) as 平均分1,

avg(case when cno = 2 then score end) as 平均分2,

avg(case when cno = 3 then score end) as 平均分3,

avg(case when cno = 4 then score end) as 平均分4,

100 * sum(case when cno = 1 and score > 60 then 1 else 0 end) / sum(casewhen cno = 1 then 1 else 0 end) as 及格率1,

100 * sum(case when cno = 2 and score > 60 then 1 else 0 end) / sum(casewhen cno = 2 then 1 else 0 end) as 及格率2,

100 * sum(case when cno = 3 and score > 60 then 1 else 0 end) / sum(casewhen cno = 3 then 1 else 0 end) as 及格率3,

100 * sum(case when cno = 4 and score > 60 then 1 else 0 end) / sum(casewhen cno = 4 then 1 else 0 end) as 及格率4

from sc

 

119、查詢不同老師所教不同課程平均分, 從高到低顯示

select max(c.tname) as 教師, max(b.cname) 課程, avg(a.score) 平均分

from sc a, course b, teacher c

where a.cno = b.cno and b.tno = c.tno

group by a.cno

order by 平均分 desc

或者:

select r.tname as '教師',r.rname as '課程' , AVG(score) as '平均分'

from sc,

(select  t.tname,c.cno as rcso,c.cname as rname

from teacher t ,course c

where t.tno=c.tno)r

where sc.cno=r.rcso

group by sc.cno,r.tname,r.rname

order by AVG(score) desc

 

120、查詢如下課程成績均在第3名到第6名之間的學生的成績:

-- [學生ID],[學生姓名],企業管理,馬克思,UML,數據庫,平均成績

select top 6 max(a.sno) 學號, max(b.sname) 姓名,

max(case when cno = 1 then score end) as 企業管理,

max(case when cno = 2 then score end) as 馬克思,

max(case when cno = 3 then score end) as UML,

max(case when cno = 4 then score end) as 數據庫,

avg(score) as 平均分

from sc a, student b

where a.sno not in

 

(select top 2 sno from sc where cno = 1 order by score desc)

  and a.sno not in (select top 2 sno from sc where cno = 2 order by scoredesc)

  and a.sno not in (select top 2 sno from sc where cno = 3 order by scoredesc)

  and a.sno not in (select top 2 sno from sc where cno = 4 order by scoredesc)

  and a.sno = b.sno

group by a.sno

 

 

Java面試題-多線程篇十三

 

121,什麼是線程?

        線程是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位。程序員可以通過它進行多處理器編程,你可以使用多線程對運算密集型任務提速。比如,如果一個線程完成一個任務要100毫秒,那麼用十個線程完成改任務只需10毫秒。

 

122,線程和進程有什麼區別?

 

        線程是進程的子集,一個進程可以有很多線程,每條線程並行執行不同的任務。不同的進程使用不同的內存空間,而所有的線程共享一片相同的內存空間。每個線程都擁有單獨的棧內存用來存儲本地數據

 

123,如何在Java中實現線程?

        兩種方式:java.lang.Thread 類的實例就是一個線程但是它需要調用java.lang.Runnable接口來執行,由於線程類本身就是調用的Runnable接口所以你可以繼承java.lang.Thread 類或者直接調用Runnable接口來重寫run()方法實現線程。

 

124,Java 關鍵字volatile 與 synchronized 作用與區別?

    1,volatile

    它所修飾的變量不保留拷貝,直接訪問主內存中的。

           在Java內存模型中,有main memory,每個線程也有自己的memory (例如寄存器)。爲了性能,一個線程會在自己的memory中保持要訪問的變量的副本。這樣就會出現同一個變 量在某個瞬間,在一個線程的memory中的值可能與另外一個線程memory中的值,或者main memory中的值不一致的情況。 一個變量聲明爲volatile,就意味着這個變量是隨時會被其他線程修改的,因此不能將它cache在線程memory中。

    2,synchronized

    當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多隻有一個線程執行該段代碼。

         一、當兩個併發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以後才能執行該代碼塊。

         二、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。

         三、尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。

         四、當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。

         五、以上規則對其它對象鎖同樣適用.

 

125,有哪些不同的線程生命週期?

        當我們在Java程序中新建一個線程時,它的狀態是New。當我們調用線程的start()方法時,狀態被改變爲Runnable。線程調度器會爲Runnable線程池中的線程分配CPU時間並且講它們的狀態改變爲Running。其他的線程狀態還有Waiting,Blocked 和Dead。

        

126,你對線程優先級的理解是什麼?

        每一個線程都是有優先級的,一般來說,高優先級的線程在運行時會具有優先權,但這依賴於線程調度的實現,這個實現是和操作系統相關的(OS dependent)。我們可以定義線程的優先級,但是這並不能保證高優先級的線程會在低優先級的線程前執行。線程優先級是一個int變量(從1-10),1代表最低優先級,10代表最高優先級。

 

127,什麼是死鎖(Deadlock)?如何分析和避免死鎖?

        死鎖是指兩個以上的線程永遠阻塞的情況,這種情況產生至少需要兩個以上的線程和兩個以上的資源。

        分析死鎖,我們需要查看Java應用程序的線程轉儲。我們需要找出那些狀態爲BLOCKED的線程和他們等待的資源。每個資源都有一個唯一的id,用這個id我們可以找出哪些線程已經擁有了它的對象鎖。

        避免嵌套鎖,只在需要的地方使用鎖和避免無限期等待是避免死鎖的通常辦法。

 

128,什麼是線程安全?Vector是一個線程安全類嗎?

        如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變量的值也和預期的是一樣的,就是線程安全的。一個線程安全的計數器類的同一個實例對象在被多個線程使用的情況下也不會出現計算失誤。很顯然你可以將集合類分成兩組,線程安全和非線程安全的。Vector 是用同步方法來實現線程安全的, 而和它相似的ArrayList不是線程安全的。

 

129,Java中如何停止一個線程?

 

        Java提供了很豐富的API但沒有爲停止線程提供API。JDK 1.0本來有一些像stop(), suspend() 和 resume()的控制方法但是由於潛在的死鎖威脅因此在後續的JDK版本中他們被棄用了,之後Java API的設計者就沒有提供一個兼容且線程安全的方法來停止一個線程。當run() 或者 call() 方法執行完的時候線程會自動結束,如果要手動結束一個線程,你可以用volatile 布爾變量來退出run()方法的循環或者是取消任務來中斷線程

 

130,什麼是ThreadLocal?

 

        ThreadLocal用於創建線程的本地變量,我們知道一個對象的所有線程會共享它的全局變量,所以這些變量不是線程安全的,我們可以使用同步技術。但是當我們不想使用同步的時候,我們可以選擇ThreadLocal變量。

        每個線程都會擁有他們自己的Thread變量,它們可以使用get()\set()方法去獲取他們的默認值或者在線程內部改變他們的值。ThreadLocal實例通常是希望它們同線程狀態關聯起來是private static屬性。

 

131,Sleep()、suspend()和wait()之間有什麼區別?

        Thread.sleep()使當前線程在指定的時間處於“非運行”(Not Runnable)狀態。線程一直持有對象的監視器。比如一個線程當前在一個同步塊或同步方法中,其它線程不能進入該塊或方法中。如果另一線程調用了interrupt()方法,它將喚醒那個“睡眠的”線程。

        注意:sleep()是一個靜態方法。這意味着只對當前線程有效,一個常見的錯誤是調用t.sleep(),(這裏的t是一個不同於當前線程的線程)。即便是執行t.sleep(),也是當前線程進入睡眠,而不是t線程。t.suspend()是過時的方法,使用suspend()導致線程進入停滯狀態,該線程會一直持有對象的監視器,suspend()容易引起死鎖問題。

 

        object.wait()使當前線程出於“不可運行”狀態,和sleep()不同的是wait是object的方法而不是thread。調用object.wait()時,線程先要獲取這個對象的對象鎖,當前線程必須在鎖對象保持同步,把當前線程添加到等待隊列中,隨後另一線程可以同步同一個對象鎖來調用object.notify(),這樣將喚醒原來等待中的線程,然後釋放該鎖。基本上wait()/notify()與sleep()/interrupt()類似,只是前者需要獲取對象鎖。

 

132,什麼是線程餓死,什麼是活鎖?

        當所有線程阻塞,或者由於需要的資源無效而不能處理,不存在非阻塞線程使資源可用。JavaAPI中線程活鎖可能發生在以下情形:

 

        1,當所有線程在程序中執行Object.wait(0),參數爲0的wait方法。程序將發生活鎖直到在相應的對象上有線程調用Object.notify()或者Object.notifyAll()。

 

        2,當所有線程卡在無限循環中。

 

133,什麼是Java Timer類?如何創建一個有特定時間間隔的任務?

        java.util.Timer是一個工具類,可以用於安排一個線程在未來的某個特定時間執行。Timer類可以用安排一次性任務或者週期任務。

 

        java.util.TimerTask是一個實現了Runnable接口的抽象類,我們需要去繼承這個類來創建我們自己的定時任務並使用Timer去安排它的執行。

 

134,Java中的同步集合與併發集合有什麼區別?

        同步集合與併發集合都爲多線程和併發提供了合適的線程安全的集合,不過併發集合的可擴展性更高。

        在Java1.5之前程序員們只有同步集合來用且在多線程併發的時候會導致爭用,阻礙了系統的擴展性。

        Java5介紹了併發集合像ConcurrentHashMap,不僅提供線程安全還用鎖分離和    內部分區等現代技術提高了可擴展性。

 

135,同步方法和同步塊,哪個是更好的選擇?

        同步塊是更好的選擇,因爲它不會鎖住整個對象(當然你也可以讓它鎖住整個對象)。同步方法會鎖住整個對象,哪怕這個類中有多個不相關聯的同步塊,這通常會導致他們停止執行並需要等待獲得這個對象上的鎖。

 

136,什麼是線程池? 爲什麼要使用它?

        創建線程要花費昂貴的資源和時間,如果任務來了才創建線程那麼響應時間會變長,而且一個進程能創建的線程數有限。

        爲了避免這些問題,在程序啓動的時候就創建若干線程來響應處理,它們被稱爲線程池,裏面的線程叫工作線程。

        從JDK1.5開始,Java API提供了Executor框架讓你可以創建不同的線程池。比如單線程池,每次處理一個任務;數目固定的線程池或者是緩存線程池(一個適合很多生存期短的任務的程序的可擴展線程池)。

 

137,Java中invokeAndWait 和 invokeLater有什麼區別?

        這兩個方法是Swing API 提供給Java開發者用來從當前線程而不是事件派發線程更新GUI組件用的。InvokeAndWait()同步更新GUI組件,比如一個進度條,一旦進度更新了,進度條也要做出相應改變。如果進度被多個線程跟蹤,那麼就調用invokeAndWait()方法請求事件派發線程對組件進行相應更新。而invokeLater()方法是異步調用更新組件的。

 

138,多線程中的忙循環是什麼?

        忙循環就是程序員用循環讓一個線程等待,不像傳統方法wait(), sleep() 或 yield() 它們都放棄了CPU控制,而忙循環不會放棄CPU,它就是在運行一個空循環。這麼做的目的是爲了保留CPU緩存。

        在多核系統中,一個等待線程醒來的時候可能會在另一個內核運行,這樣會重建緩存。爲了避免重建緩存和減少等待重建的時間就可以使用它了。

 

Java面試題-泛型篇十四

 

139. Java中的泛型是什麼 ? 使用泛型的好處是什麼?

        泛型是Java SE 1.5的新特性,泛型的本質是參數化類型,也就是說所操作的數據類型被指定爲一個參數。

好處:

        1、類型安全,提供編譯期間的類型檢測

        2、前後兼容

        3、泛化代碼,代碼可以更多的重複利用

        4、性能較高,用GJ(泛型JAVA)編寫的代碼可以爲java編譯器和虛擬機帶來更多的類型信息,這些信息對java程序做進一步優化提供條件。

 

140,Java的泛型是如何工作的 ? 什麼是類型擦除 ?如何工作?

 

       1、類型檢查:在生成字節碼之前提供類型檢查

        2、類型擦除:所有類型參數都用他們的限定類型替換,包括類、變量和方法(類型擦除)

        3、如果類型擦除和多態性發生了衝突時,則在子類中生成橋方法解決

        4、如果調用泛型方法的返回類型被擦除,則在調用該方法時插入強制類型轉換

類型擦除:

        所有類型參數都用他們的限定類型替換:

比如T->Object   ? extends BaseClass->BaseClass

 

如何工作:

        泛型是通過類型擦除來實現的,編譯器在編譯時擦除了所有類型相關的信息,所以在運行時不存在任何類型相關的信息。例如 List<String>在運行時僅用一個List來表示。這樣做的目的,是確保能和Java 5之前的版本開發二進制類庫進行兼容。你無法在運行時訪問到類型參數,因爲編譯器已經把泛型類型轉換成了原始類型。根據你對這個泛型問題的回答情況,你會得到一些後續提問,比如爲什麼泛型是由類型擦除來實現的或者給你展示一些會導致編譯器出錯的錯誤泛型代碼。

 

141,你可以把List<String>傳遞給一個接受List<Object>參數的方法嗎?

 

        對任何一個不太熟悉泛型的人來說,這個Java泛型題目看起來令人疑惑,因爲乍看起來String是一種Object,所以 List<String>應當可以用在需要List<Object>的地方,但是事實並非如此。真這樣做的話會導致編譯錯誤。如果你再深一步考慮,你會發現Java這樣做是有意義的,因爲List<Object>可以存儲任何類型的對象包括String, Integer等等,而List<String>卻只能用來存儲String s。

List<Object> objectList;

List<String> stringList;

objectList = stringList; //compilation error incompatible types

 

142,如何阻止Java中的類型未檢查的警告?

 

        如果你把泛型和原始類型混合起來使用,例如下列代碼,java 5的javac編譯器會產生類型未檢查的警告,例如

List<String> rawList = newArrayList()

注意: Hello.java使用了未檢查或稱爲不安全的操作;

這種警告可以使用@SuppressWarnings(“unchecked”)註解來屏蔽。

 

143,Java中List<Object>和原始類型List之間的區別?

 

        原始類型和帶參數類型<Object>之間的主要區別是,在編譯時編譯器不會對原始類型進行類型安全檢查,卻會對帶參數的類型進行檢查,通過使用Object作爲類型,可以告知編譯器該方法可以接受任何類型的對象,比如String或Integer。

        這道題的考察點在於對泛型中原始類型的正確理解。它們之間的第二點區別是,你可以把任何帶參數的類型傳遞給原始類型List,但卻不能把List<String>傳遞給接受 List<Object>的方法,因爲會產生編譯錯誤。

 

144,編寫一段泛型程序來實現LRU緩存?

        對於喜歡Java編程的人來說這相當於是一次練習。給你個提示,LinkedHashMap可以用來實現固定大小的LRU緩存,當LRU緩存已經滿了的時候,它會把最老的鍵值對移出緩存。

        LinkedHashMap提供了一個稱爲removeEldestEntry()的方法,該方法會被put() 和putAll()調用來刪除最老的鍵值對。當然,如果你已經編寫了一個可運行的JUnit測試,你也可以隨意編寫你自己的實現代碼。

 

145,Array中可以用泛型嗎?

        這可能是Java泛型面試題中最簡單的一個了,當然前提是你要知道Array事實上並不支持泛型,這也是爲什麼Joshua Bloch在Effective Java一書中建議使用List來代替Array,因爲List可以提供編譯期的類型安全保證,而Array卻不能。

 

146,如何編寫一個泛型方法,讓它能接受泛型參數並返回泛型類型?

 

        編寫泛型方法並不困難,你需要用泛型類型來替代原始類型,比如使用T, E or K,V等被廣泛認可的類型佔位符。最簡單的情況下,一個泛型方法可能會像這樣:

   public V put(K key, V value) {

   return cahe.put(key,value);

}

 

147,C++模板和java泛型之間有何不同?

 

        java泛型實現根植於“類型消除”這一概念。當源代碼被轉換爲Java虛擬機字節碼時,這種技術會消除參數化類型。有了Java泛型,我們可以做的事情也並沒有真正改變多少;他只是讓代碼變得漂亮些。鑑於此,Java泛型有時也被稱爲“語法糖”。

        這和 C++模板截然不同。在 C++中,模板本質上就是一套宏指令集,只是換了個名頭,編譯器會針對每種類型創建一份模板代碼的副本。

由於架構設計上的差異,Java泛型和C++模板有很多不同點:

   C++模板可以使用int等基本數據類型。Java則不行,必須轉而使用Integer。

    在Java中,可以將模板的參數類型限定爲某種特定類型。

    在C++中,類型參數可以實例化,但java不支持。

    在Java中,類型參數不能用於靜態方法(?)和變量,因爲它們會被不同類型參數指定的實例共享。在C++,這些類時不同的,因此類型參數可以用於靜態方法和靜態變量。

        在Java中,不管類型參數是什麼,所有的實例變量都是同一類型。類型參數會在運行時被抹去。在C++中,類型參數不同,實例變量也不同。

148,AJAX有哪些有點和缺點?

 

優點:

        1、最大的一點是頁面無刷新,用戶的體驗非常好。

        2、使用異步方式與服務器通信,具有更加迅速的響應能力。

        3、可以把以前一些服務器負擔的工作轉嫁到客戶端,利用客戶端閒置的能力來處理,減輕服務器和帶寬的負擔,節約空間和寬帶租用成本。並且減輕服務器的負擔,ajax的原則是“按需取數據”,可以最大程度的減少冗餘請求,和響應對服務器造成的負擔。

        4、基於標準化的並被廣泛支持的技術,不需要下載插件或者小程序。

缺點:

        1、ajax不支持瀏覽器back按鈕。

        2、安全問題 AJAX暴露了與服務器交互的細節。

        3、對搜索引擎的支持比較弱。

        4、破壞了程序的異常機制。

        5、不容易調試。

 

149,AJAX應用和傳統Web應用有什麼不同?

 

        在傳統的Javascript編程中,如果想得到服務器端數據庫或文件上的信息,或者發送客戶端信息到服務器,需要建立一個HTML form然後GET或者POST數據到服務器端。用戶需要點擊”Submit”按鈕來發送或者接受數據信息,然後等待服務器響應請求,頁面重新加載。

        因爲服務器每次都會返回一個新的頁面, 所以傳統的web應用有可能很慢而且用戶交互不友好。

        使用AJAX技術, 就可以使Javascript通過XMLHttpRequest對象直接與服務器進行交互。

        通過HTTP Request, 一個web頁面可以發送一個請求到web服務器並且接受web服務器返回的信息(不用重新加載頁面),展示給用戶的還是同一個頁面,用戶感覺頁面刷新,也看不到到Javascript後臺進行的發送請求和接受響應,體驗非常好。

 

150,Ajax的實現流程是怎樣的?

      (1)創建XMLHttpRequest對象,也就是創建一個異步調用對象.

      (2)創建一個新的HTTP請求,並指定該HTTP請求的方法、URL及驗證信息.

      (3)設置響應HTTP請求狀態變化的函數.

      (4)發送HTTP請求.

      (5)獲取異步調用返回的數據.

      (6)使用JavaScript和DOM實現局部刷新.

具體一點:

1,創建XNLHttpRequest對象

(不考慮ie)XMLHttpRequest request = new XMLHttprequest();

2,創建新的Http請求

XMLHttprequest.open(method,url,flag,name,password);

3,設置響應Http請求變化的函數

XMLHttprequest.onreadystatechange=getData;

function getData(){

if(XMLHttprequest.readyState==4){

獲取數據

        }

 }

4,發送http請求

XMLHttprequest.send(data);

5,獲取異步調用返回的對象

,function(data){

//異步提交後,交互成功,返回的data便是異步調用返回的對象,該對象是一個string類型的

}

6,使用js、DOM實現局部刷新

myDiv.innerHTML=''這是刷新後的數據''

 

151,簡單說一下數據庫的三範式?

 

        第一範式:數據庫表的每一個字段都是不可分割的

 

        第二範式:數據庫表中的非主屬性只依賴於主鍵

 

        第三範式:不存在非主屬性對關鍵字的傳遞函數依賴關係

 

152,Java集合框架是什麼?說出一些集合框架的優點?

 

        每種編程語言中都有集合,最初的Java版本包含幾種集合類:Vector、Stack、HashTable和Array。

 

        隨着集合的廣泛使用,Java1.2提出了囊括所有集合接口、實現和算法的集合框架。在保證線程安全的情況下使用泛型和併發集合類,Java已經經歷了很久。它還包括在Java併發包中,阻塞接口以及它們的實現。

        集合框架的部分優點如下:

(1)使用核心集合類降低開發成本,而非實現我們自己的集合類。

(2)隨着使用經過嚴格測試的集合框架類,代碼質量會得到提高。

(3)通過使用JDK附帶的集合類,可以降低代碼維護成本。

(4)複用性和可操作性。

 

153,Java集合框架的基礎接口有哪些?

 

        Collection爲集合層級的根接口。一個集合代表一組對象,這些對象即爲它的元素。Java平臺不提供這個接口任何直接的實現。

        Set是一個不能包含重複元素的集合。這個接口對數學集合抽象進行建模,被用來代表集合,就如一副牌。

        List是一個有序集合,可以包含重複元素。你可以通過它的索引來訪問任何元素。List更像長度動態變換的數組。

        Map是一個將key映射到value的對象.一個Map不能包含重複的key:每個key最多隻能映射一個value。

 一些其它的接口有Queue、Dequeue、SortedSet、SortedMap和ListIterator。

 

154,集合框架中的泛型有什麼優點?

 

        Java1.5引入了泛型,所有的集合接口和實現都大量地使用它。泛型允許我們爲集合提供一個可以容納的對象類型。

        因此,如果你添加其它類型的任何元素,它會在編譯時報錯。這避免了在運行時出現ClassCastException,因爲你將會在編譯時得到報錯信息。

        泛型也使得代碼整潔,我們不需要使用顯式轉換和instanceOf操作符。它也給運行時帶來好處,因爲不會產生類型檢查的字節碼指令

 

155,Enumeration和Iterator接口的區別?

        Enumeration的速度是Iterator的兩倍,也使用更少的內存。Enumeration是非常基礎的,也滿足了基礎的需要。

        但是,與Enumeration相比,Iterator更加安全,因爲當一個集合正在被遍歷的時候,它會阻止其它線程去修改集合。

        迭代器取代了Java集合框架中的Enumeration。迭代器允許調用者從集合中移除元素,而Enumeration不能做到。爲了使它的功能更加清晰,迭代器方法名已經經過改善。

 

156,Iterater和ListIterator之間有什麼區別?

 

        1,我們可以使用Iterator來遍歷Set和List集合,而ListIterator只能遍歷List。

        2,Iterator只可以向前遍歷,而LIstIterator可以雙向遍歷。

        3,ListIterator從Iterator接口繼承,然後添加了一些額外的功能,比如添加一個元素、替換一個元素、獲取前面或後面元素的索引位置。

 

157,我們如何對一組對象進行排序?

 

        如果我們需要對一個對象數組進行排序,我們可以使用Arrays.sort()方法。如果我們需要排序一個對象列表,我們可以使用Collection.sort()方法。

        兩個類都有用於自然排序(使用Comparable)或基於標準的排序(使用Comparator)的重載方法sort()。

        Collections內部使用數組排序方法,所有它們兩者都有相同的性能,只是Collections需要花時間將列表轉換爲數組。

 

158,與Java集合框架相關的有哪些最好的實踐?

 

        1,根據需要選擇正確的集合類型。比如,如果指定了大小,我們會選用Array而非ArrayList。如果我們想根據插入順序遍歷一個Map,我們需要使用TreeMap。如果我們不想重複,我們應該使用Set。

        2,一些集合類允許指定初始容量,所以如果我們能夠估計到存儲元素的數量,我們可以使用它,就避免了重新哈希或大小調整。

        3,基於接口編程,而非基於實現編程,它允許我們後來輕易地改變實現。

        4,總是使用類型安全的泛型,避免在運行時出現ClassCastException。

        5,使用JDK提供的不可變類作爲Map的key,可以避免自己實現hashCode()和equals()。

        6,儘可能使用Collections工具類,或者獲取只讀、同步或空的集合,而非編寫自己的實現。它將會提供代碼重用性,它有着更好的穩定性和可維護性。

 

159,什麼是事務?,

 

事務是恢復和併發控制的基本單位

事務的四個基本特徵

原子性,一致性,隔離性,持久性

原子性和一致性差不多,意思是要麼全部成功,要麼就失敗

一致性是說,從一個一致性狀態到另一個一致性狀態

隔離性是說一個事務執行的過程中不能被另一個事務干擾

持久性也就是事務一旦提交,他對數據庫中數據的改變就應該是永久的,不能變的(這裏只是面試簡單的說一下理解,詳細理解問度娘)

 

Java面試題-併發篇十六

 

 

161,Java內存模型是什麼?

 

        Java內存模型規定和指引Java程序在不同的內存架構、CPU和操作系統間有確定性地行爲。它在多線程的情況下尤其重要。Java內存模型對一個線程所做的變動能被其它線程可見提供了保證,它們之間是先行發生關係。這個關係定義了一些規則讓程序員在併發編程時思路更清晰。比如,先行發生關係確保了:

 

        線程內的代碼能夠按先後順序執行,這被稱爲程序次序規則。

 

        對於同一個鎖,一個解鎖操作一定要發生在時間上後發生的另一個鎖定操作之前,也叫做管程鎖定規則。

 

        前一個對volatile的寫操作在後一個volatile的讀操作之前,也叫volatile變量規則。

 

        一個線程內的任何操作必需在這個線程的start()調用之後,也叫作線程啓動規則。

 

        一個線程的所有操作都會在線程終止之前,線程終止規則。

 

        一個對象的終結操作必需在這個對象構造完成之後,也叫對象終結規則。

 

可傳遞性

 

更多介紹可以移步併發編程網:

 

(深入理解java內存模型系列文章:http://ifeve.com/java-memory-model-0)

 

162,Java中interrupted 和isInterruptedd方法的區別?

 

        interrupted() 和 isInterrupted()的主要區別是前者會將中斷狀態清除而後者不會。Java多線程的中斷機制是用內部標識來實現的,調用Thread.interrupt()來中斷一個線程就會設置中斷標識爲true。當中斷線程調用靜態方法Thread.interrupted()來檢查中斷狀態時,中斷狀態會被清零。

 

        非靜態方法isInterrupted()用來查詢其它線程的中斷狀態且不會改變中斷狀態標識。簡單的說就是任何拋出InterruptedException異常的方法都會將中斷狀態清零。無論如何,一個線程的中斷狀態都有可能被其它線程調用中斷來改變。

 

163,Java中的同步集合與併發集合有什麼區別?

 

        同步集合與併發集合都爲多線程和併發提供了合適的線程安全的集合,不過併發集合的可擴展性更高。在Java1.5之前程序員們只有同步集合來用且在多線程併發的時候會導致爭用,阻礙了系統的擴展性。Java5介紹了併發集合像ConcurrentHashMap,不僅提供線程安全還用鎖分離和內部分區等現代技術提高了可擴展性。

 

        不管是同步集合還是併發集合他們都支持線程安全,他們之間主要的區別體現在性能和可擴展性,還有他們如何實現的線程安全上。

 

        同步HashMap, Hashtable, HashSet, Vector, ArrayList 相比他們併發的實現(ConcurrentHashMap, CopyOnWriteArrayList, CopyOnWriteHashSet)會慢得多。造成如此慢的主要原因是鎖, 同步集合會把整個Map或List鎖起來,而併發集合不會。併發集合實現線程安全是通過使用先進的和成熟的技術像鎖剝離。

 

        比如ConcurrentHashMap 會把整個Map 劃分成幾個片段,只對相關的幾個片段上鎖,同時允許多線程訪問其他未上鎖的片段。

 

        同樣的,CopyOnWriteArrayList 允許多個線程以非同步的方式讀,當有線程寫的時候它會將整個List複製一個副本給它。

 

        如果在讀多寫少這種對併發集合有利的條件下使用併發集合,這會比使用同步集合更具有可伸縮性。

 

164,什麼是線程池? 爲什麼要使用它?

 

        創建線程要花費昂貴的資源和時間,如果任務來了才創建線程那麼響應時間會變長,而且一個進程能創建的線程數有限。爲了避免這些問題,在程序啓動的時候就創建若干線程來響應處理,它們被稱爲線程池,裏面的線程叫工作線程。從JDK1.5開始,Java API提供了Executor框架讓你可以創建不同的線程池。比如單線程池,每次處理一個任務;數目固定的線程池或者是緩存線程池(一個適合很多生存期短的任務的程序的可擴展線程池)

        線程池的作用,就是在調用線程的時候初始化一定數量的線程,有線程過來的時候,先檢測初始化的線程還有空的沒有,沒有就再看當前運行中的線程數是不是已經達到了最大數,如果沒有,就新分配一個線程去處理。

        就像餐館中吃飯一樣,從裏面叫一個服務員出來;但如果已經達到了最大數,就相當於服務員已經用盡了,那沒得辦法,另外的線程就只有等了,直到有新的“服務員”爲止。

        線程池的優點就是可以管理線程,有一個高度中樞,這樣程序纔不會亂,保證系統不會因爲大量的併發而因爲資源不足掛掉。

 

165,Java中活鎖和死鎖有什麼區別?

        活鎖:一個線程通常會有會響應其他線程的活動。如果其他線程也會響應另一個線程的活動,那麼就有可能發生活鎖。同死鎖一樣,發生活鎖的線程無法繼續執行。然而線程並沒有阻塞——他們在忙於響應對方無法恢復工作。這就相當於兩個在走廊相遇的人:甲向他自己的左邊靠想讓乙過去,而乙向他的右邊靠想讓甲過去。可見他們阻塞了對方。甲向他的右邊靠,而乙向他的左邊靠,他們還是阻塞了對方。

        死鎖:兩個或更多線程阻塞着等待其它處於死鎖狀態的線程所持有的鎖。死鎖通常發生在多個線程同時但以不同的順序請求同一組鎖的時候,死鎖會讓你的程序掛起無法完成任務

 

166,如何避免死鎖?

死鎖的發生必須滿足以下四個條件:

        互斥條件:一個資源每次只能被一個進程使用。

        請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。

        不剝奪條件:進程已獲得的資源,在末使用完之前,不能強行剝奪。

        循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關係。

三種用於避免死鎖的技術:

        加鎖順序(線程按照一定的順序加鎖)

        加鎖時限(線程嘗試獲取鎖的時候加上一定的時限,超過時限則放棄對該鎖的請求,並釋放自己佔有的鎖)

        死鎖檢測

 

(死鎖原因及如何避免更深理解移步:http://blog.csdn.net/ls5718/article/details/51896159)

 

167,notify()和notifyAll()有什麼區別?

        1,notify()和notifyAll()都是Object對象用於通知處在等待該對象的線程的方法。

        2,void notify(): 喚醒一個正在等待該對象的線程。

        3,void notifyAll(): 喚醒所有正在等待該對象的線程。

兩者的最大區別在於:

         notifyAll使所有原來在該對象上等待被notify的線程統統退出wait的狀態,變成等待該對象上的鎖,一旦該對象被解鎖,他們就會去競爭。

         notify他只是選擇一個wait狀態線程進行通知,並使它獲得該對象上的鎖,但不驚動其他同樣在等待被該對象notify的線程們,當第一個線程運行完畢以後釋放對象上的鎖,此時如果該對象沒有再次使用notify語句,即便該對象已經空閒,其他wait狀態等待的線程由於沒有得到該對象的通知,繼續處在wait狀態,直到這個對象發出一個notify或notifyAll,它們等待的是被notify或notifyAll,而不是鎖。

 

168,什麼是可重入鎖(ReentrantLock)?

        Java.util.concurrent.lock 中的 Lock 框架是鎖定的一個抽象,它允許把鎖定的實現作爲Java 類,而不是作爲語言的特性來實現。這就爲Lock 的多種實現留下了空間,各種實現可能有不同的調度算法、性能特性或者鎖定語義。            ReentrantLock 類實現了Lock ,它擁有與synchronized 相同的併發性和內存語義,但是添加了類似鎖投票、定時鎖等候和可中斷鎖等候的一些特性。此外,它還提供了在激烈爭用情況下更佳的性能。(換句話說,當許多線程都想訪問共享資源時,JVM可以花更少的時候來調度線程,把更多時間用在執行線程上。)

          Reentrant 鎖意味着什麼呢?簡單來說,它有一個與鎖相關的獲取計數器,如果擁有鎖的某個線程再次得到鎖,那麼獲取計數器就加1,然後鎖需要被釋放兩次才能獲得真正釋放。這模仿了synchronized 的語義;如果線程進入由線程已經擁有的監控器保護的synchronized 塊,就允許線程繼續進行,當線程退出第二個(或者後續)synchronized塊的時候,不釋放鎖,只有線程退出它進入的監控器保護的第一個synchronized 塊時,才釋放鎖。

 

169,讀寫鎖可以用於什麼應用場景?

        讀寫鎖可以用於 “多讀少寫” 的場景,讀寫鎖支持多個讀操作併發執行,寫操作只能由一個線程來操作

        ReadWriteLock對向數據結構相對不頻繁地寫入,但是有多個任務要經常讀取這個數據結構的這類情況進行了優化。ReadWriteLock使得你可以同時有多個讀取者,只要它們都不試圖寫入即可。如果寫鎖已經被其他任務持有,那麼任何讀取者都不能訪問,直至這個寫鎖被釋放爲止。

ReadWriteLock 對程序性能的提高主要受制於如下幾個因素:

1,數據被讀取的頻率與被修改的頻率相比較的結果。

2,讀取和寫入的時間

3,有多少線程競爭

4,是否在多處理機器上運行

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章