1、public、private、protected、Friendly的區別與作用域
public,protected,friendly,private的訪問權限如下:
第一句錯,第二句不錯。
Java規范:
a.高位轉低位需要強制轉換
b.低位轉高位自動轉.
復合賦值(E1 op=E2)等價于簡單賦值(E1=(T)((E1) op (E2))),而(s1 += 1)表達式使用的是復合賦值操作符,復合賦值表達式自動地將所執行計算的結果轉型為其左側變量的類型。如果結果的類型與該變量的類型相同,那么這個轉型不會造成任何影響。
空指針異常類:NullPointerException
類型強制轉換異常:ClassCastException
數組負下標異常:NegativeArrayException
數組下標越界異常:ArrayIndexOutOfBoundsException
違背安全原則異常:SecturityException
文件已結束異常:EOFException
文件未找到異常:FileNotFoundException
字符串轉換為數字異常:NumberFormatException
操作數據庫異常:SQLException
輸入輸出異常:IOException
方法未找到異常:NoSuchMethodException
ClassCastException - 類型強制轉換異常。
IllegalArgumentException - 傳遞非法參數異常。
ArithmeticException - 算術運算異常
ArrayStoreException - 向數組中存放與聲明類型不兼容對象異常
IndexOutOfBoundsException - 下標越界異常
NegativeArraySizeException - 創建一個大小為負數的數組錯誤異常
NumberFormatException - 數字格式異常
SecurityException - 安全異常
UnsupportedOperationException - 不支持的操作異常
Error和Exception的聯系
-
繼承結構:Error和Exception都是繼承于Throwable,RuntimeException繼承自Exception。
-
Error和RuntimeException及其子類稱為未檢查異常(Unchecked exception),其它異常成為受檢查異常(Checked Exception)。
Error和Exception的區別
-
Error類一般是指與虛擬機相關的問題,如系統崩潰,虛擬機錯誤,內存空間不足,方法調用棧溢出等。如Java.lang.StackOverFlowError和Java.lang.OutOfMemoryError。對于這類錯誤,Java編譯器不去檢查他們。對于這類錯誤的導致的應用程序中斷,僅靠程序本身無法恢復和預防,遇到這樣的錯誤,建議讓程序終止。
-
Exception類表示程序可以處理的異常,可以捕獲且可能恢復。遇到這類異常,應該盡可能處理異常,使程序恢復運行,而不應該隨意終止異常。
運行時異常和受檢查的異常
Exception又分為運行時異常(Runtime Exception)和受檢查的異常(Checked Exception )。
-
RuntimeException:其特點是Java編譯器不去檢查它,也就是說,當程序中可能出現這類異常時,即使沒有用try……catch捕獲,也沒有用throws拋出,還是會編譯通過,如除數為零的ArithmeticException、錯誤的類型轉換、數組越界訪問和試圖訪問空指針等。處理RuntimeException的原則是:如果出現RuntimeException,那么一定是程序員的錯誤。
-
受檢查的異常(IOException等):這類異常如果沒有try……catch也沒有throws拋出,編譯是通不過的。這類異常一般是外部錯誤,例如文件找不到、試圖從文件尾后讀取數據等,這并不是程序本身的錯誤,而是在應用環境中出現的外部錯誤。
-
ArrayList 采用的是數組形式來保存對象的,這種方式將對象放在連續的位置中,所以最大的缺點就是插入刪除時非常麻煩
-
LinkedList 采用的將對象存放在獨立的空間中,而且在每個空間中還保存下一個鏈接的索引 但是缺點就是查找非常麻煩 要叢第一個索引開始
-
ArrayList和Vector都是用數組方式存儲數據,此數組元素數要大于實際的存儲空間以便進行元素增加和插入操作,他們都允許直接用序號索引元素,但是插入數據元素涉及到元素移動等內存操作,所以索引數據快而插入數據慢.
-
Vector使用了sychronized方法(線程安全),所以在性能上比ArrayList要差些.
-
LinkedList使用雙向鏈表方式存儲數據,按序號索引數據需要前向或后向遍歷數據,所以索引數據慢,是插入數據時只需要記錄前后項即可,所以插入的速度快.
arraylist和vector的區別??
1).同步性:Vector是線程安全的,也就是說是同步的,而ArrayList是線程不安全的,不是同步的?
2).數據增長:當需要增長時,Vector默認增長為原來一培,而ArrayList卻是原來的一半
1.heap是堆,stack是棧。
2.stack的空間由操作系統自動分配和釋放,heap的空間是手動申請和釋放的,heap常用new關鍵字來分配。
3.stack空間有限,heap的空間是很大的自由區。在Java中,若只是聲明一個對象,則先在棧內存中為其分配地址空間,若再new一下,實例化它,則在堆內存中為其分配地址。
4.舉例:數據類型 變量名;這樣定義的東西在棧區。如:Object a =null; 只在棧內存中分配空間。new 數據類型();或者malloc(長度); 這樣定義的東西就在堆區如:Object b =new Object(); 則在堆內存中分配空間
-
throws用在方法聲明中,表明當前方法在運行時會有異常拋出,需要在調用該方法的時候注意控制異常
-
throw用在方法體內,手動制造一個異常,中斷代碼的繼續執行
-
try-catch-finally是一起使用的
當某段代碼在運行期間可能會發生異常而終止執行時,使用。
結構為
try
{
//可能發生異常的代碼
}
catch (異常類型 )
{
//異常發生時的處理方式
}
finally
{
//其他必須執行的語句
}
當try語句塊中的代碼在執行時發生異常,就會被catch捕獲,進入catch語句塊進行處理,如果沒有發生異常就繼續執行
finally語句塊中的代碼是一些必須執行的語句,這里的代碼無論try中是否發生異常都會被執行。
- 在?Java?中,每個異常都是一個對象,它是?Throwable?類或其它子類的實例。當一個方法出現異常后便拋出一個異常對象,該對象中包含有異常信息,調用這個對象的方法可以捕獲到這個異常并進行處理。Java?的異常處理是通過?5?個關鍵詞來實現的:try、catch、throw、throws?和?finally。一般情況下是用?try?來執行一段程序,如果出現異常,系統會拋出(throws)一個異常,這時候你可以通過它的類型來捕捉(catch)它,或最后(finally)由缺省處理器來處理;
-
try?用來指定一塊預防所有“異常”的程序;
catch?子句緊跟在?try?塊后面,用來指定你想要捕捉的“異常”的類型;
throw?語句用來明確地拋出一個“異常”;
throws?用來標明一個成員函數可能拋出的各種“異常”;
Finally?為確保一段代碼不管發生什么“異常”都被執行一段代碼;
- throws關鍵字通常被應用在聲明方法時,用來指定可能拋出的異常。多個異常可以使用逗號隔開。
-
throw關鍵字通常用在方法體中,并且拋出一個異常對象。程序在執行到throw語句時立即停止,它后面的語句都不執行。通過throw拋出異常后,如果想在上一級代碼中來捕獲并處理異常,則需要在拋出異常的方法中使用throws關鍵字在方法聲明中指明要跑出的異常;如果要捕捉throw拋出的異常,則必須使用try—catch語句。可見,throw可以主動拋出異常,也就是可以在try中拋出異常。
類的多少沒有限制,不過一個java源文件最多只能有一個public 修飾的 class,沒有也行,如果有這個.java文件的文件名得是public類的類名,編譯.java文件的時候,它會給每一個類生成一個.class文件。
內存泄露就是指一個不再被程序使用的對象或變量一直被占據在內存中。java中有垃圾回收機制,它可以保證一對象不再被引用的時候,即對象變成了孤兒的時候,對象將自動被垃圾回收器從內存中清除掉。由于Java?使用有向圖的方式進行垃圾回收管理,可以消除引用循環的問題,例如有兩個對象,相互引用,只要它們和根進程不可達的,那么GC也是可以回收它們的。
java中的內存泄露的情況:
1.長生命周期的對象持有短生命周期對象的引用就很可能發生內存泄露,盡管短生命周期對象已經不再需要,但是因為長生命周期對象持有它的引用而導致不能被回收,這就是java中內存泄露的發生場景,通俗地說,就是程序員可能創建了一個對象,以后一直不再使用這個對象,這個對象卻一直被引用,即這個對象無用但是卻無法被垃圾回收器回收的,這就是java中可能出現內存泄露的情況,例如,緩存系統,我們加載了一個對象放在緩存中(例如放在一個全局map對象中),然后一直不再使用它,這個對象一直被緩存引用,但卻不再被使用。
檢查java中的內存泄露,一定要讓程序將各種分支情況都完整執行到程序結束,然后看某個對象是否被使用過,如果沒有,則才能判定這個對象屬于內存泄露。
?2.如果一個外部類的實例對象的方法返回了一個內部類的實例對象,這個內部類對象被長期引用了,即使那個外部類實例對象不再被使用,但由于內部類持久外部類的實例對象,這個外部類對象將不會被垃圾回收,這也會造成內存泄露。
?3.當一個對象被存儲進HashSet集合中以后,就不能修改這個對象中的那些參與計算哈希值的字段了,否則,對象修改后的哈希值與最初存儲進HashSet集合中時的哈希值就不同了,在這種情況下,即使在contains方法使用該對象的當前引用作為的參數去HashSet集合中檢索對象,也將返回找不到對象的結果,這也會導致無法從HashSet集合中單獨刪除當前對象,造成內存泄露。
Java中的流分為兩種,一種是字節流,另一種是字符流,分別由四個抽象類來表示(每種流包括輸入和輸出兩種所以一共四個):InputStream,OutputStream,Reader,Writer。Java中其他多種多樣變化的流均是由它們派生出來的.
?
字符流和字節流是根據處理數據的不同來區分的。字節流按照8位傳輸,字節流是最基本的,所有文件的儲存是都是字節(byte)的儲存,在磁盤上保留的并不是文件的字符而是先把字符編碼成字節,再儲存這些字節到磁盤。
1.字節流可用于任何類型的對象,包括二進制對象,而字符流只能處理字符或者字符串;
2. 字節流提供了處理任何類型的IO操作的功能,但它不能直接處理Unicode字符,而字符流就可以。
讀文本的時候用字符流,例如txt文件。讀非文本文件的時候用字節流,例如mp3。理論上任何文件都能夠用字節流讀取,但當讀取的是文本數據時,為了能還原成文本你必須再經過一個轉換的工序,相對來說字符流就省了這個麻煩,可以有方法直接讀取。
? 字符流處理的單元為2個字節的Unicode字符,分別操作字符、字符數組或字符串,而字節流處理單元為1個字節, 操作字節和字節數組。所以字符流是由Java虛擬機將字節轉化為2個字節的Unicode字符為單位的字符而成的,所以它對多國語言支持性比較好!
1.字節流:繼承于InputStream \ OutputStream。
OutputStream提供的方法:
???? void write(int b):寫入一個字節的數據
???? void write(byte[] buffer):將數組buffer的數據寫入流
???? void write(byte[] buffer,int offset,int len):從buffer[offset]開始,寫入len個字節的數據
???? void flush():強制將buffer內的數據寫入流
???? void close():關閉流
???? InputStream提供的方法:
???? int read():讀出一個字節的數據,如果已達文件的末端,返回值為-1
???? int read(byte[] buffer):讀出buffer大小的數據,返回值為實際所讀出的字節數
???? int read(byte[] buffer,int offset,int len)
???? int available():返回流內可供讀取的字節數目
???? long skip(long n):跳過n個字節的數據,返回值為實際所跳過的數據數
???? void close():關閉流
? ?2.字符流,繼承于InputStreamReader \ OutputStreamWriter。
字符流的類:1),BufferedReader是一種過濾器(filter)(extends FilterReader)。過濾
器用來將流的數據加以處理再輸出。構造函數為:
?BufferedReader(Reader in):生成一個緩沖的字符輸入流,in為一個讀取器
?BufferedReader(Reader in,int size):生成一個緩沖的字符輸入流,并指定緩沖區的大小為size
public class IOStreamDemo { public void samples() throws IOException {?//1. 這是從鍵盤讀入一行數據,返回的是一個字符串 ???????????BufferedReader stdin =new BufferedReader(new InputStreamReader(System.in)); System.out.print("Enter a line:"); ???????????System.out.println(stdin.readLine());
??//2. 這是從文件中逐行讀入數據
???BufferedReader in = new BufferedReader(new FileReader("IOStreamDemo.java")); ???????????String s, s2 = new String(); ???????????while((s = in.readLine())!= null) ??????????????????????s2 += s + "\n"; ??????????????? ?in.close();
????//3. 這是從一個字符串中逐個讀入字節 ???????????StringReader in1 = new StringReader(s2); ???????????int c; ???????????while((c = in1.read()) != -1) ??????????????????????System.out.print((char)c);
??//4. 這是將一個字符串寫入文件 ???????????try { BufferedReader in2 = new BufferedReader(new StringReader(s2)); ??????????????????????PrintWriter out1 = new PrintWriter(new BufferedWriter(new FileWriter("IODemo.out"))); ??????????????????????int lineCount = 1; ??????????????????????while((s = in2.readLine()) != null ) ?????????????????????????????????out1.println(lineCount++ + ": " + s); ??????????????????????out1.close(); ???????????} catch(EOFException e) { System.err.println("End of stream"); ???????????} } }
對于上面的例子,需要說明的有以下幾點:
1. InputStreamReader是InputStream和Reader之間的橋梁,由于System.in是字節流,需要用它來包裝之后變為字符流供給BufferedReader使用。
3. PrintWriter out1 = new PrintWriter(new BufferedWriter(new FileWriter("IODemo.out")));
這句話體現了Java輸入輸出系統的一個特點,為了達到某個目的,需要包裝好幾層。首先,輸出目的地是文件IODemo.out,所以最內層包裝的是FileWriter,建立一個輸出文件流,接下來,我們希望這個流是緩沖的,所以用BufferedWriter來包裝它以達到目的,最后,我們需要格式化輸出結果,于是將PrintWriter包在最外層。
Java流有著另一個重要的用途,那就是利用對象流對對象進行序列化。
在一個程序運行的時候,其中的變量數據是保存在內存中的,一旦程序結束這些數據將不會被保存,一種解決的辦法是將數據寫入文件,而Java中提供了一種機制,它可以將程序中的對象寫入文件,之后再從文件中把對象讀出來重新建立。這就是所謂的對象序列化。Java中引入它主要是為了RMI(Remote Method Invocation)和Java Bean所用,不過在平時應用中,它也是很有用的一種技術。
不可以。因為非static方法是要與對象關聯在一起的,必須創建一個對象后,才可以在該對象上進行方法調用,而static方法調用時不需要創建對象,可以直接調用。也就是說,當一個static方法被調用時,可能還沒有創建任何實例對象,如果從一個static方法中發出對非static方法的調用,那個非static方法是關聯到哪個對象上的呢?這個邏輯無法成立,所以,一個static方法內部發出對非static方法的調用。
在實際編程過程中,我們常常要遇到這種情況:有一個對象A,在某一時刻A中已經包含了一些有效值,此時可能會需要一個和A完全相同新對象B,并且此后對B任何改動都不會影響到A中的值,也就是說,A與B是兩個獨立的對象,但B的初始值是由A對象確定的。Clone 有缺省行為,super.clone();他負責產生正確大小的空間,并逐位復制。使用clone()來復制一個對象,clone()從Object類繼承。所有具有clone功能的類都有一個特性,那就是它直接或間接地實現了Cloneable接口。
protected native Object clone() throws CloneNotSupportedException;
可以看出它是一個protected方法,所以我們不能簡單地調用它;關鍵字native,表明這個方法使用Java以外的語言實現。
對于 object? x,
x.clone() != x
x.clone().getClass() == x.getClass()
x.clone().equals(x)
以上返回的值都為true
要說明的有兩點:一是拷貝對象返回的是一個新對象,而不是一個引用。二是拷貝對象與用new操作符返回的新對象的區別就是這個拷貝已經包含了一些原來對象的信息,而不是對象的初始信息。
1.淺復制與深復制概念
⑴淺復制(淺克隆):被復制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。換言之,淺復制僅僅復制所考慮的對象,而不復制它所引用的對象。
⑵深復制(深克隆)
被復制對象的所有變量都含有與原來的對象相同的值,除去那些引用其他對象的變量。那些引用其他對象的變量將指向被復制過的新對象,而不再是原有的那些被引用的對象。換言之,深復制把要復制的對象所引用的對象都復制了一遍。
- java多線程實現方法主要有3種:繼承Thread類、實現Runnable接口和使用ExecutorService、callable、future實現有返回結果的多線程。其中前2方式線程執行完后都沒有返回值,只有最后一種有返回值。
- 繼承Thread類啟動線程的唯一方法是通過Thread類的start()實例方法。start()方法是一種native方法,它將啟動一個新線程并執行run方法。這種方法通過自己的類直接extend Thread,并復寫run()方法,就可以啟動新線程并執行自己定義的run()方法。
Java中交互方式分為同步和異步兩種:
-
同步交互:指發送一個請求,需要等待返回,然后才能夠發送下一個請求,有個等待過程;
-
異步交互:指發送一個請求,不需要等待返回,隨時可以再發送下一個請求,即不需要等待。?區別:一個需要等待,一個不需要等待,在部分情況下,我們的項目開發中都會優先選擇不需要等待的異步交互方式。
-
哪些情況建議使用同步交互呢?比如銀行的轉賬系統,對數據庫的保存操作等等,都會使用同步交互操作,其余情況都優先使用異步交互。
MyBatis 本是apache的一個開源項目iBatis, 2010年這個項目由apache software foundation 遷移到了google code,并且改名為MyBatis。
MyBatis是一個優秀的持久層框架,它對jdbc的操作數據庫的過程進行封裝,使開發者只需要關注 SQL 本身,而不需要花費精力去處理例如注冊驅動、創建connection、創建statement、手動設置參數、結果集檢索等jdbc繁雜的過程代碼。
Mybatis通過xml或注解的方式將要執行的statement配置起來,并通過java對象和statement中的sql進行映射生成最終執行的sql語句,最后由mybatis框架執行sql并將結果映射成java對象并返回。
1、? mybatis配SqlMapConfig.xml,此文件作為mybatis的全局配置文件,配置了mybatis的運行環境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作數據庫的sql語句。此文件需要在SqlMapConfig.xml中加載。
2、? 通過mybatis環境等配置信息構造SqlSessionFactory即會話工廠
3、? 由會話工廠創建sqlSession即會話,操作數據庫需要通過sqlSession進行。
4、? mybatis底層自定義了Executor執行器接口操作數據庫,Executor接口有兩個實現,一個是基本執行器、一個是緩存執行器。
5、? Mapped Statement也是mybatis一個底層封裝對象,它包裝了mybatis配置信息及sql映射信息等。mapper.xml文件中一個sql對應一個Mapped Statement對象,sql的id即是Mapped statement的id。
6、? Mapped Statement對sql執行輸入參數進行定義,包括HashMap、基本類型、pojo,Executor通過 Mapped Statement在執行sql前將輸入的java對象映射至sql中,輸入參數映射就是jdbc編程中對preparedStatement設置參數。
7、? Mapped Statement對sql執行輸出結果進行定義,包括HashMap、基本類型、pojo,Executor通過 Mapped Statement在執行sql后將輸出結果映射至java對象中,輸出結果映射過程相當于jdbc編程中對結果的解析處理過程。
工作流程:mybatis通過sqlSessionFactory創建sqlSession,?sqlSession表示應用程序與數據庫的會話,當用戶使用mapper.xml文件中配置的的方法時,mybatis首先會解析sql動態標簽為對應數據庫sql的形式,并將其封裝進MapperStatement對象,然后通過executor將sql注入數據庫執行,并返回結果
(1)這兩個方法來自不同的類分別是,sleep來自Thread類,和wait來自Object類;sleep是Thread的靜態類方法,誰調用的誰去睡覺,即使在a線程里調用了b的sleep方法,實際上還是a去睡覺,要讓b線程睡覺要在b的代碼中調用sleep。
(2)最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其他線程可以使用同步控制塊或者方法。sleep不出讓系統資源;wait是進入線程等待池等待,出讓系統資源,其他線程可以占用CPU。一般wait不會加時間限制,因為如果wait線程的?運行資源不夠,再出來也沒用,要等待其他線程調用notify/notifyAll喚醒等待池中的所有線程,才會進入就緒隊列等待OS分配系統資源。?sleep(milliseconds)可以用時間指定使它自動喚醒過來,如果時間不到只能調用interrupt()強行打斷;
(1)JAVA平臺提供了兩個類:String和StringBuffer,它們可以儲存和操作字符串,即包含多個字符的字符數據。這個String類提供了數值不可改變的字符串。而這個StringBuffer類提供的字符串進行修改。當你知道字符數據要改變的時候你就可以使用StringBuffer。典型地,你可以使用StringBuffers來動態構造字符數據。另外,String實現了equals方法;而StringBuffer沒有實現equals方法,所以,new?StringBuffer(“abc”).equals(new?StringBuffer(“abc”)的結果為false。
(2)StringBuffer線程安全的可變字符序列。一個類似于?String?的字符串緩沖區,但不能修改;通過某些方法調用可以改變該序列的長度和內容,可將字符串緩沖區安全地用于多個線程。可以在必要時對這些方法進行同步,因此任意特定實例上的所有操作就好像是以串行順序發生的,該順序與所涉及的每個線程進行的方法調用順序一致;
(3)StringBuilder一個可變的字符序列。此類提供一個與?StringBuffer?兼容的?API,但不保證同步。該類被設計用作?StringBuffer?的一個簡易替換,用在字符串緩沖區被單個線程使用的時候(這種情況很普遍)。(如果可能,建議優先采用該類,因為在大多數實現中,它比?StringBuffer?要快。但將?StringBuilder?的實例用于多個線程是不安全的。如果需要這樣的同步,則建議使用?StringBuffer。);
(4)HashMap是Hashtable的輕量級實現(非同步非線程安全的實現),他們都完成了Map接口,主要區別在于HashMap允許空(null)鍵值(key),由于非線程安全,在只有一個線程訪問的情況下,效率要高于Hashtable。
(1)基本數據類型包括byte、int、char、long、float、double、boolean和short;java.lang.String類是final類型的,因此不可以繼承這個類、不能修改這個類。為了提高效率節省空間,我們應該用StringBuffer類;
(2)int?i?=?Integer.parseInt([String]);i?=?Integer.parseInt([String],[int?radix]);或者int?i?=?Integer.valueOf(my_str).intValue();int轉StringString?s?=?String.valueOf(i);String?s?=?Integer.toString(i);String?s?=?""?+?i;
(1)區別:Ajax是一門技術,它提供了異步更新的機制,使用客戶端與服務器間交換數據而非整個頁面文檔,實現頁面的局部更新。jQuery是一個框架,它對JS(JS是一門前端語言。)進行了封裝,使其更方便使用。jQuery使得JS與Ajax的使用更方便
jsp負責客戶端顯示
servlet負責控制,轉向等
(2)生命周期:Servlet?生命周期:Servlet?加載--->實例化--->服務--->銷毀;
init():在Servlet的生命周期中,僅執行一次init()方法。它是在服務器裝入Servlet時執行的,負責初始化Servlet對象。可以配置服務器,以在啟動服務器或客戶機首次訪問Servlet時裝入Servlet。
service():它是Servlet的核心,負責響應客戶的請求。每當一個客戶請求一個HttpServlet對象,該對象的Service()方法?就要調用,而且傳遞給這個方法一個“請求”(ServletRequest)對象和一個“響應”(ServletResponse)對象作為參數。在?HttpServlet中已存在Service()方法。默認的服務功能是調用與HTTP請求的方法相應的do功能。
destroy():?僅執行一次,在服務器端停止且卸載Servlet時執行該方法。當Servlet對象退出生命周期時,負責釋放占用的資源。一個?Servlet在運行service()方法時可能會產生其他的線程,因此需要確認在調用destroy()方法時,這些線程已經終止或完成。
Ajax:ajax負責客戶端與服務器直接聯系,而不用jsp提交表單。一般ajax與servlet聯系,也可直接與javabean聯系
工作機制:客戶端請求提交到DispatcherServlet
由DispatcherServlet控制器查詢一個或多個HandlerMapping,找到處理請求的Controller
DispatcherServlet將請求提交到Controller
Controller調用業務邏輯處理后,返回ModelAndView
DispatcherServlet查詢一個或多個ViewResoler視圖解析器,找到ModelAndView指定的視圖
視圖負責將結果顯示到客戶端
視圖的好處:視圖對象的定義比實體定義還要簡單,不需要注解,不需要映射,但是唯一不同的是我們需要額外構造一個帶有字段初始化的構造函數
1.Spring事務機制主要包括聲明式事務和編程式事務,使用最多的就是聲明式事務。聲明式事物是具有AOP來實現的,但你并不需要真正精通AOP技術也能掌握聲明式事務而編程式事物提供了一致的事務編程風格,通過模塊化操作一致性地管理事務。
2.在使用Spring聲明式事務時,有一個非常重要的概念就是事務屬性。事務屬性通常由事務的傳播行為,事務的隔離級別,事務的超時值和事務只讀標志組成。我們在進行事務劃分時,需要進行事務定義,也就是配置事務的屬性:
事務的四種屬性
Spring在TransactionDefinition接口中定義這些屬性,以供PlatfromTransactionManager使用, PlatfromTransactionManager是spring事務管理的核心接口。
4.Spring事務管理的優勢在哪
使用JDBC的時候開啟事務使用Connection,而使用Hibernate時開啟事務使用的是Session。所以如果我們使用傳統的事務編程策略時,程序代碼必須和具體的事務操作代碼耦合。這樣在不同的事務策略之間切換時開發者必須手動改代碼。而如果使用Spring來管理事務則不會出現這種情況。
5.Spring如何管理事務(典型的策略模式:行為的抽象)
Spring事務策略是通過PlatformTransactionManager接口實現的,它是整個Spring事務的核心。它是對事務策略的一個高度抽象,不依賴于任何具體的事務策略,而對于底層的具體的事務策略它相應的有不同的實現類。而對于不同的事務策略的切換通常由Spring容器來負責管理,應用程序既無須與具體的事務API耦合,也無須與特定的實現類耦合而將應用和持久化技術,事務API徹底分離開來。
6.Spring管理事務的幾個核心類
Spring事務管理的策略模式體現在哪?PlatformTransactionManager代表事務管理接口,但它并不知道底層到底如何管理事務的,而它只要求事務管理提供開始事務(getTransaction(TransactionDefinition definition)),提交事務(commit())和回滾事務(rollback())三個方法,具體的實現交給子類來完成。
SQL 注入簡介:
??????? SQL注入是最常見的攻擊方式之一,它不是利用操作系統或其它系統的漏洞來實現攻擊的,而是程序員因為沒有做好判斷,被不法用戶鉆了SQL的空子。
SQL注入攻擊的總體思路
1.尋找到SQL注入的位置;
2.判斷服務器類型和后臺數據庫類型;
3.針對不通的服務器和數據庫特點進行SQL注入攻擊。
下面我們先來看下什么是SQL注入:
??????? 比如在一個登陸界面,要求用戶輸入用戶名和密碼:
??????? 用戶名:???? ' or 1=1 --???
??????? 密???? 碼:???
點登陸,如若沒有做特殊處理,而只是一條帶條件的查詢語句如:
??????? String sql="select * from users where username='"+userName+"' and password='"+password+"' "
??????? 那么這個非法用戶就很得意的登陸進去了.(當然現在的有些語言的數據庫API已經處理了這些問題)
??????? 這是為什么呢?我們來看看這條語句,將用戶輸入的數據替換后得到這樣一條語句:
??????? select * from users where username='' or 1=1 --' and password=''
??????? 為了更明白些,可以將其復制到SQL分析器中,將會發現,這條語句會將數據庫的數據全部讀出來,為什么呢?
??????? 很簡單,看到條件后面 username='' or 1=1 用戶名等于 '' 或 1=1 那么這個條件一定會成功,然后后面加兩個-,這意味著什么?沒錯,注釋,它將后面的語句注釋,讓他們不起作用,這樣就可以順利的把數據庫中的數據讀取出來了。
??????? 這還是比較溫柔的,如果是執行?
??????? select * from users where username='' ;DROP Database??? (DB Name) --' and password=''
??????? .......其他的您可以自己想象。。。
??????? 那么我們怎么來處理這種情況呢?下面我以Java為列給大家兩種簡單的方法:
第一種采用預編譯語句集,它內置了處理SQL注入的能力,只要使用它的setString方法傳值即可:
??????? String sql= "select * from users where username=? and password=?;
??????? PreparedStatement preState = conn.prepareStatement(sql);
??????? preState.setString(1, userName);
??????? preState.setString(2, password);
??????? ResultSet rs = preState.executeQuery();
??????? ...
第二種是采用正則表達式,將包含有單引號('),分號(;) 和 注釋符號(--)的語句給替換掉來防止SQL注入
??????? public static String TransactSQLInjection(String str)
??????? {
????????????? return str.replaceAll(".*([';]+|(--)+).*", " ");
?????????? //?我認為 應該是return str.replaceAll("([';])+|(--)+","");
??????? }
??????? userName=TransactSQLInjection(userName);
??????? password=TransactSQLInjection(password);
??????? Statement sta = conn.createStatement();
??????? ResultSet rs = sta.executeQuery(sql);
悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關系型數據庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。
?
樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。樂觀鎖適用于多讀的應用類型,這樣可以提高吞吐量,像數據庫如果提供類似于write_condition機制的其實都是提供的樂觀鎖。
?
悲觀鎖
?
格式 SELECT…FOR UPDATE
例:select * from account where name="Erica" for update
這條 sql 語句鎖定了 account 表中所有符合檢索條件( name=“Erica” )的記錄。 本次事務提交之前(事務提交時會釋放事務過程中的鎖),外界無法修改這些記錄。
?
格式 SELECT…FOR UPDATE NOWAIT
該關鍵字的含義是“不用等待,立即返回”,如果當前請求的資源被其他會話鎖定時,會發生阻塞,nowait可以避免這一阻塞。
?
樂觀鎖
?
樂觀鎖,大多是基于數據版本 ( Version )記錄機制實現。何謂數據版本?即為數據增加一個版本標識,在基于數據庫表的版本解決方案中,一般是通過為數據庫表增加一個 “version” 字段來實現。
讀取出數據時,將此版本號一同讀出,之后更新時,對此版本號加一。此時,將提交數據的版本數據與數據庫表對應記錄的當前版本信息進行比對,如果提交的數據版本號大于數據庫表當前版本號,則予以更新,否則認為是過期數據。
?
總結:
兩種鎖各有優缺點,不可認為一種好于另一種,像樂觀鎖適用于寫比較少的情況下,即沖突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。但如果經常產生沖突,上層應用會不斷的進行retry,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適。
泛型是Java SE 1.5的新特性,泛型的本質是參數化類型,也就是說所操作的數據類型被指定為一個參數。這種參數類型可以用在類、接口和方法的創建中,分別稱為泛型類、泛型接口、泛型方法。 Java語言引入泛型的好處是安全簡單。
在Java SE 1.5之前,沒有泛型的情況的下,通過對類型Object的引用來實現參數的“任意化”,“任意化”帶來的缺點是要做顯式的強制類型轉換,而這種轉換是要求開發者對實際參數類型可以預知的情況下進行的。對于強制類型轉換錯誤的情況,編譯器可能不提示錯誤,在運行的時候才出現異常,這是一個安全隱患。
泛型的好處是在編譯的時候檢查類型安全,并且所有的強制轉換都是自動和隱式的,提高代碼的重用率。
1、泛型的類型參數只能是類類型(包括自定義類),不能是簡單類型。
2、同一種泛型可以對應多個版本(因為參數類型是不確定的),不同版本的泛型類實例是不兼容的。
3、泛型的類型參數可以有多個。
4、泛型的參數類型可以使用extends語句,例如<T extends superclass>。習慣上稱為“有界類型”。
5、泛型的參數類型還可以是通配符類型。例如Class<?> classType = Class.forName("java.lang.String");
泛型好處:
泛型簡單易用?
類型安全 泛型的主要目標是實現Java的類型安全。 泛型可以使編譯器知道一個對象的限定類型是什么,這樣編譯器就可以在一個高的程度上驗證這個類型
消除了強制類型轉換 使得代碼可讀性好,減少了很多出錯的機會
泛型的實現原理
泛型的實現是靠類型擦除技術 類型擦除是在編譯期完成的 也就是在編譯期 編譯器會將泛型的類型參數都擦除成它的限定類型,如果沒有則擦除為object類型之后在獲取的時候再強制類型轉換為對應的類型。 在運行期間并沒有泛型的任何信息,因此也沒有優化。
AVA的容器---List,Map,Set?
Collection?
├List?
│├LinkedList?
│├ArrayList?
│└Vector?
│ └Stack?
└Set?
Map?
├Hashtable?
├HashMap?
└WeakHashMap
?
?
Collection接口?
Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)。一些 Collection允許相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接繼承自Collection的類,Java SDK提供的類都是繼承自Collection的“子接口”如List和Set。?
所有實現Collection接口的類都必須提供兩個標準的構造函數:無參數的構造函數用于創建一個空的Collection,有一個 Collection參數的構造函數用于創建一個新的Collection,這個新的Collection與傳入的Collection有相同的元素。后一個構造函數允許用戶復制一個Collection。?
如何遍歷Collection中的每一個元素?不論Collection的實際類型如何,它都支持一個iterator()的方法,該方法返回一個迭代子,使用該迭代子即可逐一訪問Collection中每一個元素。典型的用法如下:?
Iterator it = collection.iterator(); // 獲得一個迭代子?
while(it.hasNext()) {?
Object obj = it.next(); // 得到下一個元素?
}?
由Collection接口派生的兩個接口是List和Set。
List接口?
List是有序的Collection,使用此接口能夠精確的控制每個元素插入的位置。用戶能夠使用索引(元素在List中的位置,類似于數組下標)來訪問List中的元素,這類似于Java的數組。?
和下面要提到的Set不同,List允許有相同的元素。?
除了具有Collection接口必備的iterator()方法外,List還提供一個listIterator()方法,返回一個 ListIterator接口,和標準的Iterator接口相比,ListIterator多了一些add()之類的方法,允許添加,刪除,設定元素,還能向前或向后遍歷。?
實現List接口的常用類有LinkedList,ArrayList,Vector和Stack。
LinkedList類?
LinkedList實現了List接口,允許null元素。此外LinkedList提供額外的get,remove,insert方法在 LinkedList的首部或尾部。這些操作使LinkedList可被用作堆棧(stack),隊列(queue)或雙向隊列(deque)。?
注意LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List:?
List list = Collections.synchronizedList(new LinkedList(...));
ArrayList類?
ArrayList實現了可變大小的數組。它允許所有元素,包括null。ArrayList沒有同步。?
size,isEmpty,get,set方法運行時間為常數。但是add方法開銷為分攤的常數,添加n個元素需要O(n)的時間。其他的方法運行時間為線性。?
每個ArrayList實例都有一個容量(Capacity),即用于存儲元素的數組的大小。這個容量可隨著不斷添加新元素而自動增加,但是增長算法并沒有定義。當需要插入大量元素時,在插入前可以調用ensureCapacity方法來增加ArrayList的容量以提高插入效率。?
和LinkedList一樣,ArrayList也是非同步的(unsynchronized)。
Vector類?
Vector非常類似ArrayList,但是Vector是同步的。由Vector創建的Iterator,雖然和ArrayList創建的 Iterator是同一接口,但是,因為Vector是同步的,當一個Iterator被創建而且正在被使用,另一個線程改變了Vector的狀態(例如,添加或刪除了一些元素),這時調用Iterator的方法時將拋出ConcurrentModificationException,因此必須捕獲該異常。
Stack 類?
Stack繼承自Vector,實現一個后進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當作堆棧使用。基本的push和pop 方法,還有peek方法得到棧頂的元素,empty方法測試堆棧是否為空,search方法檢測一個元素在堆棧中的位置。Stack剛創建后是空棧。
Set接口?
Set是一種不包含重復的元素的Collection,即任意的兩個元素e1和e2都有e1.equals(e2)=false,Set最多有一個null元素。?
很明顯,Set的構造函數有一個約束條件,傳入的Collection參數不能包含重復的元素。?
請注意:必須小心操作可變對象(Mutable Object)。如果一個Set中的可變元素改變了自身狀態導致Object.equals(Object)=true將導致一些問題。
Map接口?
請注意,Map沒有繼承Collection接口,Map提供key到value的映射。一個Map中不能包含相同的key,每個key只能映射一個 value。Map接口提供3種集合的視圖,Map的內容可以被當作一組key集合,一組value集合,或者一組key-value映射。
Hashtable類?
Hashtable繼承Map接口,實現一個key-value映射的哈希表。任何非空(non-null)的對象都可作為key或者value。?
添加數據使用put(key, value),取出數據使用get(key),這兩個基本操作的時間開銷為常數。?
Hashtable通過initial capacity和load factor兩個參數調整性能。通常缺省的load factor 0.75較好地實現了時間和空間的均衡。增大load factor可以節省空間但相應的查找時間將增大,這會影響像get和put這樣的操作。?
使用Hashtable的簡單示例如下,將1,2,3放到Hashtable中,他們的key分別是”one”,”two”,”three”:?
Hashtable numbers = new Hashtable();?
numbers.put(“one”, new Integer(1));?
numbers.put(“two”, new Integer(2));?
numbers.put(“three”, new Integer(3));?
要取出一個數,比如2,用相應的key:?
Integer n = (Integer)numbers.get(“two”);?
System.out.println(“two = ” + n);?
由于作為key的對象將通過計算其散列函數來確定與之對應的value的位置,因此任何作為key的對象都必須實現hashCode和equals方法。hashCode和equals方法繼承自根類Object,如果你用自定義的類當作key的話,要相當小心,按照散列函數的定義,如果兩個對象相同,即obj1.equals(obj2)=true,則它們的hashCode必須相同,但如果兩個對象不同,則它們的hashCode不一定不同,如果兩個不同對象的hashCode相同,這種現象稱為沖突,沖突會導致操作哈希表的時間開銷增大,所以盡量定義好的hashCode()方法,能加快哈希表的操作。?
如果相同的對象有不同的hashCode,對哈希表的操作會出現意想不到的結果(期待的get方法返回null),要避免這種問題,只需要牢記一條:要同時復寫equals方法和hashCode方法,而不要只寫其中一個。?
Hashtable是同步的。
HashMap類?
HashMap和Hashtable類似,不同之處在于HashMap是非同步的,并且允許null,即null value和null key。,但是將HashMap視為Collection時(values()方法可返回Collection),其迭代子操作時間開銷和HashMap 的容量成比例。因此,如果迭代操作的性能相當重要的話,不要將HashMap的初始化容量設得過高,或者load factor過低。
WeakHashMap類?
WeakHashMap是一種改進的HashMap,它對key實行“弱引用”,如果一個key不再被外部所引用,那么該key可以被GC回收。
總結?
如果涉及到堆棧,隊列等操作,應該考慮用List,對于需要快速插入,刪除元素,應該使用LinkedList,如果需要快速隨機訪問元素,應該使用ArrayList。
如果程序在單線程環境中,或者訪問僅僅在一個線程中進行,考慮非同步的類,其效率較高,如果多個線程可能同時操作一個類,應該使用同步的類。?
要特別注意對哈希表的操作,作為key的對象要正確復寫equals和hashCode方法。?
盡量返回接口而非實際的類型,如返回List而非ArrayList,這樣如果以后需要將ArrayList換成LinkedList時,客戶端代碼不用改變。這就是針對抽象編程。
Java 集合類 map set list arraylist hashmap hashtable(轉)
Vector的方法都是同步的(Synchronized),是線程安全的(thread-safe),而ArrayList的方法不是,由于線程的同步必然要影響性能,因此,ArrayList的性能比Vector好。?
當Vector或ArrayList中的元素超過它的初始大小時,Vector會將它的容量翻倍,而ArrayList只增加50%的大小,這樣,ArrayList就有利于節約內存空間。?
Hashtable和HashMap???
它們的性能方面的比較類似 Vector和ArrayList,比如Hashtable的方法是同步的,而HashMap的不是。?
ArrayList和LinkedList???
對 于處理一列數據項,Java提供了兩個類ArrayList和LinkedList,ArrayList的內部實現是基于內部數組Object[],所以 從概念上講,它更象數組,但LinkedList的內部實現是基于一組連接的記錄,所以,它更象一個鏈表結構,所以,它們在性能上有很大的差別。???
(1) 從上面的分析可知,在ArrayList的前面或中間插入數據時,你必須將其后的所有數據相應的后移,這樣必然要花費較多時間,所以,當你的操作是在一列 數據的后面添加數據而不是在前面或中間,并且需要隨機地訪問其中的元素時,使用ArrayList會提供比較好的性能。???
(2)而訪問鏈表中的某個元素時,就必須從鏈表的一端開始沿著連接方向一個一個元素地去查找,直到找到所需的元素為止,所以,當你的操作是在一列數據的前面或中間添加或刪除數據,并且按照順序訪問其中的元素時,就應該使用LinkedList了。???
(3)如果在編程中,1,2兩種情形交替出現,這時,你可以考慮使用List這樣的通用接口,而不用關心具體的實現,在具體的情形下,它的性能由具體的實現來保證。?
設置集合類的初始大小?
在Java 集合框架中的大部分類的大小是可以隨著元素個數的增加而相應的增加的,我們似乎不用關心它的初始大小,但如果我們考慮類的性能問題時,就一定要考慮盡可能 地設置好集合對象的初始大小,這將大大提高代碼的性能,比如,Hashtable缺省的初始大小為101,載入因子為0.75,即如果其中的元素個數超過 75個,它就必須增加大小并重新組織元素,所以,如果你知道在創建一個新的Hashtable對象時就知道元素的確切數目如為110,那么,就應將其初始 大小設為110/0.75=148,這樣,就可以避免重新組織內存并增加大小。?
26、錯誤和異常的區別(Error vs Exception)?
?
1)?java.lang.Error: Throwable的子類,用于標記嚴重錯誤。合理的應用程序不應該去try/catch這種錯誤。絕大多數的錯誤都是非正常的,就根本不該出現的。
java.lang.Exception: Throwable的子類,用于指示一種合理的程序想去catch的條件。即它僅僅是一種程序運行條件,而非嚴重錯誤,并且鼓勵用戶程序去catch它。
?
2)? Error和RuntimeException 及其子類都是未檢查的異常(unchecked exceptions),而所有其他的Exception類都是檢查了的異常(checked exceptions).
checked exceptions:?通常是從一個可以恢復的程序中拋出來的,并且最好能夠從這種異常中使用程序恢復。比如FileNotFoundException, ParseException等。檢查了的異常發生在編譯階段,必須要使用try…catch(或者throws)否則編譯不通過。
unchecked exceptions:?通常是如果一切正常的話本不該發生的異常,但是的確發生了。發生在運行期,具有不確定性,主要是由于程序的邏輯問題所引起的。比如ArrayIndexOutOfBoundException, ClassCastException等。從語言本身的角度講,程序不該去catch這類異常,雖然能夠從諸如RuntimeException這樣的異常中catch并恢復,但是并不鼓勵終端程序員這么做,因為完全沒要必要。因為這類錯誤本身就是bug,應該被修復,出現此類錯誤時程序就應該立即停止執行。 因此,面對Errors和unchecked exceptions應該讓程序自動終止執行,程序員不該做諸如try/catch這樣的事情,而是應該查明原因,修改代碼邏輯。
RuntimeException:RuntimeException體系包括錯誤的類型轉換、數組越界訪問和試圖訪問空指針等等。
處理RuntimeException的原則是:如果出現 RuntimeException,那么一定是程序員的錯誤。例如,可以通過檢查數組下標和數組邊界來避免數組越界訪問異常。其他(IOException等等)checked異常一般是外部錯誤,例如試圖從文件尾后讀取數據等,這并不是程序本身的錯誤,而是在應用環境中出現的外部錯誤。?
?
Java的線程是通過java.lang.Thread類來實現的。VM啟動時會有一個由主方法所定義的線程。可以通過創建Thread的實例來創建新的線程。每個線程都是通過某個特定Thread對象所對應的方法run()來完成其操作的,方法run()稱為線程體。通過調用Thread類的start()方法來啟動一個線程。
在Java當中,線程通常都有五種狀態,創建、就緒、運行、阻塞和死亡。
第一是創建狀態。在生成線程對象,并沒有調用該對象的start方法,這是線程處于創建狀態。
第二是就緒狀態。當調用了線程對象的start方法之后,該線程就進入了就緒狀態,但是此時線程調度程序還沒有把該線程設置為當前線程,此時處于就緒狀態。在線程運行之后,從等待或者睡眠中回來之后,也會處于就緒狀態。
第三是運行狀態。線程調度程序將處于就緒狀態的線程設置為當前線程,此時線程就進入了運行狀態,開始運行run函數當中的代碼。
第四是阻塞狀態。線程正在運行的時候,被暫停,通常是為了等待某個時間的發生(比如說某項資源就緒)之后再繼續運行。sleep,suspend,wait等方法都可以導致線程阻塞。
第五是死亡狀態。如果一個線程的run方法執行結束或者調用stop方法后,該線程就會死亡。對于已經死亡的線程,無法再使用start方法令其進入就緒。
1、寫一個類繼承自Thread類,重寫run方法。用start方法啟動線程
Thread Test = new Thread();
Test.start();
2、寫一個類實現Runnable接口,實現run方法。用new Thread(Runnable target).start()方法來啟動Test impelements Runnable;
Test t = new Test();
Thread test = new Thread(t);
test.start();
?
start()和run()方法的區別
1) start:
用start方法來啟動線程,真正實現了多線程運行,這時無需等待run方法體代碼執行完畢而直接繼續執行下面的代碼。通過調用Thread類的 start()方法來啟動一個線程,這時此線程處于就緒(可運行)狀態,并沒有運行,一旦得到cpu時間片,就開始執行run()方法,這里方法 run()稱為線程體,它包含了要執行的這個線程的內容,Run方法運行結束,此線程隨即終止。
2) run:
run()方法只是類的一個普通方法而已,如果直接調用Run方法,程序中依然只有主線程這一個線程,其程序執行路徑還是只有一條,還是要順序執行,還是要等待run方法體執行完畢后才可繼續執行下面的代碼,這樣就沒有達到寫線程的目的。
總結:調用start方法方可啟動線程,而run方法只是thread的一個普通方法調用,還是在主線程里執行。
這兩個方法應該都比較熟悉,把需要并行處理的代碼放在run()方法中,start()方法啟動線程將自動調用 run()方法,這是由jvm的內存機制規定的。并且run()方法必須是public訪問權限,返回值類型為void。
答案:不能
解析:volatile關鍵字用在多線程同步中,可保證讀取的可見性,JVM只是保證從主內存加載到線程工作內存的值是最新的讀取值,而非cache中。但多個線程對
volatile的寫操作,無法保證線程安全。例如假如線程1,線程2 在進行read,load 操作中,發現主內存中count的值都是5,那么都會加載這個最新的值,在線程1堆count進行修改之后,會write到主內存中,主內存中的count變量就會變為6;線程2由于已經進行read,load操作,在進行運算之后,也會更新主內存count的變量值為6;導致兩個線程及時用volatile關鍵字修改之后,還是會存在并發的情況。
A 是 ? ? B 否
答案:A
解析:Java創建對象的幾種方式(重要):
(1) 用new語句創建對象,這是最常見的創建對象的方法。
(2) 運用反射手段,調用java.lang.Class或者java.lang.reflect.Constructor類的newInstance()實例方法。
(3) 調用對象的clone()方法。
(4) 運用反序列化手段,調用java.io.ObjectInputStream對象的 readObject()方法。
(1)和(2)都會明確的顯式的調用構造函數 ;(3)是在內存上對已有對象的影印,所以不會調用構造函數 ;(4)是從文件中還原類的對象,也不會調用構造函數。
31、
下面哪些是對稱加密算法()
A DES ? B AES ? C DSA ? D RSA
答案:AB
解析:常用的對稱加密算法有:DES、3DES、RC2、RC4、AES
常用的非對稱加密算法有:RSA、DSA、ECC
使用單向散列函數的加密算法:MD5、SHA
32、抽象類和接口
?
抽象類遵循的原則:
?
?
?
?
?
?
?
?
(1)接口是公開的,里面不能有私有的方法或變量,是用于讓別人使用的,而抽象類是可以有私有方法或私有變量的。
(2)abstract class 在 Java 語言中表示的是一種繼承關系,一個類只能使用一次繼承關系。但是,一個類卻可以實現多個interface,實現多重繼承。接口還有標識(里面沒有任何方法,如Remote接口)和數據共享(里面的變量全是常量)的作用。
(3)在abstract class 中可以有自己的數據成員,也可以有非abstarct的成員方法,而在interface中,只能夠有靜態的不能被修改的數據成員(也就是必須是 static final的,不過在 interface中一般不定義數據成員),所有的成員方法默認都是 public abstract 類型的。
(4)abstract class和interface所反映出的設計理念不同。其實abstract class表示的是"is-a"關系,interface表示的是"has-a"關系。
(5)實現接口的一定要實現接口里定義的所有方法,而實現抽象類可以有選擇地重寫需要用到的方法,一般的應用里,最頂級的是接口,然后是抽象類實現接口,最后才到具體類實現。抽象類中可以有非抽象方法。接口中則不能有實現方法。
(6)接口中定義的變量默認是public static final 型,且必須給其初值,所以實現類中不能重新定義,也不能改變其值。抽象類中的變量默認是 friendly 型,其值可以在子類中重新定義,也可以在子類中重新賦值。
Java提供和支持創建抽象類和接口。它們的實現有共同點,不同點在于:
- 接口中所有的方法隱含的都是抽象的。而抽象類則可以同時包含抽象和非抽象的方法。
- 類可以實現很多個接口,但是只能繼承一個抽象類
- 類如果要實現一個接口,它必須要實現接口聲明的所有方法。但是,類可以不實現抽象類聲明的所有方法,當然,在這種情況下,類也必須得聲明成是抽象的。
- 抽象類可以在不提供接口方法實現的情況下實現接口。
- Java接口中聲明的變量默認都是final的。抽象類可以包含非final的變量。
- Java接口中的成員函數默認是public的。抽象類的成員函數可以是private,protected或者是public。
- 接口是絕對抽象的,不可以被實例化。抽象類也不可以被實例化,但是,如果它包含main方法的話是可以被調用的。
33、同步方法和同步代碼塊的區別是什么?
在Java語言中,每一個對象有一把鎖。線程可以使用synchronized關鍵字來獲取對象上的鎖。synchronized關鍵字可應用在方法級別(粗粒度鎖)或者是代碼塊級別(細粒度鎖)。
34、如何確保N個線程可以訪問N個資源同時又不導致死鎖?
使用多線程的時候,一種非常簡單的避免死鎖的方式就是:指定獲取鎖的順序,并強制線程按照指定的順序獲取鎖。因此,如果所有的線程都是以同樣的順序加鎖和釋放鎖,就不會出現死鎖了。
35、數組(Array)和列表(ArrayList)有什么區別?什么時候應該使用Array而不是ArrayList?
?
下面列出了Array和ArrayList的不同點:
?
- Array可以包含基本類型和對象類型,ArrayList只能包含對象類型。
- Array大小是固定的,ArrayList的大小是動態變化的。
- ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。
- 對于基本類型數據,集合使用自動裝箱來減少編碼工作量。但是,當處理固定大小的基本數據類型的時候,這種方式相對比較慢。
?
ArrayList和LinkedList有什么區別?
?
ArrayList和LinkedList都實現了List接口,他們有以下的不同點:
?
-
ArrayList是基于索引的數據接口,它的底層是數組。它可以以O(1)時間復雜度對元素進行隨機訪問。與此對應,LinkedList是以元素列表的形式存儲它的數據,每一個元素都和它的前一個和后一個元素鏈接在一起,在這種情況下,查找某個元素的時間復雜度是O(n)。
-
相對于ArrayList,LinkedList的插入,添加,刪除操作速度更快,因為當元素被添加到集合任意位置的時候,不需要像數組那樣重新計算大小或者是更新索引。
-
LinkedList比ArrayList更占內存,因為LinkedList為每一個節點存儲了兩個引用,一個指向前一個元素,一個指向下一個元素。
?
36、多線程的安全問題
? ? ?總結來說,多個線程在執行同一段代碼的時候,每次的執行結果和單線程執行的結果都是一樣的,不存在執行結果的二義性,就可以稱作是線程安全的。線程安全問?題多是由全局變量和靜態變量引起的,當多個線程對共享數據只執行讀操作,不執行寫操作時,一般是線程安全的;當多個線程都執行寫操作時,需要考慮線程同步來解決線程安全問題。
? ? ?說明Java線程的兩個特性,可見性和有序性。多個線程之間是不能直接傳遞數據交互的,它們之間的交互只能通過共享變量來實現。
? ? ?java允許多線程并發控制,當多個線程同時操作一個可共享的資源變量時(如數據的增刪改查),將會導致數據不準確,相互之間產生沖突,因此加入同步鎖以避免在該線程沒有完成操作之前,被其他線程的調用,?從而保證了該變量的唯一性和準確性
37、java常見的數據類型是什么和對應的包裝類是什么?java的隱式類型?assert什么時候使用?
(1)int,?double,?float,?long,?short,?boolean,?byte,?char
(2)Integer.Double,Float,Long,Short,Boolean,Byte,Characher.
(3)java的隱式類型是int,byte,short,char都可以隱含轉換為int?
(4)一般來說,assertion用于保證程序最基本、關鍵的正確性。assertion檢查通常在開發和測試時開啟。為了提高性能,在軟件發布后,assertion檢查通常是關閉的;
38、線程中sleep和wait的區別
?
(1)這兩個方法來自不同的類分別是,sleep來自Thread類,和wait來自Object類;sleep是Thread的靜態類方法,誰調用的誰去睡覺,即使在a線程里調用了b的sleep方法,實際上還是a去睡覺,要讓b線程睡覺要在b的代碼中調用sleep。
?
(2)最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其他線程可以使用同步控制塊或者方法。sleep不出讓系統資源;wait是進入線程等待池等待,出讓系統資源,其他線程可以占用CPU。一般wait不會加時間限制,因為如果wait線程的運行資源不夠,再出來也沒用,要等待其他線程調用notify/notifyAll喚醒等待池中的所有線程,才會進入就緒隊列等待OS分配系統資源。?sleep(milliseconds)可以用時間指定使它自動喚醒過來,如果時間不到只能調用interrupt()強行打斷;
?
39、string、stringbuffer和stringbuilder的區別?哪個更安全?為什么?hashmap為什么查詢的比較快?
?
(1)JAVA平臺提供了兩個類:String和StringBuffer,它們可以儲存和操作字符串,即包含多個字符的字符數據。這個String類提供了數值不可改變的字符串。而這個StringBuffer類提供的字符串進行修改。當你知道字符數據要改變的時候你就可以使用StringBuffer。典型地,你可以使用StringBuffer來動態構造字符數據。另外,String實現了equals方法;而StringBuffer沒有實現equals方法,所以,new?StringBuffer(“abc”).equals(new?StringBuffer(“abc”)的結果為false。
?
(2)StringBuffer線程安全的可變字符序列。一個類似于?String?的字符串緩沖區,但不能修改;通過某些方法調用可以改變該序列的長度和內容,可將字符串緩沖區安全地用于多個線程。可以在必要時對這些方法進行同步,因此任意特定實例上的所有操作就好像是以串行順序發生的,該順序與所涉及的每個線程進行的方法調用順序一致;
?
(3)StringBuilder一個可變的字符序列。此類提供一個與?StringBuffer?兼容的?API,但不保證同步。該類被設計用作?StringBuffer?的一個簡易替換,用在字符串緩沖區被單個線程使用的時候(這種情況很普遍)。(如果可能,建議優先采用該類,因為在大多數實現中,它比?StringBuffer?要快。但將?StringBuilder?的實例用于多個線程是不安全的。如果需要這樣的同步,則建議使用?StringBuffer。);
?
(4)HashMap是Hashtable的輕量級實現(非同步非線程安全的實現),他們都完成了Map接口,主要區別在于HashMap允許空(null)鍵值(key),由于非線程安全,在只有一個線程訪問的情況下,效率要高于Hashtable。
?
40、hibernat和mybaitis的優勢和區別?haibernate的緩存機制有沒有了解過?如何使用hibernate將數據永久保存到數據庫中?mybaitates是如何實現查詢的?hibernate有很多數據操作時候如何優化?
?
? ?(1)mybaitis的優勢:
·??MyBatis可以進行更為細致的SQL優化,可以減少查詢字段。
·??MyBatis容易掌握,而Hibernate門檻較高。
?
???(2)hibernate的優勢:
·??Hibernate的DAO層開發比MyBatis簡單,Mybatis需要維護SQL和結果映射;
·??Hibernate對對象的維護和緩存要比MyBatis好,對增刪改查的對象的維護要方便;
·??Hibernate數據庫移植性很好,MyBatis的數據庫移植性不好,不同的數據庫需要寫不同SQL。
·??Hibernate有更好的二級緩存機制,可以使用第三方緩存。MyBatis本身提供的緩存機制不佳。
?
???(3)區別:Hibernate功能強大,數據庫無關性好,O/R映射能力強,如果你對Hibernate相當精通,而且對Hibernate進行了適當的封裝,那么你的項目整個持久層代碼會相當簡單,需要寫的代碼很少,開發速度很快,非常爽。·??iBATIS入門簡單,即學即用,提供了數據庫查詢的自動對象綁定功能,而且延續了很好的SQL使用經驗,對于沒有那么高的對象模型要求的項目來說,相當完美。
?
??(4)Hibernate一級緩存是Session緩存,利用好一級緩存就需要對Session的生命周期進行管理好。建議在一個Action操作中使用一個Session。一級緩存需要對Session進行嚴格管理。Hibernate二級緩存是SessionFactory級的緩存。?SessionFactory的緩存分為內置緩存和外置緩存。內置緩存中存放的是SessionFactory對象的一些集合屬性包含的數據(映射元素據及預定SQL語句等),對于應用程序來說,它是只讀的。外置緩存中存放的是數據庫數據的副本,其作用和一級緩存類似.二級緩存除了以內存作為存儲介質外,還可以選用硬盤等外部存儲設備。二級緩存稱為進程級緩存或SessionFactory級緩存,它可以被所有session共享,它的生命周期伴隨著SessionFactory的生命周期存在和消亡。
?
??(5)mybatitis的查詢:Mybatis的SQL是手動編寫的,所以可以按需求指定查詢的字段。mybatis是數據映射器(數據映射器層:用于在對象和數據庫之間搬運數據,同時保證對象、數據庫和數據映射器層本身相對獨立。Martin?Fowler?《企業應用架構模式》)把sql語句的參數與結果(即輸入與輸出)映射為類。為如何在類和數據庫間建立映射帶來了更大的靈活性。同時也更好的隔離了數據庫設計和應用程序中使用的對象模型。
?
??(6)hibernate?的持久化:Hibernate采用了更自然的面向對象的視角來持久化?Java?應用中的數據。使用?Hibernate?的開發者應該總是關注對象的狀態(state),不必考慮?SQL?語句的執行。這部分細節已經由?Hibernate?掌管妥當,只有開發者在進行系統性能調優的時候才需要進行了解。
?
???(6)mybatis的調優:MyBatis在Session方面和Hibernate的Session生命周期是一致的,同樣需要合理的Session管理機制。MyBatis同樣具有二級緩存機制。?MyBatis可以進行詳細的SQL優化設計。
?
??(7)hibernate如何實現優化:
·??制定合理的緩存策略;
·??盡量使用延遲加載特性;
·??采用合理的Session管理機制;
·??使用批量抓取,設定合理的批處理參數(batch_size);
·??進行合理的O/R映射設計
?
41、spring、hibernate、Struts的工作原理,為什么使用這些框架?簡單說下struts2中數據傳遞情況??hibernate的三種狀態和彼此的區別?使用hibernate如何分頁?spring的事務隔離級別?ssh如何整合(spring核心流程)?
?
(1)spring的工作原理:
?
I.Spring內部最核心的就是IOC了,動態注入,讓一個對象的創建不用new了,可以自動的生產,這其實就是利用java里的反射,反射其實就是在運行時動態的去創建、調用對象,Spring就是在運行時,根據xml Spring的配置文件來動態的創建對象,和調用對象里的方法。
?
II.Spring工作原理還有一個核心就是Aop這個就是面向切面的編程,可以為某一類對象進行監督和控制(也就是在調用這類對象的具體方法的前后去調用你指定的模塊)從而達到對一個模塊擴充的功能這些都是通過配置類達到的。
?
III.Spring目的:就是讓對象與對象(模塊與模塊)之間的關系沒有通過代碼來關聯,都是通過配置類說明管理的(主要是通過反射機制)。
?
(2)hibernate的工作原理:
?
I.讀取并解析hibernate.cfg.xml配置文件
?
II.讀取并解析映射信息
?
III.創建SessionFactory
?
IV.負責被持久化對象CRUD操作,打開Sesssion
?
V.創建并啟動事務Transation
?
VI.操作數據,持久化操作
?
VII.提交事務,關閉Session,關閉SesstionFactory;
?
(3)struts的工作原理同下:
工作流程:
? ?(1)客戶端提交一個HttpServletRequest請求(action或JSP頁面)。
???(2)請求被提交到一系列Filter過濾器,如ActionCleanUp和FilterDispatcher等。
???(3)FilterDispatcher是Struts2控制器的核心,它通常是過濾器鏈中的最后一個過濾器.
???(4)請求被發送到FilterDispatcher后,FilterDispatcher詢問ActionMapper時候需要調用某個action來處理這個Request。
???(5)如果ActionMapper決定需要調用某個action,FilterDispatcher則把請求交給ActionProxy進行處理.
???(6)ActionProxy通過Configuration?Manager詢問框架的配置文件struts.xml,找到調用的action類。
???(7)ActionProxy創建一個ActionInvocation實例,通過代理模式調用Action。
???(8)action執行完畢后,返回一個result字符串,此時再按相反的順序通過Intercepter攔截器。
???(9)最后ActionInvocation實例,負責根據struts.xml中配置result元素,找到與之相對應的result,決定進一步輸出。
簡要基本流程:
I.客戶端瀏覽器發出HTTP請求。II.根據web.xml配置,該請求被FilterDispatcher接收。III.根據struts.xml配置,找到需要調用的Action類和方法,?并通過IoC方式,將值注入給Aciton。IV.Action調用業務邏輯組件處理業務邏輯,這一步包含表單驗證。V.Action執行完畢,根據struts.xml中的配置找到對應的返回結果result,并跳轉到相應頁面。VI.返回HTTP響應到客戶端瀏覽器。
?
(4)使用原因:
?
struts是開源軟件。使用Struts的目的是為了幫助我們減少在運用MVC設計模型來開發Web應用的時間。如果我們想混合使用Servlets和JSP的優點來建立可擴展的應用,struts是一個不錯的選擇。
?
Hibernate是一個開放源代碼的對象關系映射框架,它對JDBC進行了非常輕量級的對象封裝,使得Java程序員可以隨心所欲的使用對象編程思維來操縱數據庫。?Hibernate可以應用在任何使用JDBC的場合,既可以在Java的客戶端程序使用,也可以在Servlet/JSP的Web應用中使用,最具革命意義的是,Hibernate可以在應用EJB的J2EE架構中取代CMP,完成數據持久化的重任;
?
Spring:Spring是一個開源框架,它是為了解決企業應用開發的復雜性而創建的。Spring使用基本的JavaBean來完成以前只可能由EJB完成的事情。然而,Spring的用途不僅限于服務器端的開發。從簡單性、可測試性和松耦合的角度而言,任何Java應用都可以從Spring中受益.
?
(5)struts數據傳遞:可以直接基于應用程序域對象轉移,驗證數據,數據綁定,動作把從請求接收到的所有數據放在簡單的JavaBean上。除了單獨接受每個數?據,struts2最優雅的地方時可以創建一個對象來放置這些瑣碎的數據,我們可以把復雜對象本身提供給平臺的數據轉移機制。這不但節省時間,而且也能節?省工作量。
?
(6)hibernate的三種狀態和區別:
?
瞬時(transient):也叫自由狀態.數據庫中沒有數據與之對應,超過作用域會被JVM垃圾回收器回收,一般是new出來且與session沒有關聯的對象。
?
持久(persistent):數據庫中可能有數據與之對應(save),當前與session有關聯,并且相關聯的session沒有關閉,事務沒有提交;持久對象狀態發生改變,在事務提交時會影響到數據庫(hibernate能檢測到)。
?
脫管(detached):也叫游離狀態.數據庫中可能有數據與之對應,但當前沒有session與之關聯,但是有oid;托管對象狀態發生改變,hibernate不能檢測到。
?
區別:Transient狀態的實體缺乏與數據庫表記錄之間的聯系,而Detached狀態的實體恰恰相反.只不過是脫離了session這個數據庫操作平臺而已.
?
(7)hibernate分頁:1.HQL查詢:Query?query=session.createQuery(from?實體類);2.從第幾條開始:query.setFirstResult(mini);3.每次最多提取多少條數據:query.setMaxResults(max);接收返回的結果集:List<實體類>?HousesList=query.list();
?
代碼如下(Query?query?=?session.createQuery(hql);??
query.setParameter(0,?userId); ?
query.setMaxResults(maxCount); ?
query.setFirstResult(firstResult); ?
return?query.list();
)
(8)ssh整合步驟:
?
1.導入struts2的jar包以及struts2-spring-plugin-2.0.11.2.jar;?
?
2.在web.xml中分別配置struts2與spring相關信息;
?
3.struts中原有的Action需要繼承ActionSupport;
?
4.在Spring配置Action?Bean;
?
5.在Struts2的配置文件中,調用Spring中配置的Bean;
?
6.Spring與Hibernate整合,只需要在Spring配置文件配置SessionFactory即可
?
(9)Spring的隔離級別:Default默認的事務隔離級別
?
READ_UNCOMMITTED讀未提交,一個事務可以操作另外一個未提交的事務,不能避免臟讀,不可重復讀,幻讀,隔離級別最低,并發性?能最高
?
READ_COMMITTED讀已提交,一個事務不可以操作另外一個未提交的事務,?能防止臟讀,不能避免不可重復讀,幻讀。
?
repeatable_read能夠避免臟讀,不可重復讀,不能避免幻讀
?
SERIALIZABLE隔離級別最高,消耗資源最低,代價最高,能夠防止臟讀,?不可重復讀,幻讀。
?
42、談談Spring和Spring?MVC的流程和事務;spring配置文件都寫什么?
?
(1)spring提供兩種管理事務的方式:一種是聲明式事務,一種是編程式事務。
?
Spring的聲明式事務管理,基于Spring的AOP,基于Spring?AOP實現,幾乎就是xml文件的配置,不再需要不停地寫commit,rollback,(但Spring仍然沒有放棄編程式的事務管理策略)。
?
Spring的編程式事務管理,統一的事務編碼風格,幾乎是一個模板化的。
?
為我們提供了一個TransactionTemplate,使用回調機制,將應用代碼從樣板式的資源獲取和釋放代碼中解放出來,不再有大量的try/catch/finally/try/catch代碼塊
(2)springMVC的流程和事務:動態注入,讓一個對象的創建不用new了,可以自動的生產,這其實就是利用java里的反射?,反射其實就是在運行時動態的去創建、調用對象,Spring就是在運行時,跟xml?Spring的配置文件來動態的創建對象,和調用對象里的方法的?。
?
Spring還有一個核心就是AOP這個就是面向切面編程,可以為某一類對象?進行監督和控制(也就是在調用這類對象的具體方法的前后去調用你指定的?模塊)從而達到對一個模塊擴充的功能。這些都是通過?配置類達到的。Spring目的:就是讓對象與對象(模塊與模塊)之間的關系沒有通過代碼來關聯,都是通過配置類說明管理的(Spring根據這些配置?內部通過反射去動態的組裝對象)?
要記住:Spring是一個容器,凡是在容器里的對象才會有Spring所提供的這些服務和功能。
?
(3)spring的配置文件:一、引用外部屬性文件;二、常用數據源的配置;三、配置事務管理器;四、context:component-scan<!--?對包中的所有類進行掃描,以完成Bean創建和自動依賴注入的功能?-->;五、aop注解支持;六、緩存配置;七、<!--?Spring、MyBatis的整合,需要在?Spring?應用上下文中定義至少兩樣東西:一個SqlSessionFactory和至少一個數據映射器類(UserMapper->iocContext.xml)。?-->;
?
43、SSH和SSM的區別
?
(1)基于MVC三層架構,使用ssh框架?or?ssm框架?or?ssi框架,采用面向接口的方式編程。
共同點是struts、spring,不同點是hibernate和mybatis、ibatis。
?
(2)相對Hibernate“O/R”而言,iBATIS?是一種“Sql?Mapping”的ORM實現。
?
(3)由于hibernate是完全面向對象的編程,在實現dao中就非常的方便,而且不重復;當mybatis在.java代碼中也是可以做到不重復,麻煩一點的是,每個映射文件都必須編寫幾乎相同的配置,除了resultType不一樣。
?
(4)hibernate在實際編程中可以把基礎的CRUD封裝,比如BaseDao類。其它類只要去繼承BaseDao就能執行所有的基礎的CRUD。這樣就非常方便。這個帶來的好處還有,可以建立BaseService和BaseAction。?
?
由于mybatis的映射文件中,雖然SQL語句中的表名可以通過parameterType指定,但是resultType必須定死,不能以參數?的形式給予指定。導致的結果就是所有的DAO類的每個CRUD都必須和指定的映射文件綁定在一起,以至于不可能存在BaseDao類。當然也就不能建立?BaseService和BaseAction。
?
44、數據庫對象關系映射
1.對“對象關系映射”的理解
[java]
Department?
int
id;?
String
name
;?
Set
employees=new HashSet();?
??
?Employee?
int
id;?
String
name
;?
Department dept;
?
[sql]
create
department(?
id
int
primary
key
,?
name
varchar
(20)?
);?
[sql]
create
employee(?
id
int
primary
key
,?
name
varchar
(20),?
dept_id
int
,?
constraint
dept_id_FK
foreign
key
(dept_id)
references
department(id)?
);
[java]
Teacher?
int
id;?
String
name
;?
Set
students=new HashSet();?
??
?Student?
int
id;?
String
name
;?
Set
teachers=new HashSet();
[sql]
create
table
teacher(?
id
int
primary
key
,?
name
varchar
(20)?
);?
create
table
student(?
id
int
primary
key
,?
name
varchar
(20)?
);
?
[sql]
create
table
student_teacher(?
student_id
int
,?
teacher_id
int
,?
constraint
student_teacher_PK
primary
key
(student_id,teacher_id),?
constraint
student_id_FK
foreign
key
(student_id)
references
student(id),?
constraint
teacher_id_FK
foreign
key
(teacher_id)
references
teacher(id)?
);
[java]
Person?
int
id;?
String
name
;?
IdCard ic;?
??
?IdCard?
int
id;?
String address;
[sql]
create
table
person(?
id
int
primary
key
,?
name
varchar
(20)?
);?
??
?create
table
idcard(?
id
int
primary
key
,?
address
varchar
(40),?
constraint
id_FK
foreign
key
(id)
references
person(id)?
);
?注:對于一對一關系的兩張表,分主表與從表,從表的存在必須依賴于主表,主表可以不依賴于從表。從表的設計上其主鍵字段同時也是外鍵字段。
?備注:有時在設計表時,會特意把兩張表合在一張表中,雖然會造成數據冗余,但是卻可以不因為聯表查詢而造成查詢性能有所降低。這是用空間來換時間的做法。
線程安全?
如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變量的值也和預期的是一樣的,就是線程安全的。 或者說:一個類或者程序所提供的接口對于線程來說是原子操作或者多個線程之間的切換不會導致該接口的執行結果存在二義性,也就是說我們不用考慮同步的問題。 線程安全問題都是由全局變量及靜態變量引起的。??
若每個線程中對全局變量、靜態變量只有讀操作,而無寫操作,一般來說,這個全局變量是線程安全的;若有多個線程同時執行寫操作,一般都需要考慮線程同步,否則就可能影響線程安全。
?
關于線程安全:
?
1)?常量始終是線程安全的,因為只存在讀操作。?
?
2)每次調用方法前都新建一個實例是線程安全的,因為不會訪問共享的資源。
?
3)局部變量是線程安全的。因為每執行一個方法,都會在獨立的空間創建局部變量,它不是共享的資源。局部變量包括方法的參數變量和方法內變量。?
有狀態和無狀態對象
有狀態就是有數據存儲功能。有狀態對象(Stateful Bean),就是有實例變量的對象??,可以保存數據,是非線程安全的。在不同方法調用間不保留任何狀態。
無狀態就是一次操作,不能保存數據。無狀態對象(Stateless Bean),就是沒有實例變量的對象??.不能保存數據,是不變類,是線程安全的。
?
無狀態對象一般沒有實例變量,或者有實例變量,不能改寫,如private的,對外只暴露只讀操作,無寫操作。
?
單例類可以是有狀態的(stateful),也可以是無狀態的。無狀態的單例模式,是線程安全的。有狀態的單例模式,是非線程安全的。
?
?spring中的有狀態(Stateful)和無狀態(Stateless) ??
1.通過上面的分析,相信大家已經對有狀態和無狀態有了一定的理解。無狀態的Bean適合用不變模式,技術就是單例模式,這樣可以共享實例,提高性能。有狀態的Bean,多線程環境下不安全,那么適合用Prototype原型模式。Prototype: 每次對bean的請求都會創建一個新的bean實例。
2.默認情況下,從Spring bean工廠所取得的實例為singleton(scope屬性為singleton),容器只存在一個共享的bean實例。
3.理解了兩者的關系,那么scope選擇的原則就很容易了:有狀態的bean都使用prototype作用域,而對無狀態的bean則應該使用singleton作用域。
4.如Service層、Dao層用默認singleton就行,雖然Service類也有dao這樣的屬性,但dao這些類都是沒有狀態信息的,也就是 相當于不變(immutable)類,所以不影響。Struts2中的Action因為會有User、BizEntity這樣的實例對象,是有狀態信息 的,在多線程環境下是不安全的,所以Struts2默認的實現是Prototype模式。在Spring中,Struts2的Action中,scope 要配成prototype作用域。
?
46、
47、
48、
49、
50、
?
?