java初中級面試題(最新版)


Java基礎方面:

概念

1、什么是面向對象?

萬物皆對象,把現實中有共同特性行為的對象抽象成類,類是程序中最基本的單位。

2、類和對象

面向對象的思想是如何在java展現的呢? 就是通過類和對象

*類是 一組相關的屬性和行為的集合。是一個抽象的概念。

*對象 是該類事物的具體表現形式。具體存在的個體。

類是對象的抽象,對象是類的實例。

*成員變量 事物的屬性

*成員方法 事物的行為

3、java是如何實現跨平台的?

Java的跨平台是通過Java虛擬機JVM來實現的。不同的平台需要安裝不同的虛擬機,java程序編譯之后的代碼不是能被硬件系統直接運行的代碼,而是一種“中間碼”——字節碼。然后不同的硬件平台上安裝有不同的Java虛擬機(JVM),由JVM來把字節碼再“翻譯”成所對應的硬件平台能夠執行的代碼。

4、JRE,JDK和JVM之間的關系

JDK包含JRE,JRE包含JVM

JRE(JavaRuntimeEnvironment,Java運行環境),也就是Java平台。所有的Java 程序都要在JRE下才能運行。普通用戶只需要運行已開發好的java程序,安裝JRE即可。

JDK(Java Development Kit)是程序開發者用來來編譯、調試java程序用的開發工具包。JDK的工具也是Java程序,也需要JRE才能運行。jre是jdk的一部分。為了保持JDK的獨立性和完整性,在JDK的安裝過程中,JRE也是 安裝的一部分。所以,在JDK的安裝目錄下有一個名為jre的目錄,用於存放JRE文件。

JVM(JavaVirtualMachine,Java虛擬機)是JRE的一部分。它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現的。JVM有自己完善的硬件架構,如處理器、堆棧、寄存器等,還具有相應的指令系統。Java語言最重要的特點就是跨平台運行。使用JVM就是為了支持與操作系統無關,實現跨平台。

5、GC是什么? 為什么要有GC

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

6、面向對象的特征有哪些方面

   主要有以下四方面:

1.抽象:抽象就是找出一些事物的相似和共性之處,然后將這些事物歸為一個類,這個類只考慮這些事物的相似和共性之處。抽象包括兩個方面,一是過程抽象,二是數據抽象。

2.繼承:子類繼承父類,子類共享父類屬性和方法的同時可以擴展自己的屬性和方法。提高了軟件的可重用性和可擴展性                      。

3.封裝:把對象的屬性和方法結合成一個整體,並隱藏內部的實現細節,提供對外的訪問接口。

4. 多態性:不同對象對同一消息做出不同的響應處理,主要實現:子類繼承父類,子類重寫父類的方法,父類的引用指向子類的對象。

 7、對象和面向過程的區別

面向過程

       優點:性能比面向對象高,因為類調用時需要實例化,開銷比較大,比較消耗資源;比如單片機、嵌入式開發、Linux/Unix等一般采用面向過程開發,性能是最重要的因素。

       缺點:沒有面向對象易維護、易復用、易擴展

面向對象

       優點:易維護、易復用、易擴展,由於面向對象有封裝、繼承、多態性的特性,可以設計出低耦合的系統,使系統更加靈活、更加易於維護

       缺點:性能比面向過程低

語法

7、作用域public,private,protected,以及不寫時的區別

   區別如下:

作用域           當前類       同一package  子孫類       其他package

public            √              √          √             √

protected         √              √           √            ×

friendly          √              √           ×            ×

private           √              ×           ×            ×

不寫時默認為friendly

8、&和&&的區別

   &:”與”是位運算符,表示按位與運算,左邊是false右邊還執行。&&:”並且”是邏輯運算符,表示邏輯與(and),左邊是true右邊才執行

9、什么時候用assert

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

       默認是關閉的,一般是測試的junit中用,判斷結果和自己的預想值是否一致。

10、Java有沒有goto

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

11、是否可以繼承String類

   String類是final類故不可以繼承,final是最終的。

12、try {}里有一個return語句,那么緊跟在這個try后的finally {}里的code會不會被執行,什么時候被執行,在return前還是后

   會執行,在return前執行

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

   2 << 3:表示2向左移3位,因為一個數左移 n位,就相當於 2的 n次方,那么一個數乘以 8只要將其左移 3位即可,而為運算符的效率最高,所以 2乘以 8等於幾的最有效方法是 2<<3

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

   不對,有相同的hash code,因為equals比較hash code值相同才會返回true

15、當一個對象被當作參數傳遞到一個方法后,此方法可改變這個對象的屬性,並可返回變化后的結果,那么這里到底是值傳遞還是引用傳遞

   是值傳遞。Java 編程語言只有值傳遞參數。

*值傳遞:是對所傳遞參數進行一次副本拷貝,對參數的修改只是對副本的修改,函數調用結束,副本丟棄,原來的變量不變(即實參不變),基本數據類型都是值傳遞。

*引用傳遞:參數被傳遞到函數時,不復制副本,而是直接將參數自身傳入到函數,函數內對參數的任何改變都將反映到原來的變量上。

*對於基本類型,傳遞的是基本類型的值,而對於引用類型傳遞的是地址。

16、swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上

   在Java 5以前,switch(expr)中,expr只能是byte、short、char、int。從Java 5開始,Java中引入了枚舉類型,expr也可以是enum類型,從Java 7開始,expr還可以是字符串(String),但是長整型(long)在目前所有的版本中都是不可以的。

17、String、StringBuffer和StringBuilder區別

String 是被final修飾的,長度是不可變的。StringBuffer和StringBuilder長度都是可變的

三者在執行速度方面的比較:StringBuilder > StringBuffer > String

如果要操作少量的數據用 String

單線程操作字符串緩沖區 下操作大量數據 = StringBuilder

多線程操作字符串緩沖區 下操作大量數據 = StringBuffer

StringBuffer是線程安全的有鎖,StringBuilder是線程不安全的,string是線程安全的因為final最終的。如果最后需要String,那么使用StringBuffer的toString()方法

18、談談final, finally, finalize的區別

   final—用於聲明屬性、類和方法,分別表示屬性不可變,方法不可覆蓋(重寫),類不可被繼承

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

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

19、heap和stack有什么區別

   棧是一種線形集合,其添加和刪除元素的操作應在同一段完成。棧按照先進后出的方式進行處理。棧是堆得組成元素,內存由堆,棧,池組成。堆是按照先進先出的原則。棧的空間由系統自動分配,堆的空間可以自己分配。

棧相當於你往泡菜壇子里裝泡菜,從里面拿泡菜,先拿到的當然是上面的。也就是先進后出。堆(隊列)相當於一個隧道,火車往里面開,不能回頭,頭先進去當然也先出來,這叫先進先出。

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

   Java語言中一個顯著的特點就是引入了垃圾回收機制,垃圾回收可以有效的防止內存泄露,有效的使用可以使用的內存。

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

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

*分代復制垃圾回收:根據對象的生命周期不同,分為年輕代、年老代、持久代,分區回收。

*標記垃圾回收:一、標記階段,標記所有可訪問對象;二、收集階段,標記垃圾回收算法回收首頁未標記的對象,在此過程中會出現程序無響應。

*增量垃圾回收:主要是為了解決標記垃圾回收時長停頓的問題,設置GC最多中斷的時間10ms,分時間段來回收垃圾。

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

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

1.裝載:查找和導入class文件;new對象隱式裝載,反射類顯示裝載,看log日志就知道什么是隱式/顯式

2.連接:

      (1)檢查:檢查載入的class文件數據的正確性;

      (2)准備:為類的靜態變量分配存儲空間;

      (3)解析:將符號引用轉換成直接引用(這一步是可選的)

3.初始化:初始化靜態變量,靜態代碼塊。

      這樣的過程在程序調用類的靜態成員的時候開始執行,所以靜態方法main()才會成為一般程序的入口方法。類的構造器也會引發該動作。

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

   可以。只有一個public類,並且類名與文件名相同。

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

內存泄漏是指不再被使用的對象或者變量一直被占據在內存中。檢查java中的內存泄露,一定要讓程序將各種分支情況都完整執行到程序結束,然后看某個對象是否被使用過,如果沒有,則才能判定這個對象屬於內存泄露。

   會。長生命周期的對象持有短生命周期對象的引用就有可能發生內存泄露。比如像加載了一個對象放在緩存中而一直沒有引用。

24、內存溢出和內存泄漏的區別

系統已經不能再分配出你所需要的空間,比如你需要100M的空間,系統只剩90M了,這就叫內存溢出。

內存泄露是對象沒有引用的時候沒有被回收,一直占據着內存。

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

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

26、如何避免內存泄漏、溢出

1、盡早釋放無用對象的引用
好的辦法是使用臨時變量的時候,讓引用變量在推出活動域后自動設置為null,暗示垃圾收集器來收集該對象,防止發生內存泄漏。

2、程序進行字符串處理時,盡量避免使用String,而應該使用StringBuffer。
因為String類是不可變的,每一個String對象都會獨立占用內存一塊區域。

3、盡量少用靜態變量
因為靜態變量是全局的,存在方法區,GC不會回收。(用永久代實現的方法區,垃圾回收行為在這個區域是比較少出現的,垃圾回收器的主要目標是針對常量池和類型的卸載)

4、避免集中創建對象,尤其是大對象,如果可以的話盡量使用流操作
JVM會突然需要大量neicun,這時會出發GC優化系統內存環境

5、盡量運用對象池技術以提高系統性能
生命周期長的對象擁有生命周期短的對象時容易引發內存泄漏,例如大集合對象擁有大數據量的業務對象的時候,可以考慮分塊進行處理,然后解決一塊釋放一塊的策略。

6、不要在經常調用的方法中創建對象,尤其忌諱在循環中創建對象
可以適當的使用hashtable,vector創建一組對象容器,然后從容器中去取這些對象,而不用每次new之后又丟棄。

7、優化配置

Java 內存溢出java.lang.OutOfMemoryError這個錯誤我相信大部分開發人員都有遇到過,產生該錯誤的原因大都出於以下原因:JVM內存過小、程序不嚴密,產生了過多的垃圾。

導致OutOfMemoryError異常的常見原因有以下幾種:

內存中加載的數據量過於龐大,如一次從數據庫取出過多數據;

集合類中有對對象的引用,使用完后未清空,使得JVM不能回收;

代碼中存在死循環或循環產生過多重復的對象實體;

使用的第三方軟件中的BUG;

啟動參數內存值設定的過小;

一、增加jvm的內存大小。方法有:

1)在執行某個class文件時候,可以使用java -Xmx256M aa.class來設置運行aa.class時jvm所允許占用的最大內存為256M。

2)對tomcat容器,可以在啟動時對jvm設置內存限度。對tomcat,可以在catalina.bat中添加:

set CATALINA_OPTS=-Xms128M -Xmx256M

set JAVA_OPTS=-Xms128M -Xmx256M

或者把%CATALINA_OPTS%和%JAVA_OPTS%代替為-Xms128M -Xmx256M

3)對resin容器,同樣可以在啟動時對jvm設置內存限度。在bin文件夾下創建一個startup.bat文件,內容如下:

@echo off

call "httpd.exe"  "-Xms128M" "-Xmx256M"

:end

其中"-Xms128M"為最小內存,"-Xmx256M"為最大內存。

27、靜態變量和實例變量的區別?

   static i = 10; //常量   class A a;  a.i =10;//可變

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

2)在程序運行時的區別:實例變量屬於某個對象的屬性,必須創建了實例對象,其中的實例變量才會被分配空間,才能使用這個實例變量。

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

   不可以,如果其中包含對象的method();不能保證對象初始化.

29、寫clone()方法時,通常都有一行代碼,是什么?

java賦值是復制對象引用,如果我們想要得到一個對象的副本,就需要使用克隆clone()

   Clone 有缺省行為,super.clone();他負責產生正確大小的空間,並逐位復制。

類使用克隆:

①    實現Cloneable接口,這是一個標記接口,自身沒有方法。

②    對象.clone()方法得到克隆對象,Person p1=new Person();Person p2=(Person) p1.clone();

30、在JAVA中,如何跳出當前的多重嵌套循環?

   用break; return 方法。

31、說出一些常用的類,包,接口,請各舉5個

   常用的類:BufferedReader  BufferedWriter  FileReader  FileWirter  String  Integer

常用的包:java.lang  java.awt  java.io  java.util  java.sql

常用的接口:Remote  List  Map  Document  NodeList

32、什么是值傳遞,什么是引用傳遞?

*值傳遞:是對所傳遞參數進行一次副本拷貝,對參數的修改只是對副本的修改,函數調用結束,副本丟棄,原來的變量不變(即實參不變),基本數據類型都是值傳遞。

*引用傳遞:參數被傳遞到函數時,不復制副本,而是直接將參數自身傳入到函數,函數內對參數的任何改變都將反映到原來的變量上。

33、一個javabean的生命周期

加載、驗證、准備、初始化、引用和卸載這六個過程

加載類,驗證語法,准備(分配內存),初始化(父子類構造函數,賦值),引用,卸載(垃圾回收)

34、a++、++a、a+=1和a=a+1?

a += 1這個和 a = a +1 這兩個是一樣的 只不過一個是簡寫

++a  和   a++  這兩個區別在於運算的先后 

比如:

   b = ++a;   這個是a先自增 然后才賦值   

b = a++; 這個是先賦值 后自增

35、簡述Objiect類的幾個方法

①clone():protected Object clone()創建並返回此對象的一個副本。

②equals():boolean equals(Object obj)指示其他某個對象是否與此對象“相等”。

③finalize():protected void finalize()當垃圾回收器確定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。

④getClass():Class<?> getClass()返回此 Object 的運行時類。

⑤hashCode():int hashCode()返回該對象的哈希碼值。

⑥notify():void notify()喚醒在此對象監視器上等待的單個線程。

⑦notifyAll():void notifyAll()喚醒在此對象監視器上等待的所有線程。

⑧toString():String toString()返回該對象的字符串表示。

⑨wait():void wait()在其他線程調用此對象的 notify() 方法或 notifyAll() 方法前,導致當前線程等待。

void wait(long timeout)在其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量前,導致當前線程等待。

void wait(long timeout, int nanos)在其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者其他某個線程中斷當前線程,或者已超過某個實際時間量前,導致當前線程等待。

36、裝箱和拆箱

裝箱:將值類型轉換為引用類型的過程稱為裝箱。int i=1; Object o=i

拆箱:將引用類型轉換為值類型稱為拆箱。int j=(int)o;

37、三種流程控制結構

*順序結構:從上往下,依次執行

*選擇結構:if—else結構、switch結構

*循環結構:while、do while、for循環

38、不同類型的參數傳遞值的變化

值類型:8大數據類型

引用類型:數組、類、字符串、接口等

以值傳遞方式傳遞值類型參數時,對它的修改不會保留;以值傳遞方式傳遞引用類型參數時,其值的修改會保留。

以引用傳遞方式傳遞值類型參數和引用類型參數時,其值的修改都會保留。

java中會自動區分參數類型,因此沒有ref,因此沒有引用傳遞方式。

39、實體類關系圖

*矩形表示實體

*橢圓表示屬性

*菱形表示聯系

*直線用來連接

數據類型

40、String是最基本的數據類型嗎?

   基本數據類型包括整數型4種:byte(1字節8位)、short(2字節16位)、int(4字節32位)、long(8字節64位);浮點型2種:float(4季節32位)、double(8字節64位);布爾型一種:boolean(1字節8位);字符型一種:char(2字節16位)。

       1字節=8位=8bit  1個漢子=2字節  這里的位是指二進制的位數

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

41、int 和 Integer 有什么區別

   Java 提供兩種不同的類型:引用類型和原始類型(或內置類型)。int是java的原始數據類型初始值是0,Integer是java為int提供的封裝類,初始值是null。Java為每個原始類型提供了封裝類,8大數據類型首字母大寫就是封裝類。

42、數組有沒有length()這個方法? String有沒有length()這個方法

   數組沒有length()這個方法,有length的屬性。String有length()這個方法

43、String s = new String("xyz");創建了幾個String Object

   兩個,一個字符對象,一個字符對象引用對象

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

答:  Math.round(11.5)==12;Math.round(-11.5)==-11;round方法返回與參數最接近的長整數,參數加1/2后求其floor

45、short s1 = 1; s1 = s1 + 1;有什么錯? short s1 = 1; s1 += 1;有什么錯

   short s1 = 1; s1 = s1 + 1; (s1+1運算結果是int型,需要強制轉換類型會報錯)short s1 = 1; s1 += 1;(可以正確編譯)自動轉型小轉大,大轉小必須強制轉型

i=i+2 比 i+=2多了一次對變量 i 的運算。i=i+2是先進行i+2的運算得出一個結果,再賦值給i。i+=2就是先賦值然后在進行加法,因此運算效率高,結果是一樣的。

46、char型變量中能不能存貯一個中文漢字?為什么?

   是能夠定義成為一個中文的,因為java中以unicode編碼,一個char占16個字節,所以放一個中文是沒問題的

47、float型float f=3.4是否正確?

答:不正確。精度不准確,有小數點的默認是double,應該用強制類型轉換,如下所示:float f=(float)3.4或float f=3.4f

異常

48、error和exception有什么區別

   error 是不可控制的unchecked,用來表示系統錯誤或底層資源錯誤,如果有可能應該在系統級別被捕捉

exception 是可控的或不可控的(黑客攻擊),表示程序級的錯誤,應該在程序級別被捕捉

49、給我一個你最常見到的runtime exception

1、空指針異常類:NullPointerException

2、數據類型轉換異常:java.lang.ClassCastException

3、沒有訪問權限:java.lang.IllegalAccessException

4、方法的參數錯誤:java.lang.IllegalArgumentException

5、數組下標越界異常:java.lang.IndexOutOfBoundsException

6、文件已結束異常:EOFException

7、文件未找到異常:FileNotFoundException

8、字符串轉換為數字異常:NumberFormatException

9、指定的類不存在: java.lang.ClassNotFoundException

10、實例化異常:java.lang.InstantiationException

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

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

出現運行時異常后,系統會把異常一直往上層拋,一直遇到處理代碼。如果沒有處理塊,到最上層,如果是多線程就由Thread.run() 拋出 ,如果是單線程就被 main() 拋出 。

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

原理:有錯直接轉到異常處理部分或向上拋出。

應用:JAVA 的異常就是錯誤,有兩種一種是運行時,編碼可以不用捕捉。一種是一般異常,如果throws 聲明了,必須進行處理。

   當JAVA程序違反了JAVA的語義規則時,JAVA虛擬機就會將發生的錯誤表示為一個異常。違反語義規則包括2種情況。一種是JAVA類庫內置的語義檢查。例如數組下標越界,會引發IndexOutOfBoundsException;訪問null的對象時會引發NullPointerException。另一種情況就是JAVA允許程序員擴展這種語義檢查,程序員可以創建自己的異常,並自由選擇在何時用throw關鍵字引發異常。所有的異常都是java.lang.Thowable的子類。

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

   Java通過面向對象的方法進行異常處理,把各種不同的異常進行分類,並提供了良好的接口。在Java中,每個異常都是一個對象,它是Throwable類或其它子類的實例。當一個方法出現異常后便拋出一個異常對象,該對象中包含有異常信息,調用這個對象的方法可以捕獲到這個異常並進行處理。Java的異常處理是通過5個關鍵詞來實現的:try、catch、throw、throws和finally。一般情況下是用try來執行一段程序,如果出現異常,系統會拋出(throws)一個異常,這時候你可以通過它的類型來捕捉(catch)它,或最后(finally)由缺省處理器來處理。

用try來指定一塊預防所有"異常"的程序。緊跟在try程序后面,應包含一個catch子句來指定你想要捕捉的"異常"的類型。

throw語句用來明確地拋出一個"異常"。

