2019java 开发工程师 最新面试官 问的问题
1.Java中的io流面試題
答案:我給你打個比方你就明白了;比如你家的水龍頭的管道就是一個流:流又分為輸入輸出流,輸入流就是你家水龍頭抽水庫水的那頭,輸出流就是你家水龍頭流到你家大水缸的那頭。現在有個A.txt文件,你要讀取里面的信息,就相當于水龍頭抽水庫水,然后讀取完后寫入到另一個文件里面,就是相當于水龍頭抽到水后流到大水缸。很簡單吧,就是一進一出的事,沒這么復雜
1.1: 以流向來劃分(針對內存):A.輸入流:文件—>內存??? 讀文件B.輸出流:內存—>文件??? 寫文件2)從內容劃分A.字節流:以8位的形式來處理,不能輸出漢字B.字符流:在字節流上進行包裝得到的,可以處理字節流,也可以處理漢字??? 注:在最底層,所有的I/O操作都是字節流的形式,字符流是為了處理漢字方便,字節流的處理速度快?
答: 字節流是按字節讀取或寫入設備,但字符流是以字符為單位讀取或寫入設備。
如果是二進制文件,需要用字節流讀取。一般來說,字符流只處理文本文件。在設備中,大多數情況是以字節形式存儲數據的,因此字符流通過需要傳入字節流當參數。
原文是這樣的意思,用BufferedReader封裝一個InputStream,再用DataInputStream封裝這個InputStream,這樣做之后,先用BufferedReader從流中讀取一行,然后分別用這個InputStream讀取一個字符和DataInputStream讀取一行,再用BufferedReader讀取一行,結果BufferedReader均能讀到數據,而InputStream和DataInputStream均讀不到數據.數據流中只有40多個字符。這說明了,BufferedReader第一次讀取時,就把這40多個字符都讀取出來,緩沖起來了,后面每次讀的時候,都只是從緩沖里拿出來。40多個字符就一次被BufferedReader讀進去緩存起來了,所以InputStream和DataInputStream就都讀不到字符了。?
原文并猜想,如果流中的數據夠多到BufferedReader緩存不下來的時候,InputStream和DataInputStream就能讀到數據了。?
注解:緩沖流分為字節和字符緩沖流
字節緩沖流為:
BufferedInputStream—字節輸入緩沖流
BufferedOutputStream—字節輸出緩沖流
字符緩沖流為:
BufferedReader—字符輸入緩沖流
BufferedWriter—字符輸出緩沖流
下面主要介紹這四種緩沖流的使用。
?
2.多線程面試問題
?
?
答:程序的一次執行就可以看作是一個進程。進程中又包含了許多的線程,進程之間的內存不可以共享,線程之間共享進程的內存。
一、繼承Thread類創建線程類
(1)定義Thread類的子類,并重寫該類的run方法,該run方法的方法體就代表了線程要完成的任務。因此把run()方法稱為執行體。
(2)創建Thread子類的實例,即創建了線程對象。
(3)調用線程對象的start()方法來啟動該線程。
二、通過Runnable接口創建線程類
(1)定義runnable接口的實現類,并重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執行體。
(2)創建 Runnable實現類的實例,并依此實例作為Thread的target來創建Thread對象,該Thread對象才是真正的線程對象。
(3)調用線程對象的start()方法來啟動該線程。
三、通過Callable和Future創建線程
(1)創建Callable接口的實現類,并實現call()方法,該call()方法將作為線程執行體,并且有返回值。
(2)創建Callable實現類的實例,使用FutureTask類來包裝Callable對象,該FutureTask對象封裝了該Callable對象的call()方法的返回值。
(3)使用FutureTask對象作為Thread對象的target創建并啟動新線程。
(4)調用FutureTask對象的get()方法來獲得子線程執行結束后的返回值
二、創建線程的三種方式的對比
采用實現Runnable、Callable接口的方式創見多線程時,優勢是:
線程類只是實現了Runnable接口或Callable接口,還可以繼承其他類。
在這種方式下,多個線程可以共享同一個target對象,所以非常適合多個相同線程來處理同一份資源的情況,從而可以將CPU、代碼和數據分開,形成清晰的模型,較好地體現了面向對象的思想。
劣勢是:
編程稍微復雜,如果要訪問當前線程,則必須使用Thread.currentThread()方法。
使用繼承Thread類的方式創建多線程時優勢是:
編寫簡單,如果需要訪問當前線程,則無需使用Thread.currentThread()方法,直接使用this即可獲得當前線程。
劣勢是:
線程類已經繼承了Thread類,所以不能再繼承其他父類。
?
答:樂觀鎖適用于多讀的應用類型,這樣可以提高吞吐量,像數據庫如果提供類似于write_condition機智的其實都是提供的樂觀鎖。 相反,如果經常發生沖突,上層應用會不斷進行 retry,這樣反而降低了性能,所以這種情況下用悲觀鎖比較合適
1.start() 啟動線程并執行相應的run()方法 ---run() 子線程要執行的代碼放入run()方法。
2.getName() 獲取此線程的名字?setName() 設置
此線程的名字。
3.join() 執行調用join()方法線程),阻斷其他線程。
4.sleep(毫秒)休眠。
?
線程安全的理解?
答 :線程安全就是多線程訪問時,采用了加鎖機制,當一個線程訪問該類的某個數據時,進行保護,其他線程不能進行訪問直到該線程讀取完,其他線程才可使用
答:對于sleep()方法,我們首先要知道該方法是屬于Thread類中的。而wait()方法,則是屬于Object類中的。
sleep()方法導致了程序暫停執行指定的時間,讓出cpu該其他線程,但是他的監控狀態依然保持者,當指定的時間到了又會自動恢復運行狀態。
在調用sleep()方法的過程中,線程不會釋放對象鎖。
而當調用wait()方法的時候,線程會放棄對象鎖,進入等待此對象的等待鎖定池,只有針對此對象調用notify()方法后本線程才進入對象鎖定池準備
?
3.集合面試問題(HashMap居多,問的也有上機也有)
??1、繼承的父類不同
? ? ??Hashtable繼承自Dictionary類,而HashMap繼承自AbstractMap類。但二者都實現了Map接口。
?2、線程安全性不同
? ? ??javadoc中關于hashmap的一段描述如下:此實現不是同步的。如果多個線程同時訪問一個哈希映射,而其中至少一個線程從結構上修改了該映射,則它必須保持外部同步。
?
? ? ??Hashtable 中的方法是Synchronize的,而HashMap中的方法在缺省情況下是非Synchronize的。在多線程并發的環境下,可以直接使用Hashtable,不需要自己為它的方法實現同步,但使用HashMap時就必須要自己增加同步處理。(結構上的修改是指添加或刪除一個或多個映射關系的任何操作;僅改變與實例已經包含的鍵關聯的值不是結構上的修改。)這一般通過對自然封裝該映射的對象進行同步操作來完成。如果不存在這樣的對象,則應該使用?Collections.synchronizedMap?方法來“包裝”該映射。最好在創建時完成這一操作,以防止對映射進行意外的非同步訪問,如下所示:
? ? ??Map m = Collections.synchronizedMap(new HashMap(...));
? ? ??Hashtable 線程安全很好理解,因為它每個方法中都加入了Synchronize。這里我們分析一下HashMap為什么是線程不安全的:
?
? ? ??HashMap底層是一個Entry數組,當發生hash沖突的時候,hashmap是采用鏈表的方式來解決的,在對應的數組位置存放鏈表的頭結點。對鏈表而言,新加入的節點會從頭結點加入。
我們來分析一下多線程訪問:
?
? ? ??(1)在hashmap做put操作的時候會調用下面方法:
?
[java]?view plain?copy
?
?
? ? ??在hashmap做put操作的時候會調用到以上的方法。現在假如A線程和B線程同時對同一個數組位置調用addEntry,兩個線程會同時得到現在的頭結點,然后A寫入新的頭結點之后,B也寫入新的頭結點,那B的寫入操作就會覆蓋A的寫入操作造成A的寫入操作丟失
(? ? ??2)刪除鍵值對的代碼
?
[java]?view plain?copy
?
?
? ? ??當多個線程同時操作同一個數組位置的時候,也都會先取得現在狀態下該位置存儲的頭結點,然后各自去進行計算操作,之后再把結果寫會到該數組位置去,其實寫回的時候可能其他的線程已經就把這個位置給修改過了,就會覆蓋其他線程的修改
? ? ??(3)addEntry中當加入新的鍵值對后鍵值對總數量超過門限值的時候會調用一個resize操作,代碼如下:
[java]?view plain?copy
?
? ? ??這個操作會新生成一個新的容量的數組,然后對原數組的所有鍵值對重新進行計算和寫入新的數組,之后指向新生成的數組。
?
? ? ??當多個線程同時檢測到總數量超過門限值的時候就會同時調用resize操作,各自生成新的數組并rehash后賦給該map底層的數組table,結果最終只有最后一個線程生成的新數組被賦給table變量,其他線程的均會丟失。而且當某些線程已經完成賦值而其他線程剛開始的時候,就會用已經被賦值的table作為原始數組,這樣也會有問題。
? ? ??3、是否提供contains方法
?
? ? ??HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey,因為contains方法容易讓人引起誤解。
? ? ??Hashtable則保留了contains,containsValue和containsKey三個方法,其中contains和containsValue功能相同。
我們看一下Hashtable的ContainsKey方法和ContainsValue的源碼:
[java]?view plain?copy
?
?
[java]?view plain?copy
?
?
[java]?view plain?copy
?
? ? ??下面我們看一下HashMap的ContainsKey方法和ContainsValue的源碼:
[java]?view plain?copy
?
?
[java]?view plain?copy
?
?
[java]?view plain?copy
?
通過上面源碼的比較,我們可以得到第四個不同的地方
?
? ? ??4、key和value是否允許null值
? ? ??其中key和value都是對象,并且不能包含重復key,但可以包含重復的value。
? ? ??通過上面的ContainsKey方法和ContainsValue的源碼我們可以很明顯的看出:
? ? ??Hashtable中,key和value都不允許出現null值。但是如果在Hashtable中有類似put(null,null)的操作,編譯同樣可以通過,因為key和value都是Object類型,但運行時會拋出NullPointerException異常,這是JDK的規范規定的。
HashMap中,null可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值為null。當get()方法返回null值時,可能是 HashMap中沒有該鍵,也可能使該鍵所對應的值為null。因此,在HashMap中不能由get()方法來判斷HashMap中是否存在某個鍵, 而應該用containsKey()方法來判斷。
?
? ? ??5、兩個遍歷方式的內部實現上不同
? ? ??Hashtable、HashMap都使用了 Iterator。而由于歷史原因,Hashtable還使用了Enumeration的方式 。
6、hash值不同
? ? ??哈希值的使用不同,HashTable直接使用對象的hashCode。而HashMap重新計算hash值。
? ? ??hashCode是jdk根據對象的地址或者字符串或者數字算出來的int類型的數值。
? ? ??Hashtable計算hash值,直接用key的hashCode(),而HashMap重新計算了key的hash值,Hashtable在求hash值對應的位置索引時,用取模運算,而HashMap在求位置索引時,則用與運算,且這里一般先用hash&0x7FFFFFFF后,再對length取模,&0x7FFFFFFF的目的是為了將負的hash值轉化為正值,因為hash值有可能為負數,而&0x7FFFFFFF后,只有符號外改變,而后面的位都不變。
7、內部實現使用的數組初始化和擴容方式不同
HashTable在不指定容量的情況下的默認容量為11,而HashMap為16,Hashtable不要求底層數組的容量一定要為2的整數次冪,而HashMap則要求一定為2的整數次冪。
? ? ??Hashtable擴容時,將容量變為原來的2倍加1,而HashMap擴容時,將容量變為原來的2倍。
? ? ??Hashtable和HashMap它們兩個內部實現方式的數組的初始大小和擴容的方式。HashTable中hash數組默認大小是11,增加的方式是 old*2+1。
注解詳細:https://blog.csdn.net/wangxing233/article/details/79452946
答:底層數組+鏈表實現。
答:初始size為16,擴容:newsize = oldsize*2,size一定為2的n次冪
擴容針對整個Map,每次擴容時,原來數組中的元素依次重新計算存放位置,并重新插入。
插入元素后才判斷該不該擴容,有可能無效擴容(插入后如果擴容,如果沒有再次插入,就會產生無效擴容)
當Map中元素總數超過Entry數組的75%,觸發擴容操作,為了減少鏈表長度,元素分配更均勻。
?
答:對于HashMap而言,key是唯一的,不可以重復的。?所以,以相同的key 把不同的value插入到 Map中會導致舊元素被覆蓋,只留下最后插入的元素。?? 不過,同一個對象可以作為值插入到map中,只要對應的key不一樣。
ArrayList和Vector使用了數組的實現,可以認為ArrayList或者Vector封裝了對內部數組的操作,比如向數組中添加,刪除,插入新的元素或者數據的擴展和重定向。
LinkedList使用了循環雙向鏈表數據結構。與基于數組ArrayList相比,這是兩種截然不同的實現技術,這也決定了它們將適用于完全不同的工作場景。
詳細:https://www.cnblogs.com/wwwcnblogscom/p/8036411.html
7.arrayList和vector的區別
1. Vector & ArrayList?
1)? Vector的方法都是同步的(Synchronized),是線程安全的(thread-safe),而ArrayList的方法不是,由于線程的同步必然要影響性能,因此,ArrayList的性能比Vector好。?
2) 當Vector或ArrayList中的元素超過它的初始大小時,Vector會將它的容量翻倍,而ArrayList只增加50%的大小,這樣,ArrayList就有利于節約內存空間。
2. Hashtable & HashMap?
Hashtable和HashMap它們的性能方面的比較類似 Vector和ArrayList,比如Hashtable的方法是同步的,而HashMap的不是。
3. ArrayList & LinkedList
ArrayList的內部實現是基于內部數組Object[],所以從概念上講,它更象數組,但LinkedList的內部實現是基于一組連接的記錄,所以,它更象一個鏈表結構,所以,它們在性能上有很大的差別:?
?????? 從上面的分析可知,在ArrayList的前面或中間插入數據時,你必須將其后的所有數據相應的后移,這樣必然要花費較多時間,所以,當你的操作是在一列 數據的后面添加數據而不是在前面或中間,并且需要隨機地訪問其中的元素時,使用ArrayList會提供比較好的性能; 而訪問鏈表中的某個元素時,就必須從鏈表的一端開始沿著連接方向一個一個元素地去查找,直到找到所需的元素為止,所以,當你的操作是在一列數據的前面或中 間添加或刪除數據,并且按照順序訪問其中的元素時,就應該使用LinkedList了。?
?
如果在編程中,1、2兩種情形交替出現,這時,你可以考慮使用List這樣的通用接口,而不用關心具體的實現,在具體的情形下,它的性能由具體的實現來保證。
4. 配置集合類的初始大小?
??? 在Java集合框架中的大部分類的大小是可以隨著元素個數的增加而相應的增加的,我們似乎不用關心它的初始大小,但如果我們考慮類的性能問題時,就一定要考慮盡可能地設置好集合對象的初始大小,這將大大提高代碼的性能。?
??? 比如,Hashtable缺省的初始大小為101,載入因子為0.75,即如果其中的元素個數超過75個,它就必須增加大小并重新組織元素,所以,如果你 知道在創建一個新的Hashtable對象時就知道元素的確切數目如為110,那么,就應將其初始大小設為110/0.75=148,這樣,就可以避免重 新組織內存并增加大小。
4.其他面試問題(可能會有上機題需要手寫的)
//不安全的單例模式
//安全的單例模式
public?class?Singleton {
????private?static?volatile?Singleton singleton = null;
??
????private?Singleton(){}
??
????public?static?Singleton getSingleton(){
????????synchronized?(Singleton.class){
????????????if(singleton == null){
????????????????singleton = new?Singleton();
????????????}
????????}
????????return?singleton;
????}???
}
詳細:https://www.cnblogs.com/shan1393/p/8992288.html
?
5.手寫冒泡排序 選擇排序? Arrays工具類排序:
| package com.bdqn.test; ? import java.util.Arrays; import java.util.Comparator; ? public class SelectSortTest { ?? public static void main(String[] args) { ????? //定義一個選擇排序的方法 ????? int[] arr= {2,-1,3,4,-9,2,3,5,8}; ????? Integer[] arrInteger= {2,-1,3,4,-9,2,3,5,8}; ????? System.out.println("選擇排序:"); ????? selectSort(arr); ????? System.out.println("冒泡排序:"); ????? puppleSort(arr); ????? System.out.println("使用Arrays工具類排排序:"); ????? arraysSort(arrInteger); ?? } ?? private static void selectSort(int[] arr) { ????????? for(int i=0;i<arr.length-1;i++) { ???????????? for(int j=i+1;j<arr.length;j++) { ??????????????? if(arr[i]>arr[j]) { ?????????????????? int temp=arr[i]; ?????????????????? arr[i]=arr[j]; ?????????????????? arr[j]=temp; ??????????????? } ???????????? } ????????? } ????????? //輸出排序后的集合 ????????? System.out.println(Arrays.toString(arr)); ?? } ?? private static void puppleSort(int[] arr) { ????? for(int i=0;i<arr.length-1;i++) { ????????? for(int j=0;j<arr.length-1-i;j++) { ???????????? if(arr[j]>arr[j+1]) { ??????????????? int temp=arr[j]; ??????????????? arr[j]=arr[j+1]; ??????????????? arr[j+1]=temp;? ???????????? } ????????? } ????? } ????? //輸出冒泡排序后的集合 ????? System.out.println(Arrays.toString(arr)); ?? } ?? //使用Arrays類實現排序 ?? public static void arraysSort(Integer[] arr) { ????? Arrays.sort(arr,new Comparator<Integer>() { ????????? @Override ????????? public int compare(Integer o1, Integer o2) { ???????????? return o1-o2; ????????? } ????? }); ????? System.out.println(Arrays.toString(arr)); ?? } }? |
?
答:1.抽象類中可以有一個或多個抽象方法,而接口中的方法必須都是抽象方法
2.接口中定義方法和成員變量和抽象類中定義方法和成員變量接口中成員變量默認被修飾為public static final常量
3. 接口最大的一個特點就是可以實現多繼承,而抽象類智能繼承一個(應該說java中只要是類就只能單繼承)
4. 4.抽象類和方法必須使用abstract關鍵聲明為抽象,而接口中的方法默認被修飾為public abstract類型(默認為公開抽象的方法)
詳細:https://baijiahao.baidu.com/s?id=1568702144789321&wfr=spider&for=pc
答:1.封裝、繼承、多態
理解:
封裝:把一類對象,相似的屬性匯總到一起,組成一類,這個類把該隱藏的隱藏,該暴露的暴露。
繼承:涉及到父子類的關系,自然可以得到父類的特征,相對是父類的擴展,達到代碼重用的效果。
例如:Java中用extends關鍵字,實現繼承類被稱為子類,被繼承類被稱為父類。例如:水果和蘋果的關系,蘋果繼承了水果,蘋果是水果的子類,水果是蘋果的父類。
詳細:https://blog.csdn.net/kisscatforever/article/details/79721937
String最慢的原因:
String為字符串常量,而StringBuilder和StringBuffer均為字符串變量,即String對象一旦創建之后該對象是不可更改的,但后兩者的對象是變量,是可以更改的。
2. 再來說線程安全
在線程安全上,StringBuilder是線程不安全的,而StringBuffer是線程安全的
如果一個StringBuffer對象在字符串緩沖區被多個線程使用時,StringBuffer中很多方法可以帶有synchronized關鍵字,所以可以保證線程是安全的,但StringBuilder的方法則沒有該關鍵字,所以不能保證線程安全,有可能會出現一些錯誤的操作。所以如果要進行的操作是多線程的,那么就要使用StringBuffer,但是在單線程的情況下,還是建議使用速度比較快的StringBuilder。
?總結一下
String:適用于少量的字符串操作的情況
StringBuilder:適用于單線程下在字符緩沖區進行大量操作的情況
StringBuffer:適用多線程下在字符緩沖區進行大量操作的情況
?? 詳細:https://www.cnblogs.com/su-feng/p/6659064.html
例:insert into Strdents (姓名,性別,出生日期) values ('開心朋朋','男','1980/6/15')
?delete from a where name='開心朋朋'(刪除表a中列值為開心朋朋的行)
例:update tongxunlu set 年齡=18 where 姓名='藍色小名'
詳細:https://www.cnblogs.com/daxueshan/p/6687521.html
1.去重 DISTINCT?
不同項目之間的通信方式分為,http、socket、webservice;其中socket通信的效率最高,youtube就采用的是原始的socket通信,他們信奉的原則是簡單有效。
一、http通信:
????Http通信主要有兩種方式POST方式和GET方式。前者通過Http消息實體發送數據給服務器,安全性高,數據傳輸大小沒有限制,后者通過URL的查詢字符串傳遞給服務器參數,以明文顯示在瀏覽器地址欄,保密性差,最多傳輸2048個字符。但是GET請求并不是一無是處——GET請求大多用于查詢(讀取資源),效率高。POST請求用于注冊、登錄等安全性較高且向數據庫中寫入數據的操作。除了POST和GET,http通信還有其他方式!請參見http請求的方法
二、webservice
應用場景:跨防火墻的通信、應用程序集成、B2B的集成、軟件和數據重用
三、socket
socket是“open—write/read—close”模式的一種實現
java socket通信已經被封裝好了主要使用兩個類ServerSocket 和Socket
詳細:https://blog.csdn.net/sunshine_silence/article/details/78771198
?
框架面試問題(簡歷上有寫的就會問到,沒寫的他們公司要求用到的也可能會問)
5.Spring面試問題
Spring的三大核心思想:IOC(控制反轉),DI(依賴注入),AOP(面向切面編程)。
?
(1)IOC(控制反轉)
實現將組件間的關系從程序內部提到外部容器(spring的xml)來管理首先外部容器(spring.xml)中會動態的注冊業務所需的對象(接口/類)
(2)DI(依賴注入)
組件之間的依賴關系由容器在應用系統運行期來決定, 也就是由容器動態地將某種依賴關系的目標對象實例注入到應用系統中的各個關聯的組件之中
(3)?AOP(面向切面編程)?
??利用一種稱為"橫切"的技術,剖解開封裝的對象內部,并將那些影響了多個類的公共行為封裝到一個可重用模塊,并將其命名為"Aspect",即切面。所謂"切面",簡單說就是那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便于減少系統的重復代碼,降低模塊之間的耦合度,并有利于未來的可操作性和可維護性。
詳細https://blog.csdn.net/u010688011/article/details/79431778
就是讓對象與對象(模塊與模塊)之間的關系沒有通過代碼來關聯,都是通過配置類說明管理的(Spring根據這些配置 內部通過反射去動態的組裝對象)?
?
詳細:https://www.cnblogs.com/zhoudi/p/5820513.html?
??1: 想辦法讓action具有 自動注入的功能;
??2: 讓action納入spring管理;
? ?????spring與hibernate整合兩種方式:
1. 零障礙整合;
2. Spring管理hibernate配置;
?1.零障礙整合:
?在spring的配置文件applicationContext.xml中配置bean: 并引入hibernate的核心配置文件;
2.spring管理hibernate配置:將hibernate的核心配置文件 hibernate.cfg.xml中的內容遷移到 applicationContext.xml中;
SSM:
1、dao層
1.1、必須數據:
pojo(java實體)、mapper接口(dao接口)、sql映射文件(翻譯為jdbc中的statement)
1.2、配置文件:
mybatis核心配置文件:SqlMapConfig.xml
自定義別名
spring整合mybatis配置文件:applicationContext-dao.xml
數據源
會化工廠
mapper掃描(加載dao)
其他配置:
數據庫信息:db.properties
日志信息:log4j.properties
2、service層
2.1、配置文件:
注解掃描:@service(加載service)applicationContext-service.xml
事務配置: ApplicationContext-trans.xml
3、controller層
3.1、配置文件: springMVC.xml
注解掃描:@controller(加載controller)
注解驅動:自動加載最新的處理器映射器、處理器適配器
視圖解析器:
自定義類型轉化器:(掛載于注解驅動)
文件上傳解析器:
json格式數據解析器:(若沒有配置注解驅動,則需要顯示的在處理器適配器掛載)
全局異常處理器:
自定義攔截器:
靜態資源放行:
4、web.xml web.xml
4.1、spring監聽器
4.2、springMVC前端控制器
4.3、post中文亂碼請求
原文:https://blog.csdn.net/u010758410/article/details/80145521
4.1先以靜態代理實現,靜態代理關鍵是在代理對象和目標對象實現共同的接口,并且代理對象持有目標對象的引用。
4.2:動態代理實現主要是實現InvocationHandler,并且將目標對象注入到代理對象中,利用反射機制來執行目標對象的方法。
6.SpingMVC面試問題
?一、框架機制
spring mvc 和 struts2的加載機制不同:spring mvc的入口是servlet,而struts2是filter(servlet和filter區別見本文最后)
1、Struts2采用Filter(StrutsPrepareAndExecuteFilter)實現,SpringMVC(DispatcherServlet)則采用Servlet實現。
2、Filter在容器啟動之后即初始化;服務停止以后墜毀,晚于Servlet。Servlet在是在調用時初始化,先于Filter調用,服務停止后銷毀。
二、攔截機制
1、Struts2
a、Struts2框架是類級別的攔截,每次請求就會創建一個Action,和Spring整合時Struts2的ActionBean注入作用域是原型模式prototype(否則會出現線程并發問題),然后通過setter,getter吧request數據注入到屬性。
b、Struts2中,一個Action對應一個request,response上下文,在接收參數時,可以通過屬性接收,這說明屬性參數是讓多個方法共享的。
c、Struts2中Action的一個方法可以對應一個url,而其類屬性卻被所有方法共享,這也就無法用注解或其他方式標識其所屬方法了
?
2、SpringMVC
a、SpringMVC是方法級別的攔截,一個方法對應一個Request上下文,所以方法直接基本上是獨立的,獨享request,response數據。而每個方法同時又何一個url對應,參數的傳遞是直接注入到方法中的,是方法所獨有的。處理結果通過ModeMap返回給框架。
b、在Spring整合時,SpringMVC的Controller Bean默認單例模式Singleton,所以默認對所有的請求,只會創建一個Controller,有應為沒有共享的屬性,所以是線程安全的,如果要改變默認的作用域,需要添加@Scope注解修改。
三、性能方面
SpringMVC實現了零配置,由于SpringMVC基于方法的攔截,有加載一次單例模式bean注入。而Struts2是類級別的攔截,每次請求對應實例一個新的Action,需要加載所有的屬性值注入,所以,SpringMVC開發效率和性能高于Struts2。
四、攔截機制
Struts2有自己的攔截Interceptor機制,SpringMVC這是用的是獨立的Aop方式,這樣導致Struts2的配置文件量還是比SpringMVC大。
五、配置方面
spring MVC和Spring是無縫的。從這個項目的管理和安全上也比Struts2高(當然Struts2也可以通過不同的目錄結構和相關配置做到SpringMVC一樣的效果,但是需要xml配置的地方不少)。
SpringMVC可以認為已經100%零配置。
六、設計思想
Struts2更加符合OOP的編程思想, SpringMVC就比較謹慎,在servlet上擴展。
七、集成方面
SpringMVC集成了Ajax,使用非常方便,只需一個注解@ResponseBody就可以實現,然后直接返回響應文本即可,而Struts2攔截器集成了Ajax,在Action中處理時一般必須安裝插件或者自己寫代碼集成進去,使用起來也相對不方便。
1.適配器? 試圖解析器? 映射器
MVC是Model—View—Controler的簡稱。即模型—視圖—控制器。MVC是一種設計模式,它強制性的把應用程序的輸入、處理和輸出分開。
MVC中的模型、視圖、控制器它們分別擔負著不同的任務。
視圖: 視圖是用戶看到并與之交互的界面。視圖向用戶顯示相關的數據,并接受用戶的輸入。視圖不進行任何業務邏輯處理。
模型: 模型表示業務數據和業務處理。相當于JavaBean。一個模型能為多個視圖提供數據。這提高了應用程序的重用性
控制器: 當用戶單擊Web頁面中的提交按鈕時,控制器接受請求并調用相應的模型去處理請求。
然后根據處理的結果調用相應的視圖來顯示處理的結果。
MVC的處理過程:首先控制器接受用戶的請求,調用相應的模型來進行業務處理,并返回數據給控制器。控制器調用相應的視圖來顯示處理的結果。并通過視圖呈現給用戶。
詳細:https://www.cnblogs.com/Alexander11/p/5621560.html
7.Struts2面試題
1普通的POJO類,該類通常包含一個無參數的execute()方法,返回值為字符串類型。
2實現Action接口
3繼承ActionSupport類
? 首先運行項目 所有請求被攔截器 攔截 然后交給Action 把數據返回給jsp頁面
8.MyBatis和Hibernate
答:1:hibernate是全自動,而mybatis是半自動。
2.Hibernate數據庫移植性遠大于mybatis
3.hibernate擁有完整的日志系統,mybatis則欠缺些
4.mybatis相比hibernate需要關系很多細節
5.sql直接優化上,mybatis要比hibernate方便很多
? ??總結:
Mybatis:小巧、方便、高效、簡單、直接、半自動
Hibernate:強大、方便、高效、復雜、繞彎子、全自動
詳細:https://blog.csdn.net/w_q_q_/article/details/79032062
9.Dubbo面試問題
Dobbo是一個分布式框架,致力提供高性能和透明化的 PRC遠程服務調用方案。簡單說:,dobbo就是個服務框架,如果沒有分布式需求,其實不需要要用的,只要在分布式的時候,才有dubbo這樣的分布式服務框架的需求,并且本質是個服務調用的東東,說白了就是個遠程調用分布式框架。
其核心部分包含:
1. 遠程通訊: 提供對多種基于長連接的NIO框架抽象封裝,包括多種線程模型,序列化,以及“請求-響應”模式的信息交換方式。
2. 集群容錯: 提供基于接口方法的透明遠程過程調用,包括多協議支持,以及軟負載均衡,失敗容錯,地址路由,動態配置等集群支持。
3. 自動發現: 基于注冊中心目錄服務,使服務消費方能動態的查找服務提供方,使地址透明,使服務提供方可以平滑增加或減少機器。
詳細:https://blog.csdn.net/houshaolin/article/details/76408399
默認調用netty框架,還有mian以及基于servlet等方式。
詳細:https://www.cnblogs.com/yang-lq/p/9168216.html
默認是阻塞的,可以異步調用,沒有返回值的可以這么做。
推薦使用zookeeper注冊中心,還有Multicast、Redis和Simple等。
2. zookeeper中有兩種類型的節點:
1.持久節點(PERSISENT):一旦創建,除非主動調用刪除操作,否則一直存儲在zk上;
2.臨時節點(EPHEMERAL):與客戶端會話綁定,一旦客戶端會話失效,這個客戶端所創建的所有臨時節點都會被移除;
??詳細:https://www.jianshu.com/p/f42c69e4bd3e?fromApp=1
可以直連,修改配置即可,也可以通過telnet直接某個服務。
10.SpringBoot面試問題
SpringBoot+maven? 簡化搭建以及開發過程 是一個非常好的微服務開發框架 可以快速搭建一個系統
配置少 開發和部署效率快?
詳細:https://blog.csdn.net/m0_38075425/article/details/81164501
?
總結
以上是生活随笔為你收集整理的2019java 开发工程师 最新面试官 问的问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 科技“度”善
- 下一篇: 和菜头:在碎片化的轰炸中喘息