throws用來標明一個成員函數可能拋出的各種"異常"。

Finally為確保一段代碼不管發生什么"異常"都被執行一段代碼。

可以在一個成員函數調用的外面寫一個try語句,在這個成員函數內部寫另一個try語句保護其他代碼。每當遇到一個try語句,"異常"的框架就放到堆棧上面,直到所有的try語句都完成。如果下一級的try語句沒有對某種"異常"進行處理,堆棧就會展開,直到遇到有處理這種"異常"的try語句。

53、日志

1. 常用的日志框架

①Java Logging API(Oracle)—— Java默認的日志框架

②Log4j(Apache)——開源日志框架

③Logback(Logback Project)——開源項目,被設計成Log4j版本1的后續版本

④tinylog(tinylog)——輕量級開源logger

log4j定義了8個級別的log(除去OFF和ALL,可以說分為6個級別),優先級從高到低依次為:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL。

ALL 最低等級的,用於打開所有日志記錄。

TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12,很低的日志級別,一般不會使用。

DEBUG 指出細粒度信息事件對調試應用程序是非常有幫助的,主要用於開發過程中打印一些運行信息。

INFO 消息在粗粒度級別上突出強調應用程序的運行過程。打印一些你感興趣的或者重要的信息,這個可以用於生產環境中輸出程序運行的一些重要信息,但是不能濫用,避免打印過多的日志。

WARN 表明會出現潛在錯誤的情形,有些信息不是錯誤信息,但是也要給程序員的一些提示。

ERROR 指出雖然發生錯誤事件,但仍然不影響系統的繼續運行。打印錯誤和異常信息,如果不想輸出太多的日志,可以使用這個級別。

FATAL 指出每個嚴重的錯誤事件將會導致應用程序的退出。這個級別比較高了。重大錯誤,這種級別你可以直接停止程序了。

OFF 最高等級的,用於關閉所有日志記錄。

反射機制

53、什么是反射?

反射是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為 Java 語言的反射機制。

54、 哪里用到反射機制?

JDBC中,利用反射動態加載了數據庫驅動程序。

Web服務器中利用反射調用了Sevlet的服務方法。

Eclispe等開發工具利用反射動態刨析對象的類型與結構,動態提示對象的屬性和方法。

很多框架都用到反射機制,注入屬性,調用方法,如Spring。

55、反射機制的優缺點?

優點:可以動態執行,在運行期間根據業務功能動態執行方法、訪問屬性,最大限度發揮了java的靈活性。

缺點:對性能有影響,這類操作總是慢於直接執行java代碼。

56、 動態代理是什么?有哪些應用?

動態代理是運行時動態生成代理類。

動態代理的應用有 Spring AOP數據查詢、測試框架的后端 mock、rpc,Java注解對象獲取等。

57、 怎么實現動態代理?

JDK 原生動態代理(發射機制)和 cglib 動態代理。

JDK 原生動態代理是基於接口實現的,而 cglib 是基於繼承當前類的子類實現的。

58、Java反射機制的作用

在運行時判斷任意一個對象所屬的類

在運行時構造任意一個類的對象

在運行時判斷任意一個類所具有的成員變量和方法

在運行時調用任意一個對象的方法

59、獲得一個類的類對象有哪些方式?

答:

- 方法1:類型.class,例如:String.class

- 方法2:對象.getClass(),例如:"hello".getClass()

- 方法3:Class.forName(),例如:Class.forName("java.lang.String")

60、如何通過反射創建對象?

答:

- 方法1:通過類對象調用newInstance()方法,例如:String.class.newInstance()

- 方法2:通過類對象的getConstructor()或getDeclaredConstructor()方法獲得構造器(Constructor)對象並調用其newInstance()方法創建對象,例如:String.class.getConstructor(String.class).newInstance("Hello");

61、如何通過反射獲取和設置對象私有字段的值?

答:可以通過類對象的getDeclaredField()方法字段(Field)對象,然后再通過字段對象的setAccessible(true)將其設置為可以訪問,接下來就可以通過get/set方法來獲取/設置字段的值了。

數組與集合

62、什么是數組?什么是集合?

數組是一種數據類型,即引用類型。數組是相同數據類型元素的集合。數組長度固定。

集合用來存放一組相同類型的對象,長度可變。

63、數組(Array)和列表(ArrayList)有什么區別?什么時候應該使用Array而不是ArrayList?

Array可以包含基本類型和對象類型,ArrayList只能包含對象類型。

Array大小是固定的,ArrayList的大小是動態變化的。

ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。

對於基本類型數據,集合使用自動裝箱來減少編碼工作量。但是,當處理固定大小的基本數據類型的時候,這種方式相對比較慢。

64、集合和數組的轉換?

list、set可以使用toArray()方法返回一個Obiect數組。數組轉list可以使用Arrays.aslist()得到一個list,再用list構造set(強轉)。

65、list和map的轉換

得到key的集合,List<String> result = new ArrayList(map.keySet());

得到values的集合,List<String> result2 = new ArrayList(map.values());

list轉map沒有意義,不是鍵值對。

66、Collection 和 Collections的區別

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

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

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

   Set里的元素是不能重復的,那么用iterator()方法來區分重復與否。equals()是判讀兩個Set是否相等

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

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

List,Set是,Map不是,

Map是一個獨立的接口

AbstractMap<K,V> implements Map<K,V>

HashMap<K,V> extends AbstractMap<K,V>

69、ArrayList和Vector的區別,HashMap和Hashtable的區別

   就ArrayList與Vector主要從二方面來說.

一.同步性:Vector是線程安全的,也就是說是同步的,而ArrayList是線程序不安全的,不是同步的

二.數據增長:當需要增長時,Vector默認增長為原來一培,而ArrayList卻是原來的一半

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

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

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

三.值:只有HashMap的key或value可以為空值

70、介紹JAVA中的Collection FrameWork(包括如何寫自己的數據結構)?

   Collection FrameWork如下:

Collection

├List 有序,可重復

│├LinkedList 底層數據結構是鏈表,查詢慢,增刪快,線程安全

│├ArrayList 底層數據結構是數組,查詢快,增刪慢,非線程安全

│└Vector 底層數據結構是數組,查詢快,增刪慢,線程安全

│ └Stack 棧類,先進后出

└Set 無序,唯一

│├HashSet 底層數據結構是哈希表,哈希表結合了數組的快速查詢的優點又能融合鏈表方便快捷的增加刪除元素的優勢。線程不安全,在HashSet中,底層源碼,其實就是一個HashMap,HashMap的key為HashSet中的值,而value為一個Object對象常量。

*哈希表依賴兩個方法hashcode()和equals(),首先判斷hasdcode()是否相同,是:繼續執行equals(),是true說明元素重復不添加,false添加到集合

│├LinkedHashSet 底層數據結構由哈希表和鏈表組成,由鏈表保證元素有序性,由哈希表保證元素唯一性。非線程安全

│├CopyOnWriteArraySet 底層數據結構是數組,CopyOnWriteArraySet是利用CopyOnWriteArrayList來實現的,因為CopyOnWriteArrayList是線程安全的,所以 CopyOnWriteArraySet操作也是線程安全的

Map

├Hashtable 底層數據結構是哈希表,線程安全的,效率低,不允許空值,無序

├HashMap 底層數據結構是哈希表,線程不安全,效率高,允許空值,無序

└linkedHashMap 底層數據由哈希表+鏈表組成,由鏈表保證元素有序,哈希保證元素唯一,非線程安全

arrayList初始長度是10,hashMap初始長度是16

Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)

Collections是集合的算法

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

   ArrayList,Vector底層數據結構都是數組,查詢快,增刪慢。ArrayList線程不安全,Vector線程安全但是效率慢。LinkedList線程安全,底層數據結構是鏈表,查詢慢,增刪快。

72、HashMap和Hashtable的區別

   HashMap和Hashtable底層數據結構都是哈希表。HashMap線程非安全,可以允許空值,效率高。HashTable線程安全,效率低。

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

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

Map 提供了一個更通用的元素存儲方法。 Map 集合類用於存儲元素對(稱作"鍵"和"值"),其中每個鍵映射到一個值。通過map.entrySet().iterator()或map.keySet().iterator()來獲取迭代器(iterator).hasNext()遍歷元素。

74、List、Map、Set三個接口,存取元素時,各有什么特點?

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

75、ArrayList集合加入1萬條數據,應該怎么提高效率

因為ArrayList的底層是數組實現,並且數組的默認值是10,如果插入10000條要不斷的擴容,耗費時間,所以我們調用ArrayList的指定容量的構造器方法ArrayList(int size) 就可以實現不擴容,就提高了性能。

多態(接口與抽象類)

75、abstract class和interface有什么區別

       1:抽象類用abstract關鍵字,接口用interface

       2:接口只能定義方法,抽象類不僅可以定義抽象方法,還可以有實現方法

3:抽象類只能單一繼承,接口可以被多重實現

   抽象定義的類叫抽象類,抽象類字段默認friendly(本包可見),用abstract關鍵字定義抽象類和抽象方法。

    4:抽象層次不同,抽象類是對類抽象,而接口是對行為的抽象。

抽象方法沒有主體,有抽象方法的一定是抽象類。抽象類不一定必須有抽象方法,抽象類可以定義和實現。抽象類只能被單一繼承extends。抽象類抽象方法不能使用private,因為不能被子類繼承。抽象方法不能使用static,因為方法沒有主體沒有意義。

接口(interface)是抽象類的變體。在接口中,所有方法都是抽象的。接口可以被多重實現implements,接口的字段默認為public static final。instanceof 運算符可以用來決定某對象的類是否實現了接口

當存在繼承關系時用抽象類,只需要使用單一功能用接口。

   *抽象類與接口都用於抽象,但是抽象類(JAVA中)可以有自己的部分實現,而接口則完全是一個標識(同時有多重繼承的功能)。

Collection框架中實現比較要實現Comparable 接口和 Comparator 接口,這兩個接口用於排序

76、抽象類abstract的方法method是否可同時是static,是否可同時是native,是否可同時是synchronized

   都不能,abstract是沒有被實現的,而static一定要被實現的。Synchronized是需要同步的,abstract只有被子類繼承的時候才能添加同步。Native本地方法,它把具體的實現交給了本地的函數庫,沒有通過虛擬機,是java與其他語言通信的一種機制。與抽象方法把實現交給子類實現沖突。

77、接口是否可繼承接口? 抽象類是否可實現(implements)接口? 抽象類是否可繼承實體類(concrete class)

   接口可以繼承接口。抽象類可以實現(implements)接口,抽象類是否可繼承實體類,但前提是抽象類必須能訪問實體類的構造方法,子類默認調用父類的構造函數。如果實體了申明了一個private 的無參構造函數,則系統不會自動生成該類的無參構造函數,因此抽象類訪問不到實體類的構造函數而編譯失敗。

78、構造器Constructor是否可被override

   構造器Constructor不能被繼承,因此不能重寫Overriding,但可以被重載Overloading(有參、無參、多參的構造函數)

79、Overload和Override的區別。

Overloaded的方法是否可以改變返回值的類型

方法的重寫Overriding和重載Overloading是Java多態性的不同表現。重寫Overriding是父類與子類之間多態性的一種表現,重載Overloading是一個類中多態性的一種表現。

子類重寫父類的方法,方法名、參數類型個數、返回值類型必須相同。子類的對象使用這個方法時,將調用子類中的定義,對它而言,父類中的定義如同被"屏蔽"了。發生在繼承類中,被重寫的方法不能有更高的權限。

如果在一個類中定義了多個同名的方法,方法名相同,參數類型或個數不同,返回值的類型也可以不同。則稱為方法的重載(Overloading)。發生在同一個類中,一般用於構造函數,對權限沒有要求。

80、 匿名內部類(Anonymous Inner Class) 是否可以extends(繼承)其它類,是否可以implements(實現)interface(接口)

   匿名的內部類是沒有名字的內部類。不能extends(繼承) 其它類,但一個內部類可以作為一個接口,由另一個內部類實現

81、Java的接口和C++的虛類的相同和不同處

   由於Java不支持多繼承,而有可能某個類或對象要使用分別在幾個類或對象里面的方法或屬性,現有的單繼承機制就不能滿足要求。與繼承相比,接口有更高的靈活性,因為接口中沒有任何實現代碼。當一個類實現了接口以后,該類要實現接口里面所有的方法和屬性,並且接口里面的屬性在默認狀態下面都是public static,所有方法默認情況下是public.一個類可以實現多個接口。

82、java中實現多態的機制是什么?

   方法的重寫Overriding和重載Overloading是Java多態性的不同表現。重寫Overriding是父類與子類之間多態性的一種表現,重載Overloading是一個類中多態性的一種表現。

多線程

83、為什么要使用多線程?

1發揮多核CPU的優勢,類似與食堂多個窗口打飯

2防止阻塞,四車道與單車道的比較

3便於建模,可以把先后順序關聯性不強的任務拆分成幾個同步進行,提高效率。比如在生成一個汽車骨架的時候,相應的其他零件也在同步生成,最后組裝。

84、java實現多線程的幾種方式

1、繼承Thread類,重寫run方法

2、實現Runnable接口

3、通過Callable和FutureTack創建線程

4、通過線程池創建線程

知道前面兩種即可,相比實現Runnable接口更快捷,一Java支持單繼承,繼承Thread類就不能集成其他類,繼承擴展性被占,二線程可能只要求可執行即可,Thread類相比開銷過大。

85、說說進程,線程,協程之間的區別?

簡而言之,進程是程序運行和資源分配的基本單位,一個程序至少有一個進程,一個進程至少有一個線程.進程在執行過程中擁有獨立的內存單元,而多個線程共享內存資源,減少切換次數,從而效率更高.

線程是進程的一個實體,是cpu調度和分派的基本單位,是比程序更小的能獨立運行的基本單位.同一進程中的多個線程之間可以並發執行.

86、你了解守護線程嗎?它和非守護線程有什么區別

程序運行完畢,jvm會等待非守護線程完成后關閉,但是jvm不會等待守護線程.守護線程最典型的例子就是GC線程

87、什么是多線程上下文切換

多線程的上下文切換是指CPU控制權由一個已經正在運行的線程切換到另外一個就緒並等待獲取CPU執行權的線程的過程。

88、wait()和sleep()的區別?

1)Sleeep來自Thread類,wait()來自Object類。

2)調用sleep()過程中,線程不會釋放對象鎖,wait()方法會釋放。

3)sleep()睡眠后不讓出系統資源,wait()讓出資源

4)sleep(millssecond)需要指定一個睡眠時間,時間一到會自動喚醒

89、start()方法和run()方法的區別

只有調用了start()方法,才會表現出多線程的特性,不同線程的run()方法里面的代碼交替執行。如果只是調用run()方法,那么代碼還是同步執行的,必須等待一個線程的run()方法里面的代碼全部執行完畢之后,另外一個線程才可以執行其run()方法里面的代碼。

90、什么是線程安全和線程不安全?

通俗的說:加鎖的就是是線程安全的,不加鎖的就是是線程不安全的

線程安全: 就是多線程訪問時,采用了加鎖機制,當一個線程訪問該類的某個數據時,進行保護,其他線程不能進行訪問,直到該線程讀取完,其他線程才可使用。不會出現數據不一致或者數據污染。

91、什么是樂觀鎖和悲觀鎖?

1)樂觀鎖:就像它的名字一樣,對於並發間操作產生的線程安全問題持樂觀狀態,樂觀鎖認為競爭不總是會發生,因此它不需要持有鎖,將比較-替換這兩個動作作為一個原子操作嘗試去修改內存中的變量,如果失敗則表示發生沖突,那么就應該有相應的重試邏輯。

2)悲觀鎖:還是像它的名字一樣,對於並發間操作產生的線程安全問題持悲觀狀態,悲觀鎖認為競爭總是會發生,因此每次對某資源進行操作時,都會持有一個獨占的鎖,就像synchronized,不管三七二十一,直接上了鎖就操作資源了。

92、什么是CAS

CAS,全稱為Compare and Swap,即比較-替換。假設有三個操作數:內存值V、舊的預期值A、要修改的值B,當且僅當預期值A和內存值V相同時,才會將內存值修改為B並返回true,否則什么都不做並返回false。

93、線程的生命周期

新建(New)、就緒(Runnable)、運行(Running)、阻塞(Blocked)和死亡(Dead)5種狀態。

*新建狀態,當程序使用new關鍵字創建了一個線程之后,該線程就處於新建狀態,此時僅由JVM為其分配內存,並初始化其成員變量的值

*就緒狀態,當線程對象調用了start()方法之后,該線程處於就緒狀態。Java虛擬機會為其創建方法調用棧和程序計數器,等待調度運行

*運行狀態,如果處於就緒狀態的線程獲得了CPU,開始執行run()方法的線程執行體,則該線程處於運行狀態

*阻塞狀態,當處於運行狀態的線程失去所占用資源之后,便進入阻塞狀態

*死亡狀態,線程在run()方法執行結束后進入死亡狀態。此外,如果線程執行了interrupt()或stop()方法,那么它也會以異常退出的方式進入死亡狀態。

94、Java中實現線程阻塞的方法

(1)線程睡眠:Thread.sleep (long millis)方法,使線程轉到阻塞狀態。millis參數設定睡眠的時間,以毫秒為單位。當睡眠結束后,就轉為就緒(Runnable)狀態。sleep()平台移植性好。

(2)線程等待:Object類中的wait()方法,導致當前的線程等待,直到其他線程調用此對象的 notify() 喚醒方法。這個兩個喚醒方法也是Object類中的方法,行為等價於調用 wait() 一樣。wait() 和 notify() 方法:兩個方法配套使用,wait() 使得線程進入阻塞狀態,它有兩種形式,一種允許 指定以毫秒為單位的一段時間作為參數,另一種沒有參數,前者當對應的 notify() 被調用或者超出指定時間時線程重新進入可執行狀態,后者則必須對應的 notify() 被調用.

(3)線程禮讓,Thread.yield() 方法,暫停當前正在執行的線程對象,把執行機會讓給相同或者更高優先級的線程。yield() 使得線程放棄當前分得的 CPU 時間,但是不使線程阻塞,即線程仍處於可執行狀態,隨時可能再次分得 CPU 時間。調用 yield() 的效果等價於調度程序認為該線程已執行了足夠的時間從而轉到另一個線程.

(4)線程自閉,join()方法,等待其他線程終止。在當前線程中調用另一個線程的join()方法,則當前線程轉入阻塞狀態,直到另一個進程運行結束,當前線程再由阻塞轉為就緒狀態。

95、什么是死鎖

       死鎖是指兩個以上的進程在執行過程中,由於競爭資源或通信造成的一種阻塞現象,若無外力作用,它們將無法推行下去。

96、產生死鎖的條件

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

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

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

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

97、如何避免死鎖

1、不讓產生死鎖的四個條件同時成立

2、合理分配資源

3、使用銀行家算法,如果該進程請求的資源當前操作系統余量可以滿足,就分配

98、線程間的通信方式

(1)管道(Pipe):管道可用於具有親緣關系進程間的通信,允許一個進程和另一個與它有共同祖先的進程之間進行通信。

(2)命名管道(named pipe):命名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關 系 進程間的通信。命名管道在文件系統中有對應的文件名。命名管道通過命令mkfifo或系統調用mkfifo來創建。

(3)信號(Signal):信號是比較復雜的通信方式,用於通知接受進程有某種事件發生,除了用於進程間通信外,進程還可以發送 信號給進程本身;linux除了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標准的信號函數sigaction(實際上,該函數是基於BSD的,BSD為了實現可靠信號機制,又能夠統一對外接口,用sigaction函數重新實現了signal函數)。

(4)消息(Message)隊列:消息隊列是消息的鏈接表,包括Posix消息隊列system V消息隊列。有足夠權限的進程可以向隊列中添加消息,被賦予讀權限的進程則可以讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式字節流以及緩沖區大小受限等缺

(5)共享內存:使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。往往與其它通信機制,如信號量結合使用,來達到進程間的同步及互斥。

(6)內存映射(mapped memory):內存映射允許任何多個進程間通信,每一個使用該機制的進程通過把一個共享的文件映射到自己的進程地址空間來實現它。

(7)信號量(semaphore):主要作為進程間以及同一進程不同線程之間的同步手段。

(8)套接口(Socket):更為一般的進程間通信機制,可用於不同機器之間的進程間通信。起初是由Unix系統的BSD分支開發出來的,但現在一般可以移植到其它類Unix系統上:Linux和System V的變種都支持套接字。

99、java常見的幾種鎖?

1)自旋鎖:自旋鎖顧名思義,它會等待一定時間(自旋),在這期中會什么都不做就是等資源被釋放,好處在於沒有了內核態用戶態切換的效率損失,但是如果它一直不能訪問到資源的話就會一直占用cpu資源,所以它會循環一段時間后進入阻塞狀態。

重量級鎖:synchronized就是重量級鎖的實現機制,搶不到資源的進程會進入阻塞狀態

2)偏向鎖:顧名思義,它會偏向第一個訪問資源的進程,如果說只有一個進程執行同步代碼塊,那么就會上個偏向鎖,如果有其他線程搶占資源,那么就會升級為輕量級鎖

輕量級鎖:偏向鎖升級之后就是輕量級鎖,鎖只可以升級而不可以降級。輕量級鎖中的其他進程會進入自選狀態,如果說自選失敗,就會升級會重量級鎖

3)公平,非公平鎖:主要是指線程是否先來后到拿到鎖,synchronized是非公平的,而ReentrantLock默認非公平,可以設置為公平鎖

4)悲觀鎖:總是假設最壞的情況,每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻塞直到它拿到鎖(共享資源每次只給一個線程使用,其它線程阻塞,用完后再把資源轉讓給其它線程)。傳統的關系型數據庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。Java中synchronized和ReentrantLock等獨占鎖就是悲觀鎖思想的實現。

5)樂觀鎖:總是假設最好的情況,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號機制(數據庫中)和CAS算法實現

100、線程的sleep()和yield()方法有什么區別?

 1)sleep()給其它線程運行機會不會考慮線程優先級,yield()只會給相同優先級或更高優先級的線程機會

 2)線程執行sleep()方法后進入阻塞狀態,而執行yeild()進入就緒狀態

 3)sleep()方法需要拋出異常interupdateException,而yeild()不用拋異常

 4)sleep()比yield()有更好的移植性

101、如何設置線程的優先級

線程. setPriority()方法來設置線程的優先級,參數是1~10,默認是5。優先級和線程搶到資源的概率沒有關系。結合yeild()就有用了。

102、多線程使用

1、吞吐量:你做WEB,容器幫你做了多線程,但是他只能幫你做請求層面的。簡單的說,可能就是一個請求一個線程。或多個請求一個線程。如果是單線程,那同時只能處理一個用戶的請求。

2、伸縮性:也就是說,你可以通過增加CPU核數來提升性能。如果是單線程,那程序執行到死也就利用了單核,肯定沒辦法通過增加CPU核數來提升性能。鑒於你是做WEB的,第1點可能你幾乎不涉及。那這里我就講第二點吧。--舉個簡單的例子:假設有個請求,這個請求服務端的處理需要執行3個很緩慢的IO操作(比如數據庫查詢或文件查詢),那么正常的順序可能是(括號里面代表執行時間):

a、讀取文件1 (10ms)

b、處理1的數據(1ms)

c、讀取文件2 (10ms)

d、處理2的數據(1ms)

e、讀取文件3 (10ms)

f、處理3的數據(1ms)

如果做 java web 方面開發的話幾乎用不到多線程!因為有多線程的地方 servlet 容器或者其他開發框架都已經實現掉了!

一般在網絡應用程序中使用多線程的地方非常多!

另外,你說的拷貝文件使用多線程,那是沒有用的!以多線程來提高效率的場景一般在 CPU 計算型,而不是在 IO 讀寫型。CPU 可以會有多個核心並行處理計算,但是磁盤 IO 就沒這功能了,磁頭只有一個,根本不可能靠多線程提高效率!

一般來說,磁盤 IO 的並發能力為 0,也就是說無法支持並發!網絡 IO 的話由於帶寬的限制的,使用多線程處理最多也只能達到帶寬的極值。

對於磁盤 IO 來說,多線程可以用於一個線程專門用於讀寫文件,其他的線程用於對讀取數據進行處理,這樣才有可能更好地利用 CPU 資源。

如果僅僅是單純的文件復制,使用多線程操作的話,會使用磁頭在磁盤上不停地進行尋道操作,使得效率更為低下!

 

1.創建+執行+銷毀線程>單線程時間

2.一個線程默認占用1M,內存銷毀

3.頻繁切換線程上下文影響性能

103、一個線程運行時發生異常會怎樣?

如果異常沒有被捕獲該線程將會停止執行。Thread.UncaughtExceptionHandler 是用於處理未捕獲異常造成線程突然中斷情況的一個內嵌接口。當一個未捕獲異常將造成線程中斷的時候JVM會使用Thread.getUncaughtExceptionHandler()來查詢線程的UncaughtExceptionHandler並將線程和異常作為參數傳遞給handler的uncaughtException()方法進行處理。

25、Synchronized 有哪幾種用法?

鎖類、鎖方法、鎖代碼塊。

27、線程數過多會造成什么異常?

線程過多會造成棧溢出,也有可能會造成堆異常。

28、說說線程安全的和不安全的集合。

Java 中平時用的最多的 Map 集合就是 HashMap 了,它是線程不安全的

看下面兩個場景:

1、當用在方法內的局部變量時,局部變量屬於當前線程級別的變量,其他線程訪問

不了,所以這時也不存在線程安全不安全的問題了。

2、當用在單例對象成員變量的時候呢?這時候多個線程過來訪問的就是同一個

HashMap 了,對同個 HashMap 操作這時候就存在線程安全的問題了。

30、怎么檢測一個線程是否擁有鎖?

java.lang.Thread#holdsLock 方法

32、線程同步需要注意什么?

1、盡量縮小同步的范圍,增加系統吞吐量。

2、分布式同步鎖無意義,要使用分布式鎖。

3、防止死鎖,注意加鎖順序。

35、線程之間如何傳遞數據?

通 過 在 線 程 之 間 共 享 對 象 就 可 以 了 , 然 后 通 過 wait/notify/notifyAll 、

await/signal/signalAll 進行喚起和等待,比方說阻塞隊列 BlockingQueue 就是為線程之

間共享數據而設計的

設計模式

102、java的設計模式

1)工廠模式:有一個專門的類負責創建實例的過程。

2)單例模式:一個類始終只能創建一個實例。

3)代理模式:一個對象代表另一個對象采取行動。是一種非常廣泛的設計模式,例如hibernate中A對象管理B對象,加載A對象的時候先加載一個B的代理對象,只有在實際使用到B對象的時候才會加載B的實體。

4)觀察模式:觀察者模式定義了一對多關聯依賴關系,讓一個或多個對象觀察一個主題對象。當主題對象發生變化時,系統通知所有的觀察者對象自動更新。

103、懶漢模式和餓漢模式

懶漢模式:在類加載的時候不被初始化。

餓漢模式:在類加載時就完成了初始化,但是加載比較慢,獲取對象比較快。

餓漢模式是線程安全的,在類創建好一個靜態對象提供給系統使用,懶漢模式在創建對象時不加上synchronized,會導致對象的訪問不是線程安全的

104、什么是高內聚低耦合?

高內聚低耦合是軟件設計的一個基本原則,說的是在程序的各個模塊中,盡量讓每個模塊獨立,相關的處理盡量在單個模塊中完成。優點:能提降低各模塊的之間的聯系,減少“牽一發而動全身”的幾率,提高開發效率,降低升級維護成本,也便於進行單元測試,提高軟件質量。

105、軟件設計的六大設計原則?

1)單一職責原則:一個類值負責一個功能的職責

2)開閉原則:擴展開放,修改關閉。

3)里氏代換原則:使用父類的地方都能使用子類對象

4)依賴倒轉原則:針對接口編程,

5)接口隔離原則:針對不同部分用專門接口,不用總接口,需要哪些接口就用哪些接口

6)迪米特法則: 軟件實體類,盡量不與其他實體類發生關系相互作用,對外都統一的暴露接口就行了

許多的設計模式,包括一些框架,都是參考高內聚低耦合這個點的。

IO/NIO

106、問:簡單說說你平時使用的 Java IO 流中涉及到了哪些設計策略和設計模式?

答:首先 Java 的 IO 庫提供了一種鏈接(Chaining)機制,可以將一個流處理器跟另一個流處理器首尾相接,以其中之一的輸出作為另一個的輸入而形成一個流管道鏈接,譬如常見的 new DataInputStream(new FileInputStream(file)) 就是把 FileInputStream 流當作 DataInputStream 流的管道鏈接。

其次,對於 Java IO 流還涉及一種對稱性的設計策略,其表現為輸入輸出對稱性(如 InputStream 和 OutputStream 的字節輸入輸出操作,Reader 和 Writer 的字符輸入輸出操作)和字節字符的對稱性(InputStream 和 Reader 的字節字符輸入操作,OutputStream 和 Writer 的字節字符輸出操作)。

此外,對於 Java IO 流在整體設計上還涉及裝飾者(Decorator)和適配器(Adapter)兩種設計模式。

對於 IO 流涉及的裝飾者設計模式例子如下:

//把InputStreamReader裝飾成BufferedReader來成為具備緩沖能力的Reader。

BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

對於 IO 流涉及的適配器設計模式例子如下:

//把FileInputStream文件字節流適配成InputStreamReader字符流來操作文件字符串。

FileInputStream fileInput = new FileInputStream(file);

InputStreamReader inputStreamReader = new InputStreamReader(fileInput);

而對於上面涉及的兩種設計模式通俗總結如下。

裝飾者模式就是給一個對象增加一些新的功能,而且是動態的,要求裝飾對象和被裝飾對象實現同一個接口,裝飾對象持有被裝飾對象的實例(各種字符流間裝飾,各種字節流間裝飾)。

適配器模式就是將某個類的接口轉換成我們期望的另一個接口表示,目的是消除由於接口不匹配所造成的類的兼容性問題(字符流與字節流間互相適配)。

107、問:字節流與字符流有什么區別?

答:計算機中的一切最終都是以二進制字節形式存在的,對於我們經常操作的字符串,在寫入時其實都是先得到了其對應的字節,然后將字節寫入到輸出流,在讀取時其實都是先讀到的是字節,然后將字節直接使用或者轉換為字符給我們使用。由於對於字節和字符兩種操作的需求比較廣泛,所以 Java 專門提供了字符流與字節流相關IO類。

對於程序運行的底層設備來說永遠都只接受字節數據,所以當我們往設備寫數據時無論是字節還是字符最終都是寫的字節流。字符流是字節流的包裝類,所以當我們將字符流向字節流轉換時要注意編碼問題(因為字符串轉成字節數組的實質是轉成該字符串的某種字節編碼)。

字符流和字節流的使用非常相似,但是實際上字節流的操作不會經過緩沖區(內存)而是直接操作文本本身的,而字符流的操作會先經過緩沖區(內存)然后通過緩沖區再操作文件。

108、問:什么是緩沖區?有什么作用?

答:緩沖區就是一段特殊的內存區域,很多情況下當程序需要頻繁地操作一個資源(如文件或數據庫)則性能會很低,所以為了提升性能就可以將一部分數據暫時讀寫到緩存區,以后直接從此區域中讀寫數據即可,這樣就顯著提升了性能。

對於 Java 字符流的操作都是在緩沖區操作的,所以如果我們想在字符流操作中主動將緩沖區刷新到文件則可以使用 flush() 方法操作。

109、問:字節流和字符流哪個好?怎么選擇?

答:大多數情況下使用字節流會更好,而大多數時候 IO 操作都是直接操作磁盤文件,所以這些流在傳輸時都是以字節的方式進行的(圖片等都是按字節存儲的)。

而如果對於操作需要通過 IO 在內存中頻繁處理字符串的情況使用字符流會好些,因為字符流具備緩沖區,提高了性能。

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

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

計算機中的底層一切最終都是二進制的字節形式存在。首先讀取的是字節,然后用字符流讀取字符,字符流只能處理字符或者字符串。字節流一般用於傳輸,字符用於讀取字符。字節流可以用於任何類型的對象,包括二進制,但它不能直接處理unicode字符,字符流可以。

111、什么是java序列化,如何實現java序列化?

*序列化:把Java對象轉換為字節序列的過程。

*反序列化:把字節序列恢復為Java對象的過程。

   序列化就是一種用來處理對象流的機制,把對象轉換成字節流方便網絡傳輸。

序列化的實現:將需要被序列化的類實現Serializable接口,該接口沒有需要實現的方法。implements Serializable只是為了標注該對象是可被序列化的,然后使用一個輸出流(如:FileOutputStream)來構造一個ObjectOutputStream(對象流)對象,接着,使用ObjectOutputStream對象的writeObject(Object obj)方法就可以將參數為obj的對象寫出(即保存其狀態),要恢復的話則用輸入流。

泛型

112、Java中的泛型是什么 ? 使用泛型的好處是什么?

泛型,即“參數化類型”。創建集合時就指定集合元素的類型,該集合只能保存其指定類型的元素,避免使用強制類型轉換。

Java編譯器生成的字節碼是不包涵泛型信息的,泛型類型信息將在編譯處理是被擦除,這個過程即類型擦除。泛型擦除可以簡單的理解為將泛型java代碼轉換為普通java代碼,只不過編譯器更直接點,將泛型java代碼直接轉換成普通java字節碼。

類型擦除的主要過程如下:

1).將所有的泛型參數用其最左邊界(最頂級的父類型)類型替換。

2).移除所有的類型參數。

113、 Java的泛型是如何工作的 ? 什么是類型擦除 ?

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

114、什么是泛型中的限定通配符和非限定通配符 ?

限定通配符對類型進行了限制。有兩種限定通配符,一種是<? extends T>它通過確保類型必須是T的子類來設定類型的上界,另一種是<? super T>它通過確保類型必須是T的父類來設定類型的下界。泛型類型必須用限定內的類型來進行初始化,否則會導致編譯錯誤。另一方面<?>表示了非限定通配符,因為<?>可以用任意類型來替代。更多信息請參閱我的文章泛型中限定通配符和非限定通配符之間的區別。

115、 List<? extends T>和List <? super T>之間有什么區別 ?

這兩個List的聲明都是限定通配符的例子,List<? extends T>可以接受任何繼承自T的類型的List,而List<? super T>可以接受任何T的父類構成的List。例如List<? extends Number>可以接受List<Integer>或List<Float>。在本段出現的連接中可以找到更多信息。

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

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

       public V put(K key, V value) {

               return cache.put(key, value);  

}

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

這樣做的話會導致編譯錯誤。因為List<Object>可以存儲任何類型的對象包括String, Integer等等,而List<String>卻只能用來存儲Strings。

List<Object> objectList;

List<String> stringList;

objectList = stringList;

118、Array中可以用泛型嗎?

Array不支持泛型,這也是List代替Array的一個原因,因為List可以提供編譯期的類型安全保證,而Array卻不能。

119、 如何阻止Java中的類型未檢查的警告?

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

List<String> rawList = new ArrayList()

算法

120、排序都有哪幾種方法?請列舉

     排序的方法有:插入排序(直接插入排序、希爾排序),交換排序(冒泡排序、快速排序),選擇排序(直接選擇排序、堆排序),歸並排序,分配排序(箱排序、基數排序)

快速排序是一種常用的排序算法,比冒泡排序快很多。

**在快速排序中使用了大量的遞歸,快速排序的三個步驟:

1、選擇基准值

2、將數組分成兩個子數組;小於基准值的元素和大於基准值的元素

3、對這兩個子數組進行快速排序(遞歸)

快速排序的速度取決於選擇的基准值,運行速度記做 O(n longn ),大O表示法底數默認為2

**選擇排序的數組位移在外層循環,而冒泡排序的位移在內循環。

121、旅行商算法

最慢的算法,有一個旅行商要到N個城市去旅游,希望計算出最短的路線。計算公式為n!=1×2×3×...×n。也就是n的階乘。

XML與JSON

 

1、Xml與JSON區別

區別:

xml是重量級、json是輕量級

xml比較占帶寬、json占帶寬小,易於壓縮

json在webservice 用的比較少、xml用的較多

相同:

兩者都用在項目交互下  例如  移動app接口用的就是json、在web項目中與其他項目對接用xml較多。

json常用解析方法 gson、jsonobject、jackson等 xml dom sax pull 解析

框架

1、什么是dao模式

DAO模式的組成部分:

         1.DAO接口

         2.DAO實現類

         3.實體類

         4.數據庫連接和關閉工具類

DAO模式的作用

         1.隔離業務邏輯代碼和數據訪問代碼

         2.隔離不同數據庫的實現

Spring MVC

122、什么是Spring MVC ?簡單介紹下你對springMVC的理解?

Spring MVC是一個基於Java的實現了MVC設計模式的請求驅動類型的輕量級Web框架,通過把Model,View,Controller分離,將web層進行職責解耦,把復雜的web應用分成邏輯清晰的幾部分,簡化開發,減少出錯,方便組內開發人員之間的配合。

123、什么是輕量級

輕量級是指代碼的侵入性,可以理解為框架與業務代碼的耦合程度。SpringMVC是通過注解或外部文件進行配置的,不需要繼承框架里的類或顯示調用框架里的類或方法,因此是輕量級的。

123、SpringMVC的流程?

(1)用戶發送請求至前端控制器DispatcherServlet;

(2) DispatcherServlet收到請求后,調用HandlerMapping處理器映射器,查找匹配該url 的handle,並返回一個執行鏈,沒有則返回404

(3)DispatcherServlet 調用 HandlerAdapter處理器適配器返回ModelAndView;

(4)DispatcherServlet將ModelAndView傳給ViewResolver視圖解析器進行解析並返回視圖View;

(5)DispatcherServlet對View進行渲染視圖(即將模型數據填充至視圖中),並把數據裝入到request域,返回給用戶

124、Springmvc的優點:

(1)可以支持各種視圖技術,而不僅僅局限於JSP;

(2)與Spring框架集成(如IoC容器、AOP等);

(3)清晰的角色分配:前端控制器(dispatcherServlet) , 請求到處理器映射(handlerMapping), 處理器適配器(HandlerAdapter), 視圖解析器(ViewResolver)。

(4) 支持各種請求資源的映射策略。

125、Spring MVC的主要組件?

(1)前端控制器 DispatcherServlet(不需要程序員開發)

作用:接收請求、響應結果,相當於轉發器,有了DispatcherServlet 就減少了其它組件之間的耦合度。

(2)處理器映射器HandlerMapping(不需要程序員開發)

作用:根據請求的URL來查找Handler

(3)處理器適配器HandlerAdapter

注意:在編寫Handler的時候要按照HandlerAdapter要求的規則去編寫,這樣適配器HandlerAdapter才可以正確的去執行Handler。

(4)處理器Handler(需要程序員開發)

(5)視圖解析器 ViewResolver(不需要程序員開發)

作用:進行視圖的解析,根據視圖邏輯名解析成真正的視圖(view)

(6)視圖View(需要程序員開發jsp)

View是一個接口, 它的實現類支持不同的視圖類型(jsp,freemarker,pdf等等)

126、springMVC和struts2的區別有哪些?

(1)springmvc的入口是一個servlet即前端控制器(DispatchServlet),而struts2入口是一個filter過慮器(StrutsPrepareAndExecuteFilter)。

(2)springmvc是基於方法開發(一個url對應一個方法),請求參數傳遞到方法的形參,可以設計為單例或多例(建議單例),struts2是基於類開發,傳遞參數是通過類的屬性,只能設計為多例。

(3)Struts采用值棧存儲請求和響應的數據,通過OGNL存取數據,springmvc通過參數解析器是將request請求內容解析,並給方法形參賦值,將數據和視圖封裝成ModelAndView對象,最后又將ModelAndView中的模型數據通過reques域傳輸到頁面。Jsp視圖解析器默認使用jstl。

127、SpringMVC怎么樣設定重定向和轉發的?

(1)轉發:在返回值前面加"forward:",譬如"forward:user.do?name=method4"

(2)重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com"

 

7、SpringMvc怎么和AJAX相互調用的?

通過Jackson框架就可以把Java里面的對象直接轉化成Js可以識別的Json對象。具體步驟如下 :

(1)加入Jackson.jar

(2)在配置文件中配置json的映射

(3)在接受Ajax方法里面可以直接返回Object,List等,但方法前面要加上@ResponseBody注解。

128、如何解決POST請求中文亂碼問題,GET的又如何處理呢?

(1)解決post請求亂碼問題:

在web.xml中配置一個CharacterEncodingFilter過濾器,設置成utf-8;

(2)get請求中文參數出現亂碼解決方法有兩個:

①修改tomcat配置文件添加編碼與工程編碼一致,如下:

<ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

②另外一種方法對參數進行重新編碼:

String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")

ISO8859-1是tomcat默認編碼,需要將tomcat編碼后的內容按utf-8編碼。

129、Spring MVC的異常處理 ?

答:可以將異常拋給Spring框架,由Spring框架來處理;我們只需要配置簡單的異常處理器,在異常處理器中添視圖頁面即可。

130、SpringMvc的控制器是不是單例模式,如果是,有什么問題,怎么解決?

答:是單例模式,所以在多線程訪問的時候有線程安全問題,不要用同步,會影響性能的,解決方案是在控制器里面不能寫字段。

131、 SpringMVC常用的注解有哪些?

@RequestMapping:用於處理請求 url 映射的注解,可用於類或方法上。用於類上,則表示類中的所有響應請求的方法都是以該地址作為父路徑。

@RequestBody:注解實現接收http請求的json數據,將json轉換為java對象。

@ResponseBody:注解實現將conreoller方法返回對象轉化為json對象響應給客戶。

132、SpingMvc中的控制器的注解一般用那個,有沒有別的注解可以替代?

答:一般用@Controller注解,也可以使用@RestController,@RestController注解相當於@ResponseBody + @Controller,表示是表現層,除此之外,一般不用別的注解代替。

133、如果在攔截請求中,我想攔截get方式提交的方法,怎么配置?

答:可以在@RequestMapping注解里面加上method=RequestMethod.GET。

134、怎樣在方法里面得到Request,或者Session?

答:直接在方法的形參中聲明request,SpringMvc就自動把request對象傳入。

135、如果想在攔截的方法里面得到從前台傳入的參數,怎么得到?

答:直接在形參里面聲明這個參數就可以,但必須名字和傳過來的參數一樣。

 

136、如果前台有很多個參數傳入,並且這些參數都是一個對象的,那么怎么樣快速得到這個對象?

答:直接在方法中聲明這個對象,SpringMvc就自動會把屬性賦值到這個對象里面。

137、SpringMvc中函數的返回值是什么?

答:返回值可以有很多類型,有String, ModelAndView。ModelAndView類把視圖和數據都合並的一起的,但一般用String比較好。

138、SpringMvc用什么對象從后台向前台傳遞數據的?

答:通過ModelMap對象,可以在這個對象里面調用put方法,把對象加到里面,前台就可以通過el表達式拿到。

139、怎么樣把ModelMap里面的數據放入Session里面?

答:可以在類上面加上@SessionAttributes注解,里面包含的字符串就是要放入session里面的key。

140、SpringMvc里面攔截器是怎么寫的:

有兩種寫法,一種是實現HandlerInterceptor接口,另外一種是繼承適配器類,接着在接口方法當中,實現處理邏輯;然后在SpringMvc的配置文件中配置攔截器即可:

  <!-- 配置SpringMvc的攔截器 -->

<mvc:interceptors>

    <!-- 配置一個攔截器的Bean就可以了 默認是對所有請求都攔截 -->

    <bean id="myInterceptor" class="com.zwp.action.MyHandlerInterceptor"></bean>

    <!-- 只針對部分請求攔截 -->

    <mvc:interceptor>

       <mvc:mapping path="/modelMap.do" />

       <bean class="com.zwp.action.MyHandlerInterceptorAdapter" />

    </mvc:interceptor>

</mvc:interceptors>

 

141、注解原理:

注解本質是一個繼承了Annotation的特殊接口,其具體實現類是Java運行時生成的動態代理類。我們通過反射獲取注解時,返回的是Java運行時生成的動態代理對象。通過代理對象調用自定義注解的方法,會最終調用AnnotationInvocationHandler的invoke方法。該方法會從memberValues這個Map中索引出對應的值。而memberValues的來源是Java常量池。

Struts2

142、描述Struts2的執行流程

Struts 2框架本身大致可以分為3個部分:核心控制器FilterDispatcher、業務控制器Action和用戶實現的企業業務邏輯組件。   1)核心控制器FilterDispatcher是Struts 2框架的基礎,包含了框架內部的控制流程和處理機制。 

 2)業務控制器Action和業務邏輯組件是需要用戶來自己實現的。用戶在開發Action和業務邏輯組件的同時,還需要編寫相關的配置文件,供核心控制器FilterDispatcher來使用。 

 Struts 2的工作流程相對於Struts 1要簡單,與WebWork框架基本相同,所以說Struts 2是WebWork的升級版本。 

 

 基本簡要流程如下:

 1)客戶端瀏覽器發出HTTP請求。 

 2)根據web.xml配置,該請求被FilterDispatcher接收。 

 3)根據struts.xml配置,找到需要調用的Action類和方法, 並通過IoC方式,將值注入給Aciton。 

 4)Action調用業務邏輯組件處理業務邏輯,這一步包含表單驗證。 

 5)Action執行完畢,根據struts.xml中的配置找到對應的返回結果result,並跳轉到相應頁面。

 6)返回HTTP響應到客戶端瀏覽器。

143、Struts2中的攔截器有什么用?列舉框架提供的攔截器名稱?(至少3種,可用中文名)

 1)攔截器是struts2核心組成部分,它提供了一種機制,使得開發者可以定義一個特定的功能模塊,這個模塊會在Action執行之前或者之后執行,也可以在Action執行之前阻止Action執行。 

 2)常用的攔截器有: 

 chain:在不同請求之間將請求參數在不同名字件轉換,請求內容不變 

 fileUpload:提供文件上傳。 

 ​i18n:記錄用戶選擇的區域環境 

 logger:輸出Action的名字

 params:將請求中的參數設置到Action中去。

144、Struts2有哪些優點?

 1)在軟件設計上Struts2的應用可以不依賴於Servlet API和struts API。 Struts2的這種設計屬於無侵入式設計; 

 2)攔截器,實現如參數攔截注入等功能;

 3)類型轉換器,可以把特殊的請求參數轉換成需要的類型; 

 4)多種表現層技術,如:JSP、freeMarker、Velocity等;

 5)Struts2的輸入校驗可以對指定某個方法進行校驗;

 6)提供了全局范圍、包范圍和Action范圍的國際化資源文件管理實現 

 7) 實現MVC模式,結構清晰,使開發者只關注業務邏輯的實現。有豐富的tag可以用,大大提高了開發效率。(簡要)

145、什么是OGNL,有什么用途?如何訪問存放在session中叫user的對象的username屬性

​ OGNL是Object-Graph Navigation Language的縮寫,也叫對象導航語言。它是Struts的一種功能強大的表達式語言列如:訪問session中的user對象的username屬性:注意的是:使用前需要在頁面頭部導入taglib prefix="s" uri="/struts-tags"

​146、什么是國際化,struts2實現國際化的原理?

國際化是根據不同的國家和地區的語言文化的不同,所設計的適用於不同地區的編碼格式。 

 實現方法: 

 1)首先在src目錄下新建message_en.properties(英文); 

 2)頁面獲取國際化信息或者使用 

原理:程序得到當前運行環境的國際/區域,語言環境並存放於Locale,ResourceBundle根據Locale中信息自動搜索對應的國際化資源文件並加載。

 

147、AJAX是什么? 描述ajax的原理

Ajax又叫異步刷新,(JavaScript和xml)原理:使用HttpRequest向服務器發送異步請求,服務器返回處理結果

148、什么是反射?請用反射動態創建一個類的對象(寫關鍵代碼,其它可省略)

反射,程序運行時動態獲取類型信息,完成對象創建,方法調用等。

例如:

Class myclass=Class.forNama("包名.類名");

Student stu=Factory.createInstance("stu1");

149、在struts2中如何實現轉發和重定向?

在struts.xml中配置type="redirect"(重定向);type="redirectAction"(轉發)

150、Struts2中的type類型有哪些?至少寫4種

dispatcher:result type默認的類型,相當於servlet的foward方式跳轉頁面。客戶端看到的是struts2中配置的地址,而不是真正頁面的地址,一般用於跳轉到jsp頁面,頁面能拿到值

redirect:頁面重定向,客戶端跳轉,數據全部丟失,地址欄發生變化,頁面不能拿到值

chain:將請求轉發給一個Action,Action能通過getAttribute(“uname”)拿到值

redirect-action:一般用於跳轉到Action,Action不能通過getAttribute(“uname”)拿到值10、struts2默認能解決get和post提交方式的亂碼問題嗎?

答:不能。struts.i18n.encoding=UTF-8屬性值只能解析POST提交下的亂碼問題。

151、說下Struts的設計模式

MVC模式: 

 1)web應用程序啟動時就會加載並初始化ActionServler。

 2)用戶提交表單時,一個配置好的ActionForm對象被創建,並被填入表單相應的數據,ActionServler根據Struts-config.xml文件配置好的設置決定是否需要表單驗證,如果需要就調用ActionForm的Validate()驗證后選擇將請求發送到哪個Action,如果Action不存在,ActionServlet會先創建這個對象,然后調用Action的execute()方法. 

 3)Execute()從ActionForm對象中獲取數據,完成業務邏輯,返回一個ActionForward對象,ActionServlet再把客戶請求轉發給ActionForward對象指定的jsp組件,ActionForward對象指定的jsp生成動態的網頁,返回給客戶。

152、攔截器和過濾器的區別

 1)攔截器是基於java反射機制的,而過濾器是基於函數回調的。 

 2)過濾器依賴於servlet容器,而攔截器不依賴於servlet容器。

 3)攔截器只能對Action請求起作用,而過濾器則可以對幾乎所有請求起作用。 

 4)攔截器可以訪問Action上下文、值棧里的對象,而過濾器不能。 

 5)在Action的生命周期中,攔截器可以多次調用,而過濾器只能在容器初始化時被調用一次。

153、請你寫出struts2中至少5個的默認攔截器?

 fileUpload 提供文件上傳功能 

 i18n 記錄用戶選擇的locale 

 cookies 使用配置的name,value來是指cookies 

 checkbox 添加了checkbox自動處理代碼,將沒有選中的checkbox的內容設定為false,而html默認情況下不提交沒有選中的 checkbox。 

 chain 讓前一個Action的屬性可以被后一個Action訪問,現在和chain類型的result()結合使用。

 alias 在不同請求之間將請求參數在不同名字件轉換,請求內容不變

154、ActionContext、ServletContext、pageContext的區別? 

 1)ActionContext是當前的Action的上下文環境,通過ActionContext可以獲取到request、session、ServletContext等與Action有關的對象的引用; 

 2)ServletContext是域對象,一個web應用中只有一個ServletContext,生命周期伴隨整個web應用; 

 3)pageContext是JSP中的最重要的一個內置對象,可以通過pageContext獲取其他域對象的應用,同時它是一個域對象,作用范圍只針對當前頁面,當前頁面結束時,pageContext銷毀, 生命周期是JSP四個域對象中最小的。

155、攔截器的生命周期與工作過程? 

 1)每個攔截器都是實現了Interceptor接口的 Java 類; 

 2)init(): 該方法將在攔截器被創建后立即被調用, 它在攔截器的生命周期內只被調用一次. 可以在該方法中對相關資源進行必要的初始化; 

 3)intercept(ActionInvocation invocation): 每攔截一個動作請求, 該方法就會被調用一次; 

 4)destroy: 該方法將在攔截器被銷毀之前被調用, 它在攔截器的生命周期內也只被調用一次; 

 5)struts2中有內置了18個攔截器。

Mybatis

156、什么是Mybatis?

(1)Mybatis是一個半ORM(對象關系映射)框架,它內部封裝了JDBC,開發時只需要關注SQL語句本身,不需要花費精力去處理加載驅動、創建連接、創建statement等繁雜的過程。程序員直接編寫原生態sql,可以嚴格控制sql執行性能,靈活度高。

(2)MyBatis 可以使用 XML 或注解來配置和映射原生信息,將 POJO映射成數據庫中的記錄,避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。

(3)通過xml 文件或注解的方式將要執行的各種 statement 配置起來,並通過java對象和 statement中sql的動態參數進行映射生成最終執行的sql語句,最后由mybatis框架執行sql並將結果映射為java對象並返回。(從執行sql到返回result的過程)。

157、Mybaits的優點:

(1)基於SQL語句編程,相當靈活,不會對應用程序或者數據庫的現有設計造成任何影響,SQL寫在XML里,解除sql與程序代碼的耦合,便於統一管理;提供XML標簽,支持編寫動態SQL語句,並可重用。

(2)與JDBC相比,減少了50%以上的代碼量,消除了JDBC大量冗余的代碼,不需要手動開關連接;

(3)很好的與各種數據庫兼容(因為MyBatis使用JDBC來連接數據庫,所以只要JDBC支持的數據庫MyBatis都支持)。

(4)能夠與Spring很好的集成;

(5)提供映射標簽,支持對象與數據庫的ORM字段關系映射;提供對象關系映射標簽,支持對象關系組件維護。

158、MyBatis框架的缺點:

(1)SQL語句的編寫工作量較大,尤其當字段多、關聯表多時,對開發人員編寫SQL語句的功底有一定要求。

(2)SQL語句依賴於數據庫,導致數據庫移植性差,不能隨意更換數據庫。

159、MyBatis框架適用場合:

(1)MyBatis專注於SQL本身,是一個足夠靈活的DAO層解決方案。

(2)對性能的要求很高,或者需求變化較多的項目,如互聯網項目,MyBatis將是不錯的選擇。 

160、MyBatis與Hibernate有哪些不同?

(1)Mybatis和hibernate不同,它不完全是一個ORM框架,因為MyBatis需要程序員自己編寫Sql語句。

(2)Mybatis直接編寫原生態sql,可以嚴格控制sql執行性能,靈活度高,非常適合對關系數據模型要求不高的軟件開發,因為這類軟件需求變化頻繁,一但需求變化要求迅速輸出成果。但是靈活的前提是mybatis無法做到數據庫無關性,如果需要實現支持多種數據庫的軟件,則需要自定義多套sql映射文件,工作量大。 

(3)Hibernate對象/關系映射能力強,數據庫無關性好,對於關系模型要求高的軟件,如果用hibernate開發可以節省很多代碼,提高效率。 

160、#{}和${}的區別是什么?

#{}是預編譯處理,${}是字符串替換。

Mybatis在處理#{}時,會將sql中的#{}替換為?號,調用PreparedStatement的set方法來賦值;

Mybatis在處理${}時,就是把${}替換成變量的值。

使用#{}可以有效的防止SQL注入,提高系統安全性。

161、當實體類中的屬性名和表中的字段名不一樣 ,怎么辦 ?

第1種: 通過在查詢的sql語句中定義字段名的別名,讓字段名的別名和實體類的屬性名一致。

第2種: 通過<resultMap>來映射字段名和實體類屬性名的一一對應的關系。

162、 模糊查詢like語句該怎么寫?

第1種:在Java代碼中添加sql通配符。

第2種:在sql語句中拼接通配符,會引起sql注入

163、通常一個Xml映射文件,都會寫一個Dao接口與之對應,請問,這個Dao接口的工作原理是什么?Dao接口里的方法,參數不同時,方法能重載嗎?

Dao接口即Mapper接口。接口的全限名,就是映射文件中的namespace的值;接口的方法名,就是映射文件中Mapper的Statement的id值;接口方法內的參數,就是傳遞給sql的參數。

Mapper接口是沒有實現類的,當調用接口方法時,接口全限名+方法名拼接字符串作為key值,可唯一定位一個MapperStatement。在Mybatis中,每一個<select>、<insert>、<update>、<delete>標簽,都會被解析為一個MapperStatement對象。

舉例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到namespace為com.mybatis3.mappers.StudentDao下面 id 為 findStudentById 的 MapperStatement。

Mapper接口里的方法,是不能重載的,因為是使用 全限名+方法名 的保存和尋找策略。Mapper 接口的工作原理是JDK動態代理,Mybatis運行時會使用JDK動態代理為Mapper接口生成代理對象proxy,代理對象會攔截接口方法,轉而執行MapperStatement所代表的sql,然后將sql執行結果返回。

164、Mybatis是如何進行分頁的?分頁插件的原理是什么?

Mybatis使用RowBounds對象進行分頁,它是針對ResultSet結果集執行的內存分頁,而非物理分頁。可以在sql內直接書寫帶有物理分頁的參數來完成物理分頁功能,也可以使用分頁插件來完成物理分頁。分頁插件的基本原理是使用Mybatis提供的插件接口,實現自定義插件,在插件的攔截方法內攔截待執行的sql,然后重寫sql,根據dialect方言,添加對應的物理分頁語句和物理分頁參數。

165、Mybatis是如何將sql執行結果封裝為目標對象並返回的?都有哪些映射形式?

第一種是使用<resultMap>標簽,逐一定義數據庫列名和對象屬性名之間的映射關系。

第二種是使用sql列的別名功能,將列的別名書寫為對象屬性名。

有了列名與屬性名的映射關系后,Mybatis通過反射創建對象,同時使用反射給對象的屬性逐一賦值並返回,那些找不到映射關系的屬性,是無法完成賦值的。

166、如何執行批量插入?

首先,創建一個簡單的insert語句:mapper.xml中

然后在java代碼中批量賦值:業務層調用dao層執行插入

167、如何獲取自動生成的(主)鍵值?

在insert語句中開啟usegeneratedkeys=”true” keyproperty=”id”

insert 方法總是返回一個int值 ,這個值代表的是插入的行數。

如果采用自增長策略,自動生成的鍵值在 insert 方法執行完后可以被設置到傳入的參數對象中。

168、在mapper中如何傳遞多個參數?

(1)第一種:

//DAO層的函數

Public UserselectUser(String name,String area); 

//對應的xml,#{0}代表接收的是dao層中的第一個參數,#{1}代表dao層中第二參數,更多參數一致往后加即可。

<select id="selectUser"resultMap="BaseResultMap"> 

    select *  fromuser_user_t   whereuser_name = #{0} anduser_area=#{1} 

</select> 

(2)第二種: 使用 @param 注解:

public interface usermapper {

   user selectuser(@param(“username”) string username,@param(“hashedpassword”) string hashedpassword);

}

然后,就可以在xml像下面這樣使用(推薦封裝為一個map,作為單個參數傳遞給mapper):

<select id=”selectuser” resulttype=”user”>

         select id, username, hashedpassword

         from some_table

         where username = #{username}

         and hashedpassword = #{hashedpassword}

</select>

(3)第三種:多個參數封裝成map

try{

//映射文件的命名空間.SQL片段的ID,就可以調用對應的映射文件中的SQL

//由於我們的參數超過了兩個,而方法中只有一個Object參數收集,因此我們使用Map集合來裝載我們的參數

Map<String, Object> map = new HashMap();

     map.put("start", start);

     map.put("end", end);

     return sqlSession.selectList("StudentID.pagination", map);

 }catch(Exception e){

     e.printStackTrace();

     sqlSession.rollback();

    throw e; }

finally{

 MybatisUtil.closeSqlSession();

 }

169、Mybatis動態sql有什么用?執行原理?有哪些動態sql?

Mybatis動態sql可以在Xml映射文件內,以標簽的形式編寫動態sql,執行原理是根據表達式的值 完成邏輯判斷並動態拼接sql的功能。

Mybatis提供了9種動態sql標簽:trim | where | set | foreach | if | choose | when | otherwise | bind。

170、Xml映射文件中,除了常見的select|insert|updae|delete標簽之外,還有哪些標簽?

<resultMap>、<parameterMap>、<sql>、<include>、<selectKey>,加上動態sql的9個標簽,其中<sql>為sql片段標簽,通過<include>標簽引入sql片段,<selectKey>為不支持自增的主鍵生成策略標簽。

171、Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重復?

不同的Xml映射文件,如果配置了namespace,那么id可以重復;如果沒有配置namespace,那么id不能重復;

原因就是namespace+id是作為Map<String, MapperStatement>的key使用的,如果沒有namespace,就剩下id,那么,id重復會導致數據互相覆蓋。有了namespace,自然id就可以重復,namespace不同,namespace+id自然也就不同。

但是,在以前的Mybatis版本的namespace是可選的,不過新版本的namespace已經是必須的了。

172、為什么說Mybatis是半自動ORM映射工具?它與全自動的區別在哪里?

Hibernate屬於全自動ORM映射工具,使用Hibernate查詢關聯對象或者關聯集合對象時,可以根據對象關系模型直接獲取,所以它是全自動的。而Mybatis在查詢關聯對象或關聯集合對象時,需要手動編寫sql來完成,所以,稱之為半自動ORM映射工具。

173、 一對一、一對多的關聯查詢 ? 

association 一對一, 一對多  collection,多對多 discrimination

174、MyBatis實現一對一有幾種方式?具體怎么操作的?

有聯合查詢和嵌套查詢,聯合查詢是幾個表聯合查詢,只查詢一次, 通過在resultMap里面配置association節點配置一對一的類就可以完成;

嵌套查詢是先查一個表,根據這個表里面的結果的 外鍵id,去再另外一個表里面查詢數據,也是通過association配置,但另外一個表的查詢通過select屬性配置。

175、MyBatis實現一對多有幾種方式,怎么操作的?

有聯合查詢和嵌套查詢。聯合查詢是幾個表聯合查詢,只查詢一次,通過在resultMap里面的collection節點配置一對多的類就可以完成;嵌套查詢是先查一個表,根據這個表里面的 結果的外鍵id,去再另外一個表里面查詢數據,也是通過配置collection,但另外一個表的查詢通過select節點配置。

176、Mybatis是否支持延遲加載?如果支持,它的實現原理是什么?

Mybatis僅支持association關聯對象和collection關聯集合對象的延遲加載,association指的就是一對一,collection指的就是一對多查詢。在Mybatis配置文件中,可以配置是否啟用延遲加載lazyLoadingEnabled=true|false。

它的原理是,使用CGLIB創建目標對象的代理對象,當調用目標方法時,進入攔截器方法,比如調用a.getB().getName(),攔截器invoke()方法發現a.getB()是null值,那么就會單獨發送事先保存好的查詢關聯B對象的sql,把B查詢上來,然后調用a.setB(b),於是a的對象b屬性就有值了,接着完成a.getB().getName()方法的調用。這就是延遲加載的基本原理。

當然了,不光是Mybatis,幾乎所有的包括Hibernate,支持延遲加載的原理都是一樣的。

 177、Mybatis的一級、二級緩存:

1)一級緩存: 基於 PerpetualCache 的 HashMap 本地緩存,其存儲作用域為 Session,當 Session flush 或 close 之后,該 Session 中的所有 Cache 就將清空,默認打開一級緩存。

2)二級緩存與一級緩存其機制相同,默認也是采用 PerpetualCache,HashMap 存儲,不同在於其存儲作用域為 Mapper(Namespace),並且可自定義存儲源,如 Ehcache。默認不打開二級緩存,要開啟二級緩存,使用二級緩存屬性類需要實現Serializable序列化接口(可用來保存對象的狀態),可在它的映射文件中配置<cache/> ;

3)對於緩存數據更新機制,當某一個作用域(一級緩存 Session/二級緩存Namespaces)的進行了C/U/D 操作后,默認該作用域下所有 select 中的緩存將被 clear 掉並重新更新,如果開啟了二級緩存,則只根據配置判斷是否刷新。

178、什么是MyBatis的接口綁定?有哪些實現方式?

接口綁定,就是在MyBatis中任意定義接口,然后把接口里面的方法和SQL語句綁定, 我們直接調用接口方法就可以,這樣比起原來了SqlSession提供的方法我們可以有更加靈活的選擇和設置。

接口綁定有兩種實現方式,一種是通過注解綁定,就是在接口的方法上面加上 @Select、@Update等注解,里面包含Sql語句來綁定;另外一種就是通過xml里面寫SQL來綁定, 在這種情況下,要指定xml映射文件里面的namespace必須為接口的全路徑名。當Sql語句比較簡單時候,用注解綁定, 當SQL語句比較復雜時候,用xml綁定,一般用xml綁定的比較多。

179、使用MyBatis的mapper接口調用時有哪些要求?

①  Mapper接口方法名和mapper.xml中定義的每個sql的id相同;

②  Mapper接口方法的輸入參數類型和mapper.xml中定義的每個sql 的parameterType的類型相同;

③  Mapper接口方法的輸出參數類型和mapper.xml中定義的每個sql的resultType的類型相同;

③      Mapper.xml文件中的namespace即是mapper接口的類路徑。

180、Mapper編寫有哪幾種方式?

第一種:接口實現類繼承SqlSessionDaoSupport:使用此種方法需要編寫mapper接口,mapper接口實現類、mapper.xml文件。

(1)在sqlMapConfig.xml中配置mapper.xml的位置

<mappers>

    <mapper resource="mapper.xml文件的地址" />

    <mapper resource="mapper.xml文件的地址" />

</mappers>

(2)定義mapper接口

(3)實現類集成SqlSessionDaoSupport

mapper方法中可以this.getSqlSession()進行數據增刪改查。

(4)spring 配置

<bean id=" " class="mapper接口的實現">

    <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>

</bean>

第二種:使用org.mybatis.spring.mapper.MapperFactoryBean:

(1)在sqlMapConfig.xml中配置mapper.xml的位置,如果mapper.xml和mappre接口的名稱相同且在同一個目錄,這里可以不用配置

<mappers>

    <mapper resource="mapper.xml文件的地址" />

    <mapper resource="mapper.xml文件的地址" />

</mappers>

(2)定義mapper接口:

①mapper.xml中的namespace為mapper接口的地址

②mapper接口中的方法名和mapper.xml中的定義的statement的id保持一致

③Spring中定義

<bean id="" class="org.mybatis.spring.mapper.MapperFactoryBean">

    <property name="mapperInterface"   value="mapper接口地址" /> 

    <property name="sqlSessionFactory" ref="sqlSessionFactory" /> 

</bean>

第三種:使用mapper掃描器:

(1)mapper.xml文件編寫:

mapper.xml中的namespace為mapper接口的地址;

mapper接口中的方法名和mapper.xml中的定義的statement的id保持一致;

如果將mapper.xml和mapper接口的名稱保持一致則不用在sqlMapConfig.xml中進行配置。 

(2)定義mapper接口:

注意mapper.xml的文件名和mapper的接口名稱保持一致,且放在同一個目錄

(3)配置mapper掃描器:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

    <property name="basePackage" value="mapper接口包地址"></property>

    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> 

</bean>

(4)使用掃描器后從spring容器中獲取mapper的實現對象。

181、簡述Mybatis的插件運行原理,以及如何編寫一個插件。

Mybatis僅可以編寫針對ParameterHandler、ResultSetHandler、StatementHandler、Executor這4種接口的插件,Mybatis使用JDK的動態代理,為需要攔截的接口生成代理對象以實現接口方法攔截功能,每當執行這4種接口對象的方法時,就會進入攔截方法,具體就是InvocationHandler的invoke()方法,當然,只會攔截那些你指定需要攔截的方法。

編寫插件:實現Mybatis的Interceptor接口並復寫intercept()方法,然后在給插件編寫注解,指定要攔截哪一個接口的哪些方法即可,記住,別忘了在配置文件中配置你編寫的插件。

Hibernate

182、Hibernate的核心思想

Hibernate的核心思想是ROM對象關系映射機制。它是將表與表之間的操作映射成對象與對象之間的操作。從數據庫中提取的信息會自動按照你設置的映射要求封裝成特點的對象,使得對對象的修改對應數據行的修改。

183、Hibernate工作原理及為什么要用?

讀取並解析配置文件

讀取並解析映射信息,創建SessionFactory

打開Sesssion

創建事務Transation

持久化操作

提交事務

關閉Session

關閉SesstionFactory

使用Hibernate框架就不用我們寫很多繁瑣的SQL語句。Hibernate實現了ORM,能夠將對象映射成數據庫表,從而簡化我們的開發!

184、Hibernate是如何延遲加載(懶加載)?

通過設置屬性lazy進行設置是否需要懶加載

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

185、Hibernate中怎樣實現類之間的關系?(如:一對多、多對多的關系)

它們通過配置文件中的many-to-one、one-to-many、many-to-many來實現類之間的關聯關系的。

186、hibernate的三種狀態之間如何轉換

Hibernate中對象的狀態:

臨時/瞬時狀態

持久化狀態

游離狀態

new出來的對象是瞬時狀態->保存到數據庫中(受Session管理)就是持久化狀態->將session close掉就是游離狀態

187、比較hibernate的三種檢索策略優缺點

1)立即檢索:

優點: 對應用程序完全透明,不管對象處於持久化狀態,還是游離狀態,應用程序都可以方便的從一個對象導航到與它關聯的對象;

缺點: 1.select語句太多;2.可能會加載應用程序不需要訪問的對象白白浪費許多內存空間;

立即檢索:lazy=false;

2)延遲檢索:

優點: 由應用程序決定需要加載哪些對象,可以避免可執行多余的select語句,以及避免加載應用程序不需要訪問的對象。因此能提高檢索性能,並且能節省內存空間;

缺點: 應用程序如果希望訪問游離狀態代理類實例,必須保證他在持久化狀態時已經被初始化;

延遲加載:lazy=true;

3)迫切左外連接檢索:

優點: 1對應用程序完全透明,不管對象處於持久化狀態,還是游離狀態,應用程序都可以方便地沖一個對象導航到與它關聯的對象。2使用了外連接,select語句數目少;

缺點: 1 可能會加載應用程序不需要訪問的對象,白白浪費許多內存空間;2復雜的數據庫表連接也會影響檢索性能;

預先抓取: fetch=“join”;

188、hibernate都支持哪些緩存策略

4種:

放入二級緩存的對象,只讀(Read-only);

非嚴格的讀寫(Nonstrict read/write)

讀寫; 放入二級緩存的對象可以讀、寫(Read/write);

基於事務的策略(Transactional)

189、hibernate里面的sorted collection 和ordered collection有什么區別

sorted collection是在內存中通過Java比較器進行排序的

ordered collection是在數據庫中通過order by進行排序的

對於比較大的數據集,為了避免在內存中對它們進行排序而出現 Java中的OutOfMemoryError,最好使用ordered collection。

190、說下Hibernate的緩存機制

一級緩存:

Hibenate中一級緩存,也叫做session的緩存,它可以在session范圍內減少數據庫的訪問次數! 只在session范圍有效! Session關閉,一級緩存失效!

只要是持久化對象狀態的,都受Session管理,也就是說,都會在Session緩存中!

Session的緩存由hibernate維護,用戶不能操作緩存內容; 如果想操作緩存內容,必須通過hibernate提供的evit/clear方法操作。

二級緩存:

二級緩存是基於應用程序的緩存,所有的Session都可以使用

Hibernate提供的二級緩存有默認的實現,且是一種可插配的緩存框架!如果用戶想用二級緩存,只需要在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影響代碼。

如果用戶覺得hibernate提供的框架框架不好用,自己可以換其他的緩存框架或自己實現緩存框架都可以。

Hibernate二級緩存:存儲的是常用的類

191、Hibernate的查詢方式有幾種

一、對象導航查詢(objectcomposition)

二、HQL查詢

1、 屬性查詢

2、 參數查詢、命名參數查詢

3、 關聯查詢

4、 分頁查詢

5、 統計函數

三、Criteria 查詢

四、SQLQuery本地SQL查詢

192、如何優化Hibernate?

Ø 數據庫設計調整

Ø HQL優化

Ø API的正確使用(如根據不同的業務類型選用不同的集合及查詢API)

Ø 主配置參數(日志,查詢緩存,fetch_size, batch_size等)

Ø 映射文件優化(ID生成策略,二級緩存,延遲加載,關聯優化)

Ø 一級緩存的管理

Ø 針對二級緩存,還有許多特有的策略

詳情可參考資料:

193、談談Hibernate中inverse(反轉)的作用

inverse屬性默認是false,就是說關系的兩端都來維護關系。

比如Student和Teacher是多對多關系,用一個中間表TeacherStudent維護。Gp)

如果Student這邊inverse=”true”, 那么關系由另一端Teacher維護,就是說當插入Student時,不會操作TeacherStudent表(中間表)。只有Teacher插入或刪除時才會觸發對中間表的操作。所以兩邊都inverse=”true”是不對的,會導致任何操作都不觸發對中間表的影響;當兩邊都inverse=”false”或默認時,會導致在中間表中插入兩次關系。

如果表之間的關聯關系是“一對多”的話,那么inverse只能在“一”的一方來配置!

194、JDBC hibernate 和 ibatis 的區別

jdbc:手動

手動寫sql

delete、insert、update要將對象的值一個一個取出傳到sql中,不能直接傳入一個對象。

select:返回的是一個resultset,要從ResultSet中一行一行、一個字段一個字段的取出,然后封裝到一個對象中,不直接返回一個對象。

ibatis的特點:半自動化

sql要手動寫

delete、insert、update:直接傳入一個對象

select:直接返回一個對象

hibernate:全自動

不寫sql,自動封裝

delete、insert、update:直接傳入一個對象

select:直接返回一個對象

195、在數據庫中條件查詢速度很慢的時候,如何優化?

建索引

減少表之間的關聯

優化sql,盡量讓sql很快定位數據,不要讓sql做全表查詢,應該走索引,把數據量大的表排在前面

簡化查詢字段,沒用的字段不要,已經對返回結果的控制,盡量返回少量數據

196、什么是SessionFactory,她是線程安全么

SessionFactory 是Hibrenate單例數據存儲和線程安全的,以至於可以多線程同時訪問。一個SessionFactory 在啟動的時候只能建立一次。SessionFactory應該包裝各種單例以至於它能很簡單的在一個應用代碼中儲存.

197、get和load區別

get()立即查詢

load()懶加載

1)get如果沒有找到會返回null, load如果沒有找到會拋出異常。

2)get會先查一級緩存, 再查二級緩存,然后查數據庫;load會先查一級緩存,如果沒有找到,就創建代理對象, 等需要的時候去查詢二級緩存和數據庫。

198、merge的含義:

如果session中存在相同持久化標識(identifier)的實例,用用戶給出的對象的狀態覆蓋舊有的持久實例

如果session沒有相應的持久實例,則嘗試從數據庫中加載,或創建新的持久化實例,最后返回該持久實例

用戶給出的這個對象沒有被關聯到session上,它依舊是托管的

199、persist和save的區別

persist不保證立即執行,可能要等到flush;

persist不更新緩存;

save, 把一個瞬態的實例持久化標識符,及時的產生,它要返回標識符,所以它會立即執行Sql insert

使用 save() 方法保存持久化對象時,該方法返回該持久化對象的標識屬性值(即對應記錄的主鍵值);

使用 persist() 方法來保存持久化對象時,該方法沒有任何返回值。

200、主鍵生成 策略有哪些

主鍵的自動生成策略

identity 自增長(mysql,db2)

sequence 自增長(序列), oracle中自增長是以序列方法實現**

native 自增長【會根據底層數據庫自增長的方式選擇identity或sequence】

如果是mysql數據庫, 采用的自增長方式是identity

如果是oracle數據庫, 使用sequence序列的方式實現自增長

increment 自增長(會有並發訪問的問題,一般在服務器集群環境使用會存在問題。)

指定主鍵生成策略為手動指定主鍵的值

assigned

指定主鍵生成策略為UUID生成的值

uuid

foreign(外鍵的方式)

201、簡述hibernate中getCurrentSession和openSession區別

1、getCurrentSession會綁定當前線程,而openSession不會,因為我們把hibernate交給我們的spring來管理之后,我們是有事務配置,這個有事務的線程就會綁定當前的工廠里面的每一個session,而openSession是創建一個新session。

2、getCurrentSession事務是有spring來控制的,而openSession需要我們手動開啟和手動提交事務,

3、getCurrentSession是不需要我們手動關閉的,因為工廠會自己管理,而openSession需要我們手動關閉。

4、而getCurrentSession需要我們手動設置綁定事務的機制,有三種設置方式,jdbc本地的Thread、JTA、第三種是spring提供的事務管理機制org.springframework.orm.hibernate4.SpringSessionContext,而且srping默認使用該種事務管理機制

202、Hibernate中的命名SQL查詢指的是什么?

命名查詢指的是用<sql-query>標簽在影射文檔中定義的SQL查詢,可以通過使用Session.getNamedQuery()方法對它進行調用。命名查詢使你可以使用你所指定的一個名字拿到某個特定的查詢。

Hibernate中的命名查詢可以使用注解來定義,也可以使用我前面提到的xml影射問句來定義。在Hibernate中,@NameQuery用來定義單個的命名查詢,@NameQueries用來定義多個命名查詢。

203、為什么在Hibernate的實體類中要提供一個無參數的構造器這一點非常重要?

每個Hibernate實體類必須包含一個 無參數的構造器, 這是因為Hibernate框架要使用Reflection API,通過調用Class.newInstance()來創建這些實體類的實例。如果在實體類中找不到無參數的構造器,這個方法就會拋出一個InstantiationException異常。

204、可不可以將Hibernate的實體類定義為final類?

你可以將Hibernate的實體類定義為final類,但這種做法並不好。因為Hibernate會使用代理模式在延遲關聯的情況下提高性能,如果你把實體類定義成final類之后,因為 Java不允許對final類進行擴展,所以Hibernate就無法再使用代理了, 如此一來就限制了使用可以提升性能的手段。

Spring

205、Spring是什么?

Spring是一個輕量級的IoC和AOP容器框架。是為Java應用程序提供基礎性服務的一套框架,目的是用於簡化企業應用程序的開發,它使得開發者只需要關心業務需求。常見的配置方式有三種:基於XML的配置、基於注解的配置、基於Java的配置。

主要由以下幾個模塊組成:

Spring Core:核心類庫,提供IOC服務;

Spring Context:提供框架式的Bean訪問方式,以及企業級功能(JNDI、定時任務等);

Spring AOP:AOP服務;

Spring DAO:對JDBC的抽象,簡化了數據訪問異常的處理;

Spring ORM:對現有的ORM框架的支持;

Spring Web:提供了基本的面向Web的綜合特性,例如多方文件上傳;

Spring MVC:提供面向Web應用的Model-View-Controller實現。

206、Spring 的優點?

(1)spring屬於低侵入式設計,代碼的污染極低;

(2)spring的DI機制將對象之間的依賴關系交由框架處理,減低組件的耦合性;

(3)Spring提供了AOP技術,支持將一些通用任務,如安全、事務、日志、權限等進行集中式管理,從而提供更好的復用。

(4)spring對於主流的應用框架提供了集成支持。

207、Spring的AOP理解:

OOP面向對象,允許開發者定義縱向的關系,但並適用於定義橫向的關系,導致了大量代碼的重復,而不利於各個模塊的重用。

AOP,一般稱為面向切面,作為面向對象的一種補充,用於將那些與業務無關,但卻對多個對象產生影響的公共行為和邏輯,抽取並封裝為一個可重用的模塊,這個模塊被命名為“切面”(Aspect),減少系統中的重復代碼,降低了模塊間的耦合度,同時提高了系統的可維護性。可用於權限認證、日志、事務處理。

AOP實現的關鍵在於 代理模式,AOP代理主要分為靜態代理和動態代理。靜態代理的代表為AspectJ;動態代理則以Spring AOP為代表。

(1)AspectJ是靜態代理的增強,所謂靜態代理,就是AOP框架會在編譯階段生成AOP代理類,因此也稱為編譯時增強,他會在編譯階段將AspectJ(切面)織入到Java字節碼中,運行的時候就是增強之后的AOP對象。

(2)Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改字節碼,而是每次運行時在內存中臨時為方法生成一個AOP對象,這個AOP對象包含了目標對象的全部方法,並且在特定的切點做了增強處理,並回調原對象的方法。

Spring AOP中的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理:

        ①JDK動態代理只提供接口的代理,不支持類的代理。核心InvocationHandler接口和Proxy類,InvocationHandler 通過invoke()方法反射來調用目標類中的代碼,動態地將橫切邏輯和業務編織在一起;接着,Proxy利用 InvocationHandler動態創建一個符合某一接口的的實例,  生成目標類的代理對象。

        ②如果代理類沒有實現 InvocationHandler 接口,那么Spring AOP會選擇使用CGLIB來動態代理目標類。CGLIB(Code Generation Library),是一個代碼生成的類庫,可以在運行時動態的生成指定類的一個子類對象,並覆蓋其中特定方法並添加增強代碼,從而實現AOP。CGLIB是通過繼承的方式做的動態代理,因此如果某個類被標記為final,那么它是無法使用CGLIB做動態代理的。

(3)靜態代理與動態代理區別在於生成AOP代理對象的時機不同,相對來說AspectJ的靜態代理方式具有更好的性能,但是AspectJ需要特定的編譯器進行處理,而Spring AOP則無需特定的編譯器處理。

 InvocationHandler 的 invoke(Object  proxy,Method  method,Object[] args):proxy是最終生成的代理實例;  method 是被代理目標實例的某個具體方法;  args 是被代理目標實例某個方法的具體入參, 在方法反射調用時使用。

208、Spring的IoC理解:

(1)IOC就是控制反轉,是指創建對象的控制權的轉移,以前創建對象的主動權和時機是由自己把控的,而現在這種權力轉移到Spring容器中,並由容器根據配置文件去創建實例和管理各個實例之間的依賴關系,對象與對象之間松散耦合,也利於功能的復用。DI依賴注入,和控制反轉是同一個概念的不同角度的描述,即 應用程序在運行時依賴IoC容器來動態注入對象需要的外部資源。

(2)最直觀的表達就是,IOC讓對象的創建不用去new了,可以由spring自動生產,使用java的反射機制,根據配置文件在運行時動態的去創建對象以及管理對象,並調用對象的方法的。

(3)Spring的IOC有三種注入方式 :構造器注入、setter方法注入、根據注解注入。

IoC讓相互協作的組件保持松散的耦合,而AOP編程允許你把遍布於應用各層的功能分離出來形成可重用的功能組件。

209、BeanFactory和ApplicationContext有什么區別?

BeanFactory和ApplicationContext是Spring的兩大核心接口,都可以當做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

(1)BeanFactory:是Spring里面最底層的接口,包含了各種Bean的定義,讀取bean配置文檔,管理bean的加載、實例化,控制bean的生命周期,維護bean之間的依賴關系。ApplicationContext接口作為BeanFactory的派生,除了提供BeanFactory所具有的功能外,還提供了更完整的框架功能:

①繼承MessageSource,因此支持國際化。

②統一的資源文件訪問方式。

③提供在監聽器中注冊bean的事件。

④同時加載多個配置文件。

⑤載入多個(有繼承關系)上下文 ,使得每一個上下文都專注於一個特定的層次,比如應用的web層。

(2)①BeanFactroy采用的是延遲加載形式來注入Bean的,即只有在使用到某個Bean時(調用getBean()),才對該Bean進行加載實例化。這樣,我們就不能發現一些存在的Spring的配置問題。如果Bean的某一個屬性沒有注入,BeanFacotry加載后,直至第一次使用調用getBean方法才會拋出異常。

②ApplicationContext,它是在容器啟動時,一次性創建了所有的Bean。這樣,在容器啟動時,我們就可以發現Spring中存在的配置錯誤,這樣有利於檢查所依賴屬性是否注入。 ApplicationContext啟動后預載入所有的單實例Bean,通過預載入單實例bean ,確保當你需要的時候,你就不用等待,因為它們已經創建好了。

 ③相對於基本的BeanFactory,ApplicationContext 唯一的不足是占用內存空間。當應用程序配置Bean較多時,程序啟動較慢。

(3)BeanFactory通常以編程的方式被創建,ApplicationContext還能以聲明的方式創建,如使用ContextLoader。

(4)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但兩者之間的區別是:BeanFactory需要手動注冊,而ApplicationContext則是自動注冊。

210、請解釋Spring Bean的生命周期?

       首先說一下Servlet的生命周期:實例化,初始init,接收請求service,銷毀destroy;

 Spring上下文中的Bean生命周期也類似,如下:

(1)實例化Bean:

對於BeanFactory容器,當客戶向容器請求一個尚未初始化的bean時,或初始化bean的時候需要注入另一個尚未初始化的依賴時,容器就會調用createBean進行實例化。對於ApplicationContext容器,當容器啟動結束后,通過獲取BeanDefinition對象中的信息,實例化所有的bean。

(2)設置對象屬性(依賴注入):

實例化后的對象被封裝在BeanWrapper對象中,緊接着,Spring根據BeanDefinition中的信息 以及 通過BeanWrapper提供的設置屬性的接口完成依賴注入。

(3)處理Aware接口:

接着,Spring會檢測該對象是否實現了xxxAware接口,並將相關的xxxAware實例注入給Bean:

①如果這個Bean已經實現了BeanNameAware接口,會調用它實現的setBeanName(String beanId)方法,此處傳遞的就是Spring配置文件中Bean的id值;

②如果這個Bean已經實現了BeanFactoryAware接口,會調用它實現的setBeanFactory()方法,傳遞的是Spring工廠自身。

③如果這個Bean已經實現了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文;

(4)BeanPostProcessor:

如果想對Bean進行一些自定義的處理,那么可以讓Bean實現了BeanPostProcessor接口,那將會調用postProcessBeforeInitialization(Object obj, String s)方法。

(5)InitializingBean 與 init-method:

如果Bean在Spring配置文件中配置了 init-method 屬性,則會自動調用其配置的初始化方法。

(6)如果這個Bean實現了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法;由於這個方法是在Bean初始化結束時調用的,所以可以被應用於內存或緩存技術;

以上幾個步驟完成后,Bean就已經被正確創建了,之后就可以使用這個Bean了。

(7)DisposableBean:

當Bean不再需要時,會經過清理階段,如果Bean實現了DisposableBean這個接口,會調用其實現的destroy()方法;

(8)destroy-method:

最后,如果這個Bean的Spring配置中配置了destroy-method屬性,會自動調用其配置的銷毀方法。

211、 解釋Spring支持的幾種bean的作用域。

Spring容器中的bean可以分為5個范圍:

(1)singleton:默認,每個容器中只有一個bean的實例,單例的模式由BeanFactory自身來維護。

(2)prototype:為每一個bean請求提供一個實例。

(3)request:為每一個網絡請求創建一個實例,在請求完成以后,bean會失效並被垃圾回收器回收。

(4)session:與request范圍類似,確保每個session中有一個bean的實例,在session過期后,bean會隨之失效。

(5)global-session:全局作用域,global-session和Portlet應用相關。當你的應用部署在Portlet容器中工作時,它包含很多portlet。如果你想要聲明讓所有的portlet共用全局的存儲變量的話,那么這全局變量需要存儲在global-session中。全局作用域與Servlet中的session作用域效果相同。

212、Spring框架中的單例Beans是線程安全的么?

Spring框架並沒有對單例bean進行任何多線程的封裝處理。關於單例bean的線程安全和並發問題需要開發者自行去搞定。但實際上,大部分的Spring bean並沒有可變的狀態(比如Serview類和DAO類),所以在某種程度上說Spring的單例bean是線程安全的。如果你的bean有多種狀態的話(比如 View Model 對象),就需要自行保證線程安全。最淺顯的解決辦法就是將多態bean的作用域由“singleton”變更為“prototype”。

213、Spring如何處理線程並發問題?

在一般情況下,只有無狀態的Bean才可以在多線程環境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域,因為Spring對一些Bean中非線程安全狀態采用ThreadLocal進行處理,解決線程安全問題。

ThreadLocal和線程同步機制都是為了解決多線程中相同變量的訪問沖突問題。同步機制采用了“時間換空間”的方式,僅提供一份變量,不同的線程在訪問前需要獲取鎖,沒獲得鎖的線程則需要排隊。而ThreadLocal采用了“空間換時間”的方式。

ThreadLocal會為每一個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問沖突。因為每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的變量封裝進ThreadLocal。

 

214、Spring基於xml注入bean的幾種方式:

(1)Set方法注入;

(2)構造器注入:①通過index設置參數的位置;②通過type設置參數類型;

(3)靜態工廠注入;

(4)實例工廠;

215、Spring的自動裝配:

在spring中,對象無需自己查找或創建與其關聯的其他對象,由容器負責把需要相互協作的對象引用賦予各個對象,使用autowire來配置自動裝載模式。

在Spring框架xml配置中共有5種自動裝配:

(1)no:默認的方式是不進行自動裝配的,通過手工設置ref屬性來進行裝配bean。

(2)byName:通過bean的名稱進行自動裝配,如果一個bean的 property 與另一bean 的name 相同,就進行自動裝配。 

(3)byType:通過參數的數據類型進行自動裝配。

(4)constructor:利用構造函數進行裝配,並且構造函數的參數通過byType進行裝配。

(5)autodetect:自動探測,如果有構造方法,通過 construct的方式自動裝配,否則使用 byType的方式自動裝配。

基於注解的方式:

使用@Autowired注解來自動裝配指定的bean。在使用@Autowired注解之前需要在Spring配置文件進行配置,<context:annotation-config />。在啟動spring IoC時,容器自動裝載了一個AutowiredAnnotationBeanPostProcessor后置處理器,當容器掃描到@Autowied、@Resource或@Inject時,就會在IoC容器自動查找需要的bean,並裝配給該對象的屬性。在使用@Autowired時,首先在容器中查詢對應類型的bean:

如果查詢結果剛好為一個,就將該bean裝配給@Autowired指定的數據;

如果查詢的結果不止一個,那么@Autowired會根據名稱來查找;

如果上述查找的結果為空,那么會拋出異常。解決方法時,使用required=false。

@Autowired可用於:構造函數、成員變量、Setter方法

注:@Autowired和@Resource之間的區別

(1) @Autowired默認是按照類型裝配注入的,默認情況下它要求依賴對象必須存在(可以設置它required屬性為false)。

(2) @Resource默認是按照名稱來裝配注入的,只有當找不到與名稱匹配的bean才會按照類型來裝配注入。

216、Spring 框架中都用到了哪些設計模式?

(1)工廠模式:BeanFactory就是簡單工廠模式的體現,用來創建對象的實例;

(2)單例模式:Bean默認為單例模式。

(3)代理模式:Spring的AOP功能用到了JDK的動態代理和CGLIB字節碼生成技術;

(4)模板方法:用來解決代碼重復的問題。比如. RestTemplate, JmsTemplate, JpaTemplate。

(5)觀察者模式:定義對象鍵一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴於它的對象都會得到通知被制動更新,如Spring中listener的實現--ApplicationListener。

217、Spring事務的實現方式和實現原理:

Spring事務的本質其實就是數據庫對事務的支持,沒有數據庫的事務支持,spring是無法提供事務功能的。真正的數據庫層的事務提交和回滾是通過binlog或者redo log實現的。

(1)Spring事務的種類:

spring支持編程式事務管理和聲明式事務管理兩種方式:

①編程式事務管理使用TransactionTemplate。

②聲明式事務管理建立在AOP之上的。其本質是通過AOP功能,對方法前后進行攔截,將事務處理的功能編織到攔截的方法中,也就是在目標方法開始之前加入一個事務,在執行完目標方法之后根據執行情況提交或者回滾事務。

聲明式事務最大的優點就是不需要在業務邏輯代碼中摻雜事務管理的代碼,只需在配置文件中做相關的事務規則聲明或通過@Transactional注解的方式,便可以將事務規則應用到業務邏輯中。

聲明式事務管理要優於編程式事務管理,這正是spring倡導的非侵入式的開發方式,使業務代碼不受污染,只要加上注解就可以獲得完全的事務支持。唯一不足地方是,最細粒度只能作用到方法級別,無法做到像編程式事務那樣可以作用到代碼塊級別。

(2)spring的事務傳播行為:

spring事務的傳播行為說的是,當多個事務同時存在的時候,spring如何處理這些事務的行為。

① PROPAGATION_REQUIRED:如果當前沒有事務,就創建一個新事務,如果當前存在事務,就加入該事務,該設置是最常用的設置。

② PROPAGATION_SUPPORTS:支持當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就以非事務執行。‘

③ PROPAGATION_MANDATORY:支持當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就拋出異常。

④ PROPAGATION_REQUIRES_NEW:創建新事務,無論當前存不存在事務,都創建新事務。

⑤ PROPAGATION_NOT_SUPPORTED:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。

⑥ PROPAGATION_NEVER:以非事務方式執行,如果當前存在事務,則拋出異常。

⑦ PROPAGATION_NESTED:如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則按REQUIRED屬性執行。

(3)Spring中的隔離級別:

① ISOLATION_DEFAULT:這是個 PlatfromTransactionManager 默認的隔離級別,使用數據庫默認的事務隔離級別。

② ISOLATION_READ_UNCOMMITTED:讀未提交,允許另外一個事務可以看到這個事務未提交的數據。

③ ISOLATION_READ_COMMITTED:讀已提交,保證一個事務修改的數據提交后才能被另一事務讀取,而且能看到該事務對已有記錄的更新。

④ ISOLATION_REPEATABLE_READ:可重復讀,保證一個事務修改的數據提交后才能被另一事務讀取,但是不能看到該事務對已有記錄的更新。

⑤ ISOLATION_SERIALIZABLE:一個事務在執行的過程中完全看不到其他事務對數據庫所做的更新。

13、Spring框架中有哪些不同類型的事件?

Spring 提供了以下5種標准的事件:

(1)上下文更新事件(ContextRefreshedEvent):在調用ConfigurableApplicationContext 接口中的refresh()方法時被觸發。

(2)上下文開始事件(ContextStartedEvent):當容器調用ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發該事件。

(3)上下文停止事件(ContextStoppedEvent):當容器調用ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件。

(4)上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷毀。

(5)請求處理事件(RequestHandledEvent):在Web應用中,當一個http請求(request)結束觸發該事件。

如果一個bean實現了ApplicationListener接口,當一個ApplicationEvent 被發布以后,bean會自動被通知。

 

14、解釋一下Spring AOP里面的幾個名詞:

(1)切面(Aspect):被抽取的公共模塊,可能會橫切多個對象。 在Spring AOP中,切面可以使用通用類(基於模式的風格) 或者在普通類中以 @AspectJ 注解來實現。

(2)連接點(Join point):指方法,在Spring AOP中,一個連接點 總是 代表一個方法的執行。 

(3)通知(Advice):在切面的某個特定的連接點(Join point)上執行的動作。通知有各種類型,其中包括“around”、“before”和“after”等通知。許多AOP框架,包括Spring,都是以攔截器做通知模型, 並維護一個以連接點為中心的攔截器鏈。

(4)切入點(Pointcut):切入點是指 我們要對哪些Join point進行攔截的定義。通過切入點表達式,指定攔截的方法,比如指定攔截add*、search*。

(5)引入(Introduction):(也被稱為內部類型聲明(inter-type declaration))。聲明額外的方法或者某個類型的字段。Spring允許引入新的接口(以及一個對應的實現)到任何被代理的對象。例如,你可以使用一個引入來使bean實現 IsModified 接口,以便簡化緩存機制。

(6)目標對象(Target Object): 被一個或者多個切面(aspect)所通知(advise)的對象。也有人把它叫做 被通知(adviced) 對象。 既然Spring AOP是通過運行時代理實現的,這個對象永遠是一個 被代理(proxied) 對象。

(7)織入(Weaving):指把增強應用到目標對象來創建新的代理對象的過程。Spring是在運行時完成織入。

切入點(pointcut)和連接點(join point)匹配的概念是AOP的關鍵,這使得AOP不同於其它僅僅提供攔截功能的舊技術。 切入點使得定位通知(advice)可獨立於OO層次。 例如,一個提供聲明式事務管理的around通知可以被應用到一組橫跨多個對象中的方法上(例如服務層的所有業務操作)。

218、Spring通知有哪些類型?

(1)前置通知(Before advice):在某連接點(join point)之前執行的通知,但這個通知不能阻止連接點前的執行(除非它拋出一個異常)。

(2)返回后通知(After returning advice):在某連接點(join point)正常完成后執行的通知:例如,一個方法沒有拋出任何異常,正常返回。 

(3)拋出異常后通知(After throwing advice):在方法拋出異常退出時執行的通知。 

(4)后通知(After (finally) advice):當某連接點退出的時候執行的通知(不論是正常返回還是異常退出)。 

(5)環繞通知(Around Advice):包圍一個連接點(join point)的通知,如方法調用。這是最強大的一種通知類型。 環繞通知可以在方法調用前后完成自定義的行為。它也會選擇是否繼續執行連接點或直接返回它們自己的返回值或拋出異常來結束執行。 環繞通知是最常用的一種通知類型。大部分基於攔截的AOP框架,例如Nanning和JBoss4,都只提供環繞通知。 

同一個aspect,不同advice的執行順序:

①沒有異常情況下的執行順序:

around before advice

before advice

target method 執行

around after advice

after advice

afterReturning

 

②有異常情況下的執行順序:

around before advice

before advice

target method 執行

around after advice

after advice

afterThrowing:異常發生

java.lang.RuntimeException: 異常發生

Spring Boot

218、什么是 Spring Boot?

Spring Boot 是 Spring 開源組織下的子項目,是 Spring 組件一站式解決方案,主要是簡化了使用 Spring 的難度,簡省了繁重的配置,提供了各種啟動器,開發者能快速上手。集成了44種服務。

219、為什么要用 Spring Boot?

Spring Boot 優點非常多,如:

獨立運行

簡化配置

應用監控(本地調試生產環境)

上手容易

220、Spring Boot 的核心配置文件有哪幾個?它們的區別是什么?

Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。

application 配置文件這個容易理解,主要用於 Spring Boot 項目的自動化配置。

bootstrap 配置文件有以下幾個應用場景。

使用 Spring Cloud Config 配置中心時,這時需要在 bootstrap 配置文件中添加連接到配置中心的配置屬性來加載外部配置中心的配置信息;

一些固定的不能被覆蓋的屬性;

一些加密/解密的場景;

具體請看這篇文章《Spring Boot 核心配置文件詳解》。

221、Spring Boot 的配置文件有哪幾種格式?它們有什么區別?

.properties 和 .yml,它們的區別主要是書寫格式不同。

1).properties

app.user.name = javastack

2).yml

app:

  user:

    name: javastack

另外,.yml 格式不支持 @PropertySource 注解導入配置。

他們都要求層級關系。

222、Spring Boot 的核心注解是哪個?它主要由哪幾個注解組成的?

啟動類上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要組合包含了以下 3 個注解:

@SpringBootConfiguration:組合了 @Configuration 注解,實現配置文件的功能。

@EnableAutoConfiguration:打開自動配置的功能,也可以關閉某個自動配置的選項,如關閉數據源自動配置功能@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。

@ComponentScan:Spring組件掃描。

223、開啟 Spring Boot 特性有哪幾種方式?

1)繼承spring-boot-starter-parent項目

2)導入spring-boot-dependencies項目依賴

224、Spring Boot 需要獨立的容器運行嗎?

可以不需要,內置了 Tomcat/ Jetty 等容器。

225、運行 Spring Boot 有哪幾種方式?

1)打包用命令或者放到容器中運行

2)用 Maven/ Gradle 插件運行

3)直接執行 main 方法運行

226、Spring Boot 自動配置原理是什么?

注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自動配置的核心,首先它得是一個配置文件,其次根據類路徑下是否有這個類去自動配置。

227、Spring Boot 的目錄結構是怎樣的?

cn

 +- javastack

     +- MyApplication.java

     |

     +- customer

     |   +- Customer.java

     |   +- CustomerController.java

     |   +- CustomerService.java

     |   +- CustomerRepository.java

     |

     +- order

         +- Order.java

         +- OrderController.java

         +- OrderService.java

         +- OrderRepository.java

Application類要處於bean的最上一層,否則掃描不到層級高於它的bean。這個目錄結構是主流及推薦的做法,而在主入口類上加上 @SpringBootApplication 注解來開啟 Spring Boot 的各項能力,如自動配置、組件掃描等。具體看這篇文章《Spring Boot 主類及目錄結構介紹》。

228、你如何理解 Spring Boot 中的 Starters?

Starters可以理解為啟動器,它包含了一系列可以集成到應用里面的依賴包,你可以一站式集成 Spring 及其他技術,而不需要到處找示例代碼和依賴包。如你想使用 Spring JPA 訪問數據庫,只要加入 spring-boot-starter-data-jpa 啟動器依賴就能使用了。

Starters包含了許多項目中需要用到的依賴,它們能快速持續的運行,都是一系列得到支持的管理傳遞性依賴。具體請看這篇文章《Spring Boot Starters啟動器》。

229、如何在 Spring Boot 啟動的時候運行一些特定的代碼?

可以實現接口 ApplicationRunner 或者 CommandLineRunner,這兩個接口實現方式一樣,它們都只提供了一個 run 方法,具體請看這篇文章《Spring Boot Runner啟動器》。

230、Spring Boot 有哪幾種讀取配置的方式?

Spring Boot 可以通過 @PropertySource,@Value,@Environment, @ConfigurationProperties 來綁定變量,具體請看這篇文章《Spring Boot讀取配置的幾種方式》。

231、Spring Boot 支持哪些日志框架?推薦和默認的日志框架是哪個?

Spring Boot 支持 Java Util Logging, Log4j2, Lockback 作為日志框架,如果你使用 Starters 啟動器,Spring Boot 將使用 Logback 作為默認日志框架,具體請看這篇文章《Spring Boot日志集成》。

232、SpringBoot 實現熱部署有哪幾種方式?

主要有兩種方式:

Spring Loaded

Spring-boot-devtools

233、你如何理解 Spring Boot 配置加載順序?

在 Spring Boot 里面,可以使用以下幾種方式來加載配置。

1)properties文件;

2)YAML文件;

3)系統環境變量;

4)命令行參數;

234、Spring Boot 如何定義多套不同環境配置?

提供多套配置文件,如:

applcation.properties

application-dev.properties

application-test.properties

application-prod.properties

運行時指定具體的配置文件,具體請看這篇文章《Spring Boot Profile 不同環境配置》。

235、Spring Boot 可以兼容老 Spring 項目嗎,如何做?

可以兼容,使用 @ImportResource 注解導入老 Spring 項目配置文件。

236、保護 Spring Boot 應用有哪些方法?

在生產中使用HTTPS

使用Snyk檢查你的依賴關系

升級到最新版本

啟用CSRF保護

使用內容安全策略防止XSS攻擊

237、Spring Boot 2.X 有什么新特性?與 1.X 有什么區別?

配置變更

JDK 版本升級

第三方類庫升級

響應式 Spring 編程支持

HTTP/2 支持

配置屬性綁定

更多改進與加強…

數據庫

238、什么是事務?

事務是一種機制,一個操作序列,它包含了一組數據庫操作命令,並當做一個整體提交。要么都執行,要么都不執行。

239、事務四大特性ACID

*原子性Atomicity:不可分割的操作單元,事務中所有操作,要么全部成功;要么撤回到執行事務之前的狀態

*一致性Consistency:如果在執行事務之前數據庫是一致的,那么在執行事務之后數據庫也還是一致的;

*隔離性Isolation:事務操作之間彼此獨立和透明互不影響。事務獨立運行。這通常使用鎖來實現。一個事務處理后的結果,影響了其他事務,那么其他事務會撤回。事務的100%隔離,需要犧牲速度。

*持久性Durability:事務一旦提交,其結果就是永久的。即便發生系統故障,也能恢復。

240、MySQL的事務隔離級別

①未提交讀(Read Uncommitted):允許臟讀,其他事務只要修改了數據,即使未提交,本事務也能看到修改后的數據值。也就是可能讀取到其他會話中未提交事務修改的數據

②提交讀(Read Committed):只能讀取到已經提交的數據。Oracle等多數數據庫默認都是該級別 (不重復讀)。

③可重復讀(Repeated Read):可重復讀。無論其他事務是否修改並提交了數據,在這個事務中看到的數據值始終不受其他事務影響。

④串行讀(Serializable):完全串行化的讀,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞

MySQL數據庫(InnoDB引擎)默認使用可重復讀( Repeatable read)

241、索引

數據庫索引,是數據庫管理系統中一個排序的數據結構,以協助快速查詢、更新數據庫表中數據。采取的是空間換時間的概念。

MyISAM引擎和InnoDB引擎使用B+Tree作為索引結構

242、MySQL數據庫的四類索引:

  index  ----  普通索引,數據可以重復,沒有任何限制。

  unique   ---- 唯一索引,要求索引列的值必須唯一,但允許有空值;如果是組合索引,那么列值的組合必須唯一。

  primary key ---- 主鍵索引,是一種特殊的唯一索引,一個表只能有一個主鍵,不允許有空值,一般是在創建表的同時創建主鍵索引。

  組合索引 ----  在多個字段上創建的索引,只有在查詢條件中使用了創建索引時的第一個字段,索引才會被使用。

  fulltext ---- 全文索引,是對於大表的文本域:char,varchar,text列才能創建全文索引,主要用於查找文本中的關鍵字,並不是直接與索引中的值進行比較。fulltext更像是一個搜索引擎,配合match against操作使用,而不是一般的where語句加like。

  注:全文索引目前只有MyISAM存儲引擎支持全文索引,InnoDB引擎5.6以下版本還不支持全文索引

  所有存儲引擎對每個表至少支持16個索引,總索引長度至少為256字節,索引有兩種存儲類型,包括B型樹索引和哈希索引。

  索引可以提高查詢的速度,但是創建和維護索引需要耗費時間,同時也會影響插入的速度,如果需要插入大量的數據時,最好是先刪除索引,插入數據后再建立索引。

243、索引生效條件

假設index(a,b,c)

1)最左前綴匹配:模糊查詢時,使用%匹配時:’a%‘會使用索引,’%a‘不會使用索引

2)條件中有or,索引不會生效

3) a and c,a生效,c不生效

b and c,都不生效

檢測索引的效果:

show status like '%handler_read%'越大越好

244、sql語句分類:

DDL:數據定義語言(create drop)

DML:數據操作語句(insert update delete)

DQL:數據查詢語句(select )

DCL:數據控制語句,進行授權和權限回收(grant revoke)

TPL:數據事務語句(commit collback savapoint)

245、數據庫三范式:

第一范式:確保每列的原子性,確保每列都是最小的不可再分割的數據單元。

第二范式:確保表中的每列都和主鍵相關。

第三范式:確保每列都和主鍵直接相關,而不是間接相關。除了主鍵列,其他的列和列之間不存在依賴關系。

246、臟讀&不可重復讀&幻讀

*臟讀: 是指事務T1將某一值修改,然后事務T2讀取該值,此后T1因為某種原因撤銷對該值的修改,這就導致了T2所讀取到的數據是無效的。

*不可重復讀 :是指在數據庫訪問時,一個事務范圍內的兩次相同查詢卻返回了不同數據。在一個事務內多次讀同一數據。在這個事務還沒有結束時,另外一個事務也訪問該同一數據。那么在第一個事務中的兩次讀數據之間,由於第二個事務的修改,第一個事務兩次讀到的的數據可能是不一樣的。這樣在一個事務內兩次讀到的數據是不一樣的,因此稱為是不可重復讀。

*幻讀: 是指當事務不是獨立執行時發生的一種現象,比如第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那么就會發生,操作第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺一樣。

不可重復讀&幻讀區別:

如果使用鎖機制來實現這兩種隔離級別,在可重復讀中,該sql第一次讀取到數據后,就將這些數據加鎖,其它事務無法修改這些數據,就可以實現可重復讀了。但這種方法卻無法鎖住insert的數據,所以當事務A先前讀取了數據,或者修改了全部數據,事務B還是可以insert數據提交,這時事務A就會發現莫名其妙多了一條之前沒有的數據,這就是幻讀,不能通過行鎖來避免。需要Serializable隔離級別 ,讀用讀鎖,寫用寫鎖,讀鎖和寫鎖互斥,這么做可以有效的避免幻讀、不可重復讀、臟讀等問題,但會極大的降低數據庫的並發能力。

不可重復讀重點在於update和delete,而幻讀的重點在於insert。如何通過鎖機制來解決他們產生的問題

247、mysql的存儲引擎

1)MyISAM 不支持事務,不支持外鍵,優勢是訪問速度快,對事務完整性沒有要求,或者以select、insert為主的可以使用

2)InnoDB 支持事務,外鍵約束,自增,寫的效率差一些,更占據空間

3)Memory 使用內存中的內容來創建表,訪問速度非常快,使用哈希索引。但是一旦服務關閉,表中的數據就會丟失。

4)Merge 是一組MyISAM表的組合,這些表必須結構完全相同,merge本身沒有數據。對merge的查詢、更新、刪除實際是對MyISAM的修改。

248、存儲引擎 MyISAM和InnoDB區別:

1)InnoDB支持事務,MyISAM不支持。

2)MyISAM適合查詢以及插入為主的應用,InnoDB適合頻繁修改以及涉及到安全性較高的應用。

3)InnoDB支持外鍵,MyISAM不支持。

4)從MySQL5.5.5以后,InnoDB是默認引擎。

5)MyISAM支持全文類型索引,而InnoDB不支持全文索引。

6)InnoDB中不保存表的總行數,select count(*) from table時,InnoDB需要掃描整個表計算有多少行,但MyISAM只需簡單讀出保存好的總行數即可。注:當count(*)語句包含where條件時MyISAM也需掃描整個表。

7)對於自增長的字段,InnoDB中必須包含只有該字段的索引,但是在MyISAM表中可以和其他字段一起建立聯合索引。

8)清空整個表時,InnoDB是一行一行的刪除,效率非常慢。MyISAM則會重建表。MyisAM使用delete語句刪除后並不會立刻清理磁盤空間,需要定時清理,命令:OPTIMIZE table dept;

9)InnoDB支持行鎖(某些情況下還是鎖整表,如 update table set a=1 where user like ‘%lee%’)

10)Myisam創建表生成三個文件:.frm 數據表結構 、 .myd 數據文件 、 .myi 索引文件,Innodb只生成一個 .frm文件,數據存放在ibdata1.log

現在一般都選用InnoDB,主要是MyISAM的全表鎖,讀寫串行問題,並發效率鎖表,效率低,MyISAM對於讀寫密集型應用一般是不會去選用的。

應用場景:

MyISAM不支持事務處理等高級功能,但它提供高速存儲和檢索,以及全文搜索能力。如果應用中需要執行大量的SELECT查詢,那么MyISAM是更好的選擇。

InnoDB用於需要事務處理的應用程序,包括ACID事務支持。如果應用中需要執行大量的INSERT或UPDATE操作,則應該使用InnoDB,這樣可以提高多用戶並發操作的性能。

249、CHAR和VARCHAR的區別:

CHAR和VARCHAR類型在存儲和檢索方面有所不同

CHAR列長度固定為創建表時聲明的長度,長度值范圍是1到255

當CHAR值被存儲時,它們被用空格填充到特定長度,檢索CHAR值時需刪除尾隨空格。

250、數據庫使用

1.    一些全表掃描的慎用,or、like、<>、distinct(排除)、not in、not exists,not null的慎用。如有必然請用正向邏輯。

2.    一些重要操作請開啟事物

3.    數據庫不擅長運算,請把你的運算放在邏輯代碼中,或者放在=號右邊。

4.    Limit分頁的提醒,limit 10000,10所查詢到的結果是1到10010條,而不是你所想的10條。大量數據請記得優化。

5.    Sql執行順序:

(1)FROM [left_table]

(2)ON <join_condition>

(3)<join_type> JOIN <right_table>

(4)WHERE <where_condition>

(5)GROUP BY <group_by_list>

(6)WITH <CUBE | RollUP>

(7)HAVING <having_condition>

(8)SELECT

(9)DISTINCT 

(10)ORDER BY <order_by_list>

(11)<Top Num> <select list>

251、數據庫查詢優化

1)避免全部掃描,比如對null值進行篩選判讀;使用!=或<>、like、or等等都將放棄索引全表掃描

2)考慮在where及order by涉及的列上建立索引

3)使用正向邏輯(not in,not exists)

4)數據庫不擅長運算,把運算交給邏輯代碼,非要有把運算放在右邊

5)合理建表,使用合理的字段,善用非空、外鍵約束保證數據的完整性

6)索引並不是越多越好,一個表最好不要超過6個,多了影響增、刪、改的性能。這個影響很大

7)多從業務邏輯方面考慮問題,合理使用中間件

8)對於數據量太大的數據分庫分表,使用中間件比如mycat

252、分表分庫

①:垂直分割(並不常用)

就是將一個表按照字段來分,每張表保證有相同的主鍵就好。一般來說,將常用字段和大字段分表來放。

優勢:比沒有分表來說,提高了查詢速度,降低了查詢結果所用內存;

劣勢:沒有解決大量記錄的問題,對於單表來說隨着記錄增多,性能還是下降很快;

②: 水平分割(重要,實際應用中使用最多)

水平分割是企業最常用到的,水平拆分就是大表按照記錄分為很多子表:

水平分的規則完全是自定義的,有以下幾種參考設計:

1 hash、自增id取模:

對某個字段進行hash來確定創建幾張表,並根據hash結果存入不同的表;

2 按時間

根據業務可以按照天、月、年來進行拆分;

3 按每個表的固定記錄數

一般按照自增ID進行拆表,一張表的數據行到了指定的數量,就自動保存到下一張表中。比如規定一張表只能存1-1000個記錄;

4 將老數據遷移到一張歷史表

比如日志表,一般只查詢3個月之內的數據,對於超過3個月的記錄將之遷移到歷史子表中;

253、數據庫的備份

什么是物理冷備?科普一下:

(1)熱備:在數據庫運行時,直接進行備份,對運行的數據庫沒有影響。

(2)冷備:在數據庫停止運行的時候進行備份,這種備份方式最為簡單,只需要拷貝數據庫物理文件即可。

(3)溫備:同樣是在數據庫運行的時候進行備份的,但對當前數據庫的操作會產生影響。

熱備份的缺點:

  1.盡量不要出錯,否則后果會很嚴重。

  2.如果熱備份不成功,所得結果不可用於時間點的數據恢復。

  3.維護的工作比較困難。

冷備份的缺點:

  1.單獨使用時,只能提供到"某一時間點的上"的恢復。

  2.再實施備份的全過程中,數據庫必須是關閉狀態。

  3.不能按表或按用戶恢復。

綜上,如果你不是大牛大能,物理備份還是選擇冷備份吧,自動保存7天數據。

254、Mysql中有哪幾種鎖?

MyISAM支持表鎖,InnoDB支持表鎖和行鎖,默認為行鎖

表級鎖:開銷小,加鎖快,不會出現死鎖。鎖定粒度大,發生鎖沖突的概率最高,並發量最低

行級鎖:開銷大,加鎖慢,會出現死鎖。鎖力度小,發生鎖沖突的概率小,並發度最高

255、存儲過程

我們常用的操作數據庫語言SQL語句在執行的時候需要要先編譯,然后執行,而存儲過程(Stored Procedure)是一組為了完成特定功能的SQL語句集,經編譯后存儲在數據庫中,用戶通過指定存儲過程的名字並給定參數(如果該存儲過程帶有參數)來調用執行它。

一個存儲過程是一個可編程的函數,它在數據庫中創建並保存。它可以有SQL語句和一些特殊的控制結構組成。當希望在不同的應用程序或平台上執行相同的函數,或者封裝特定功能時,存儲過程是非常有用的。數據庫中的存儲過程可以看做是對編程中面向對象方法的模擬。它允許控制數據的訪問方式。

優點:

(1).存儲過程增強了SQL語言的功能和靈活性。存儲過程可以用流控制語句編寫,有很強的靈活性,可以完成復雜的判斷和較復雜的運算。

(2).存儲過程允許標准組件是編程。存儲過程被創建后,可以在程序中被多次調用,而不必重新編寫該存儲過程的SQL語句。而且數據庫專業人員可以隨時對存儲過程進行修改,對應用程序源代碼毫無影響。

(3).存儲過程能實現較快的執行速度。如果某一操作包含大量的Transaction-SQL代碼或分別被多次執行,那么存儲過程要比批處理的執行速度快很多。因為存儲過程是預編譯的。在首次運行一個存儲過程時查詢,優化器對其進行分析優化,並且給出最終被存儲在系統表中的執行計划。而批處理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。

(4).存儲過程能過減少網絡流量。針對同一個數據庫對象的操作(如查詢、修改),如果這一操作所涉及的Transaction-SQL語句被組織程存儲過程,那么當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,從而大大增加了網絡流量並降低了網絡負載。

(5).存儲過程可被作為一種安全機制來充分利用。系統管理員通過執行某一存儲過程的權限進行限制,能夠實現對相應的數據的訪問權限的限制,避免了非授權用戶對數據的訪問,保證了數據的安全。

256、delete、drop、truncate區別

truncate 和 delete只刪除數據,不刪除表結構 ,drop刪除表結構,並且釋放所占的空間。

刪除數據的速度,drop> truncate > delete

delete屬於DML語言,需要事務管理,commit之后才能生效。drop和truncate屬於DDL語言,操作立刻生效,不可回滾。

使用場合:

當你不再需要該表時, 用 drop;

當你仍要保留該表,但要刪除所有記錄時, 用 truncate;

當你要刪除部分記錄時(always with a where clause), 用 delete

257、CAP定理(布魯爾定律)

CAP定理(CAP theorem),又被稱作布魯爾定理(Brewer's theorem),它指出對於一個分布式計算系統來說,不可能同時滿足以下三點:

一致性(Consistency)   所有節點訪問同一份最新的數據副本;

可用性(Availability)   每次請求都能獲取到非錯的響應,但是不保證獲取的數據為最新數據;

分區容錯性(Partition tolerance)      分布式系統在遇到任何網絡分區故障的時候,仍然能夠對外提供滿足一致性和可用性的服務,除非整個網絡環境都發生了故障;

CAP之間是不能共存的,我們最多只能滿足兩個條件:

CA (Consistency + Availability):關注一致性和可用性,代表作:關系型數據庫MySQL。

CP (consistency + partition tolerance):關注一致性和分區容錯性,代表作:分布式數據庫hadoop。

AP (availability + partition tolerance):關心可用性和分區容錯性,代表作:非關系型數據庫Redis。

258、Bse理論

BASE 理論是對 CAP 理論的延伸,核心思想是即使無法做到強一致性(Strong Consistency,CAP 的一致性就是強一致性),但應用可以采用適合的方式達到最終一致性(Eventual Consitency)。

基本可用(Basically Available): 基本可用是指分布式系統在出現故障的時候,允許損失部分可用性,即保證核心可用。電商大促時,為了應對訪問量激增,部分用戶可能會被引導到降級頁面,服務層也可能只提供降級服務。這就是損失部分可用性的體現。

軟狀態(Soft State): 軟狀態是指允許系統存在中間狀態,而該中間狀態不會影響系統整體可用性。分布式存儲中一般一份數據至少會有三個副本,允許不同節點間副本同步的延時就是軟狀態的體現。MySQL Replication 的異步復制也是一種體現。

最終一致性(Eventual Consistency): 最終一致性是指系統中的所有數據副本經過一定時間后,最終能夠達到一致的狀態。弱一致性和強一致性相反,最終一致性是弱一致性的一種特殊情況。

Redis

1、什么是redis?

Redis 是一個開源的使用 ANSI C 語言編寫、遵守 BSD 協議、支持網絡、可基於內存亦可持久化的日志型、Key-Value 數據庫,並提供多種語言的 API的非關系型數據庫。

2、Redis支持的數據類型?

1)St ing字符串:格式: set key value

string類型是二進制安全的。意思是redis的string可以包含任何數據。比如jpg圖片或者序列化的對象 。string類型是Redis最基本的數據類型,一個鍵最大能存儲512MB。

2)Hash(哈希)格式: hmset name  key1 value1 key2 value2

Redis hash 是一個鍵值(key=>value)對集合。Redis hash是一個string類型的field和value的映射表,hash特別適合用於存儲對象。

3)   lsit(列表)Redis 列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)

 

4)set(集合)

5)zset(有序集合)

Redis zset 和 set 一樣也是string類型元素的集合,且不允許重復的成員。

不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。

zset的成員是唯一的,但分數(score)卻可以重復。

3、什么是Redis持久化?Redis有哪幾種持久化方式?優缺點是什么?

持久化就是把內存的數據寫到磁盤中去,防止服務宕機了內存數據丟失。

Redis 提供了兩種持久化方式:RDB(默認) 和AOF

RDB:rdb是Redis DataBase縮寫

功能核心函數rdbSave(生成RDB文件)和rdbLoad(從文件加載內存)兩個函數

AOF:Aof是Append-only file縮寫

每當執行服務器(定時)任務或者函數時flushAppendOnlyFile 函數都會被調用, 這個函數執行以下兩個工作

aof寫入保存:

WRITE:根據條件,將 aof_buf 中的緩存寫入到 AOF 文件

SAVE:根據條件,調用 fsync 或 fdatasync 函數,將 AOF 文件保存到磁盤中。

比較:

1、aof文件比rdb更新頻率高,優先使用aof還原數據。

2、aof比rdb更安全也更大

3、rdb性能比aof好

4、如果兩個都配了優先加載AOF

4、什么是RESP?有什么特點?

RESP 是redis客戶端和服務端之前使用的一種通訊協議;

RESP 的特點:實現簡單、快速解析、可讀性好

5、Redis 有哪些架構模式?講講各自的特點

1)單機版

特點:簡單

問題:1、內存容量有限 2、處理能力有限 3、無法高可用。

2)哨兵

Redis sentinel 是一個分布式系統中監控 redis 主從服務器,並在主服務器下線時自動進行故障轉移。其中三個特性:

監控(Monitoring):    Sentinel  會不斷地檢查你的主服務器和從服務器是否運作正常。

提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程序發送通知。

自動故障遷移(Automatic failover): 當一個主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作。

特點:1、保證高可用2、監控各個節點3、自動故障遷移

缺點:主從模式,切換需要時間丟數據,沒有解決 master 寫的壓力

 

3)集群(proxy 型):

Twemproxy 是一個 Twitter 開源的一個 redis 和 memcache 快速/輕量級代理服務器; Twemproxy 是一個快速的單線程代理程序,支持 Memcached ASCII 協議和 redis 協議。

特點:1、多種 hash 算法:MD5、CRC16、CRC32、CRC32a、hsieh、murmur、Jenkins

2、支持失敗節點自動刪除

3、后端 Sharding 分片邏輯對業務透明,業務方的讀寫方式和操作單個 Redis 一致

缺點:增加了新的 proxy,需要維護其高可用。failover 邏輯需要自己實現,其本身不能支持故障的自動轉移可擴展性差,進行擴縮容都需要手動干預

4)集群(直連型):從redis 3.0之后版本支持redis-cluster集群,Redis-Cluster采用無中心結構,每個節點保存數據和整個集群狀態,每個節點都和其他所有節點連接。

特點:1、無中心架構(不存在哪個節點影響性能瓶頸),少了 proxy 層。

2、數據按照 slot 存儲分布在多個節點,節點間數據共享,可動態調整數據分布。

3、可擴展性,可線性擴展到 1000 個節點,節點可動態添加或刪除。

4、高可用性,部分節點不可用時,集群仍可用。通過增加 Slave 做備份數據副本

5、實現故障自動 failover,節點之間通過 gossip 協議交換狀態信息,用投票機制完成 Slave到 Master 的角色提升。

缺點:

1、資源隔離性較差,容易出現相互影響的情況。

2、數據通過異步復制,不保證數據的強一致性

6、使用過Redis分布式鎖么,它是怎么實現的?

先拿setnx來爭搶鎖,搶到之后,再用expire給鎖加一個過期時間防止鎖忘記了釋放。

7、如果在setnx之后執行expire之前進程意外crash或者要重啟維護了,那會怎么樣?

set指令有非常復雜的參數,這個應該是可以同時把setnx和expire合成一條指令來用的!

8、使用過Redis做異步隊列么,你是怎么用的?有什么缺點?

一般使用list結構作為隊列,rpush生產消息,lpop消費消息。當lpop沒有消息的時候,要適當sleep一會再重試。

缺點:在消費者下線的情況下,生產的消息會丟失,得使用專業的消息隊列如rabbitmq等。

9、能不能生產一次消費多次呢?

使用pub/sub主題訂閱者模式,可以實現1:N的消息隊列。

10、什么是緩存穿透?如何避免?什么是緩存雪崩?何如避免?

一般的緩存系統,都是按照key去緩存查詢,如果不存在對應的value,就應該去后端系統查找(比如DB)。一些惡意的請求會故意查詢不存在的key,請求量很大,就會對后端系統造成很大的壓力。這就叫做緩存穿透。

如何避免:

1:對查詢結果為空的情況也進行緩存,緩存時間設置短一點,或者該key對應的數據insert了之后清理緩存。

2:對一定不存在的key進行過濾。可以把所有的可能存在的key放到一個大的Bitmap中,查詢時通過該bitmap過濾。

緩存雪崩:當緩存服務器重啟或者大量緩存集中在某一個時間段失效,這樣在失效的時候,會給后端系統帶來很大壓力。導致系統崩潰。

如何避免:

1:在緩存失效后,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對某個key只允許一個線程查詢數據和寫緩存,其他線程等待。

2:做二級緩存,A1為原始緩存,A2為拷貝緩存,A1失效時,可以訪問A2,A1緩存失效時間設置為短期,A2設置為長期

3:不同的key,設置不同的過期時間,讓緩存失效的時間點盡量均勻。

Web編程Jsp&Servlet技術

257、簡單說說 tomcat的配置?

JAVA_HOME=JDK 的根目錄

CATALINA_HOME=tomcat 的根目錄

CATALINA-HOME\conf\server.xml:可以配置tomcat 的端口,可以配置tomcat 中下連接

池。

CATALINA-HOME\common\lib:存放公用的類包

258、JSP中動態 include與靜態include的區別?

jsp:include:在運行時調用另一個頁面,變量是可以重復的。

<%@include file=””%>:在轉譯時合在一起,會成為同一個類,變量不可以重復。

259、forward和 redirect的區別?

重定向是客戶端行為,轉發是服務器端行為

重定向時服務器產生兩次請求,轉發產生一次請求,重定向時可以轉發到項目以外的任何網址,轉發只能在當前項目里轉發

重定向會導致request對象信息丟失。轉發則不會

轉發的url不會變,request.getRequestDispatch()。forward()

重定向的url會改變,response.getRedirect();

260、Servlet的體系結構是什么?

Servlet

GenericServlet

HttpServlet

自定義

261、如何實現一個自定義的 servlet?

extends HttpServlet 並覆蓋doPost 或doGet 方法

在web.xml 中進行部署

262、Servlet的生命周期是什么?

Init

多次執行doGet 或doPost

destroy

263、jsp就是一個 servlet是否正確?

264、請羅列jsp中的腳本、指令及動作?

腳本

<%%> <%=%> <%!%> <%----%>

指令

<%@page contentType=”text/html;charset=utf-8” language=”java”

import=””%>

<%@include file=””%>

<%@taglib uri=”” prefix=””%>

動作:

<jsp:useBean class=”” id=”” scope=””> 在scope 中如果沒有

實例化一個對象,如果有直接用以前的。

<jsp:getProperty name=”” property=””> 向一個bean 中設置屬性

<jsp:forward > jsp 頁的轉發

<jsp:include page=””> 導入一個jsp 頁面

265、JSP的內置對象及方法

JSP一共有9個內置對象:request、response、session、application、out、pagecontext、config、page、exception。

1、Request request 表示HttpServletRequest 對象。取客戶端表單域信息及cookie,header, 和session

2、response 表示HttpServletResponse 對象,對客戶端的響應返回文本、寫cookies。

3、out 向客戶端打印html 文本.

4、pageContext :當前jsp 頁面的上下文環境,可以得到session、request、application等內置對象,在自定義標簽中使用的很多。

5、session 表示一個請求的javax.servlet.http.HttpSession 對象。Session 一個用戶多個頁面共享同一變量。

6、applicaton 表示一個javax.servle.ServletContext 對象。存放容器級

的變量。

7、config 表示一個javax.servlet.ServletConfig 對象。該對象用於存取servlet實例的初始化參數。

8、page 表示從該頁面產生的一個servlet 實例

9、exception:異常,當iserrorpage=true

266、四種會話跟蹤技術

1).隱藏表單域:<input type="hidden">,非常適合步需要大量數據存儲的會話應用。

2).URL 重寫:URL 可以在后面附加參數,和服務器的請求一起發送,這些參數為名字/值對。

3).Cookie:一個 Cookie 是一個小的,已命名數據元素。服務器使用 SET-Cookie 頭標將它作為 HTTP響應的一部分傳送到客戶端,客戶端被請求保存 Cookie 值,在對同一服務器的后續請求使用一個Cookie 頭標將之返回到服務器。與其它技術比較,Cookie 的一個優點是在瀏覽器會話結束后,甚至在客戶端計算機重啟后它仍可以保留其值

4).Session:使用 setAttribute(String str,Object obj)方法將對象捆綁到一個會話

267、說出在 JSP頁面里是怎么分頁的?

頁面需要保存以下參數:(數據庫的分頁及比較)

總行數:根據sql 語句得到總行數

每頁顯示行數:設定值

當前頁數:請求參數

頁面根據當前頁數和每頁行數計算出當前頁第一行行數,定位結果集到此行,對結果集

取出每頁顯示行數的行即可。

268、include的兩種實現方式的區別?

<@include file>:在將jsp 生成servlet 類前將兩個文件和在一起,生成一個java 類,

一起運行的。所以是一家子,當中的變量名不能重名。

<jsp:include page>:是兩個類,是一個調用關系,在運行時動態的調用,不是一家子,

可以重復變量。

269、jsp頁面中兩種跳轉方式分別是什么?有什么區別?

轉發: 保留上次的request

<jsp:forward>

actionMapping.findForWard(“”);

pageContext.forward();

request.getRequestDispacher(“a.jsp”).forward(request,response)

跳轉:不保留上次的request

Response.setRedirect(“”)

270、描述 JSP和Servlet的區別、共同點、各自應用的范圍

Jsp 主要在於頁面的顯示動態生成頁面,可以與html 標記一起使用,其還是要生成為一個servlet。

Servlet:主要是控制的處理,如調用業務層,跳轉不同的jsp 頁面。

Mvc

Jsp:v

Servlet:c

271、在 JSP中如何讀取客戶端的請求,如何確定某個 Jsp文件的真實路徑?

Request.getparameter(“”)

<%=application.getRealPath("aa.jsp") %>

272、描述 Cookie和Session的作用,區別和各自的應用范圍,Session工作原理。

Cookie:主要用在保存客戶端,其值在客戶端與服務端之間傳送,不安全,存儲的數據量有限。

Session:保存在服務端,每一個session 在服務端有一個sessionID 作一個標識。存儲的數據量大,安全性高。占用服務端的內存資源。

273、說明 Jsp中errorPage的作用,應用范圍。

正常頁面中

%@page erropage=”error.jsp”%

錯誤頁面

<%@page iserrorpage=”true”%>

有一內置對象:exception

274、介紹在 Jsp中如何使用 JavaBeans

<jsp:useBean class=”” id=”” scope=””/>

<%

New 類();

%>

275、簡單介紹 JSP的標記庫

做一個標記處理類extends TagSupport

通過tld 說明標記處理的類的前綴及后綴

在web.xml 中說明tld 文件

<taglib>

<taglib-uri>

<taglib-location>

<taglib>

在jsp 頁面是引用tld<%@taglib uri=”” prefix=””%>

276、Servlet中的核心類有那些,各有什么特點?

ServletContext:容器,放置全局變量

setAtribute()

getAttribute()

ServletConfig:一個servlet 的配置

getInitParameter(”名稱”)

HttpServletRequest:封裝的所有的請求

getParameterValue(”名稱”)

getParameterValues(”稱”)

getSession();

getAttribute(” 名稱”);

getRequestDispatch(”a.jsp”).forward(request,response)

HttpServletResponse:響應

getOut();

sendRedirect(””)

HttpSession:一個用戶多個頁面共享同一變量

setAttribute(””,””)

277、Servlet中重要的包有那些,有什么區別?

javax.servlet.*;javax.servlet.http.*;

278、說出 Servlet的生命周期,並說出 Servlet和 CGI的區別?

Servlet 被服務器實例化后,容器運行其init 方法,請求到達時運行其service 方法,service 方法自動派遣運行與請求對應的doXXX 方法(doGet,doPost)等,當服務器決定將實例銷毀的時候調用其destroy 方法。

與cgi 的區別在於servlet 處理服務器進程中,它通過多線程方式運行其service 方法,一個實例可以服務於多個請求,並且其實例一般不會銷毀,而CGI 對每個請求都產生新的進程,服務完成后就銷毀,所以效率上低於servlet。

279、什么情況下調用 doGet()和doPost()?

Jsp 頁面中的form 標簽里的method 屬性為get 時調用doGet(),為post 時調用

doPost()。

280、如何現實 servlet的單線程模式

在doGet 及doPost 方法前加入synchoronized

JSP:

<%@ page isThreadSafe="true"%>

281、Request對象的主要方法:

setAttribute(String name,Object):設置名字為name 的request 的參數值

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

getAttributeNames():返回request 對象所有屬性的名字集合,結果是一個枚舉的實例

getCookies():返回客戶端的所有Cookie 對象,結果是一個Cookie 數組

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

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

實例

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

getMethod():獲得客戶端向服務器端傳送數據的方法

getParameter(String name):獲得客戶端傳送給服務器端的有name 指定的參數

getParameterNames():獲得客戶端傳送給服務器端的所有參數的名字,結果是一個枚舉的實例

getParameterValues(String name):獲得有name 指定的參數的所有值

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

getQueryString():獲得查詢字符串

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

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

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

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

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

getServletPath():獲取客戶端所請求的腳本文件的路徑

getServerPort():獲取服務器的端口號

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

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

Public String translate (String str) {

String tempStr = "";

try {

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

tempStr = tempStr.trim();

}catch (Exception e) {

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

}

return tempStr;

}

283、Servlet執行時一般實現哪幾個方法?

public void init(ServletConfig config)

public ServletConfig getServletConfig()

public String getServletInfo()

public void service(ServletRequest request,ServletResponse response)

public void destroy()

284、rvlet的執行流程。doGet和doPost的區別

Servlet的執行流程也就是servlet的生命周期,當服務器啟動的時候生命周期開始,然后通過init()《啟動順序根據web.xml里的startup-on-load來確定加載順序》方法初始化servlet,再根據不同請求調用doGet或doPost方法,最后再通過destroy()方法進行銷毀。

doGet和doPost都是接受用戶請求的方法,doGet處理get請求,doPost處理post請求,doGet用於地址欄提交,doPost用於表單提交,在頁面提交數據時,get的數據大小有限制4k,post沒有限制,get請求提交的數據會在地址欄顯示,post不顯示,所以post比get安全.

285、vice有一個實例變量,doGet和doPost去調用這個變量,會出現什么問題,你是如何解決的。

會出現線程不安全問題。無論是doGet還是doPost去調用,服務器端處理的過程都是一樣的,那么我們可以把處理過程單獨寫在另外一個方法handle里,讓兩個方法都去調用handle,根據不同請求去調用不同的方法。

286、servlet的線程不安全問題

線程安全就是多線程操作同一個對象不會有問題,線程同步一般來保護線程安全,所以可以在Servlet的線程里面加上同步方法或同步塊。(Synchronized)可以保證在同一時間只有一個線程訪問,(使用同步塊會導致性能變差,最好不去使用實例變量)

287、Jsp和servlet的區別

jsp的可讀性強,容易維護,並且jsp在最后會編譯成servlet

servlet容易調試

288、Jsp的九大內置對象,三大指令,七大動作的具體功能

九大內置對象:

pageContext :只對當前jsp頁面有效,里面封裝了基本的request和session的對象

Request :對當前請求進行封裝

Session :瀏覽器會話對象,瀏覽器范圍內有效

Application :應用程序對象,對整個web工程都有效

Out :頁面打印對象,在jsp頁面打印字符串

Response :返回服務器端信息給用戶

Config :單個servlet的配置對象,相當於servletConfig對象

Page :當前頁面對象,也就是this

Exception :錯誤頁面的exception對象,如果指定的是錯誤頁面,這個就是異常對象

三大指令:

Page :指令是針對當前頁面的指令

Include :用於指定如何包含另一個頁面

Taglib :用於定義和指定自定義標簽

七大動作:

Forward,執行頁面跳轉,將請求的處理轉發到另一個頁面

Param :用於傳遞參數

Include :用於動態引入一個jsp頁面

Plugin :用於下載javaBean或applet到客戶端執行

useBean :使用javaBean

setProperty :修改javaBean實例的屬性值

getProperty :獲取javaBean實例的屬性值

獲取頁面的元素和值有幾種方式,分別說一下

request.getParameter() 返回客戶端的請求參數與值

request.getParameterNames() 返回所有可用屬性名的枚舉

request.getParameterValues() 返回包含參數的所有值的數組

289、et和javaScript的區別,他們分別是什么作用

一個是服務端,一個是客戶端

Servlet是獨立於平台和協議的服務器端的java應用程序,可以動態生成web頁面,並采用響應--請求的模式提供web服務

javaScript是一種解釋性語言,用於向html頁面提供交互行為,通常被直接嵌入在html頁面中

servlet是java語言編寫的web應用

js是基於html上的一種解釋語言


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM