Java面試題
分爲基礎、jvm、javaEE、框架、數據庫、工具
一、java基礎
1、java的8個基本數據類型:
整形{int(4字節)、short(2)、byte(1)、long(8)},浮點型{float(4)、double(8)},字符型{char(2)},布爾型{boolean(4)}。
2、&與&&區別:
&&之所以稱爲短路運算是因爲,如果&&左邊的表達式的值是false,右邊的表達式會被直接短路掉,不會進行運算
3、最有效率的2乘8:
(2<<3)
4、String不能被繼承,final用法:
(1)修飾類:表示該類不能被繼承;
(2)修飾方法:表示方法不能被重寫;
(3)修飾變量:表示變量只能一次賦值以後值不能被修改(常量)。
多線程操作字符串緩衝區下操作大量數據 StringBuffer:可變字符串、效率低、線程安全;
單線程操作字符串緩衝區下操作大量數據 StringBuilder:可變字符序列、效率高、線程不安全。
5、try{}裏有一個return語句,那麼緊跟在這個try後的finally{}裏的代碼會不會被執行,什麼時候被執行,在return前還是後?
答:會執行,在方法返回調用者前執行。在finally中改變返回值的做法是不好的,因爲如果存在finally代碼塊,try中的return語句不會立馬返回調用者,而是記錄下返回值待finally代碼塊執行完畢之後再向調用者返回其值,然後如果在finally中修改了返回值,就會返回修改後的值
6、事務的ACID是指:
1、原子性(atomicity)
事務是原子性操作,由一系列動作組成,事務的原子性確保動作要麼全部完成,要麼完全不起作用
2、一致性(consistency)
一旦所有事務動作完成,事務就要被提交。數據和資源處於一種滿足業務規則的一致性狀態中
3、隔離性(isolation)
可能多個事務會同時處理相同的數據,因此每個事務都應該與其他事務隔離開來,防止數據損壞
4、持久性(durability)
事務一旦完成,無論系統發生什麼錯誤,結果都不會受到影響。通常情況下,事務的結果被寫到持久化存儲器中
7、用Java寫一個冒泡排序
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;
}
}
}
8、用Java寫一個二分查找。
非遞歸實現:
public static int biSearch(int []array,int a){
int lo=0;
int hi=array.length-1;
int mid;
while(lo<=hi){
mid=(lo+hi)/2;
if(array[mid]==a){
return mid+1;
}else if(array[mid]<a){
lo=mid+1;
}else{
hi=mid-1;
}
}
return -1;
}
遞歸實現:
public static int sort(int []array,int a,int lo,int hi){
if(lo<=hi){
int mid=(lo+hi)/2;
if(a==array[mid]){
return mid+1;
}
else if(a>array[mid]){
return sort(array,a,mid+1,hi);
}else{
return sort(array,a,lo,mid-1);
}
}
return -1;
}
9、什麼是多態
所謂的“多態”,簡單的理解就是對象在不同情況下的不同表現,具體體現在定義和功能兩個方面,簡單的總結一下,多態可以用“三個定義和兩個方法”來總結。三個定義分別是父類定義子類構建、接口定義實現類構建和抽象類定義實體類構建,而兩個方法分別是方法重載和方法重寫。
10、什麼是繼承
繼承是java面向對象編程技術的一塊基石,因爲它允許創建分等級層次的類。
繼承就是子類繼承父類的特徵和行爲,使得子類對象(實例)具有父類的實例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行爲。
11、重寫(Override)和重載(Overload)
**重寫 ** 是子類對父類的允許訪問的方法的實現過程進行重新編寫, 返回值和形參都不能改變。
重載 (overloading) 是在一個類裏面,方法名字相同,而參數不同。返回類型可以相同也可以不同。每個重載的方法(或者構造函數)都必須有一個獨一無二的參數類型列表。
12、接口的意義用三個詞概括
規範,擴展,回調
二、jvm
1、類的實例化順序
首先是父類的靜態變量和靜態代碼塊(看兩者的書寫順序);
第二執行子類的靜態變量和靜態代碼塊(看兩者的書寫順序);
第三執行父類的成員變量賦值
第四執行父類的構造代碼塊
第五執行父類的構造方法
第六執行子類的構造代碼塊
第七執行子類的構造方法
總結,也就是說雖然客戶端代碼是new 的構造方法,但是構造方法確實是在整個實例創建中的最後一個調用。切記切記!!!
先是父類,再是子類;
先是類靜態變量和靜態代碼塊,再是對象的成員變量和構造代碼塊–>構造方法。
記住,構造方法最後調用!!!!成員變量優先構造代碼塊優先構造方法!!
2、內存泄漏和內存溢出的區別
內存泄漏:分配出去的內存無法回收(可達卻無用的對象無法被GC回收)
內存溢出:程序要求的內存超出了系統能分配的範圍(如棧滿進棧,棧空出棧)
三、javaEE
1、Servlet的運行過程?
Web容器加載Servlet並將其實例化後,Servlet生命週期開始,容器運行其init()方法進行Servlet的初始化;請求到達時調用Servlet的service()方法,service()方法會根據需要調用與請求對應的doGet或doPost等方法;當服務器關閉或項目被卸載時服務器會將Servlet實例銷燬,此時會調用Servlet的destroy()方法。
2、轉發(forward)和重定向(redirect)的區別?
答:forward是容器中控制權的轉向,是服務器請求資源,服務器直接訪問目標地址的URL,把那個URL 的響應內容讀取過來,然後把這些內容再發給瀏覽器,瀏覽器根本不知道服務器發送的內容是從哪兒來的,所以它的地址欄中還是原來的地址。redirect就是服務器端根據邏輯,發送一個狀態碼,告訴瀏覽器重新去請求那個地址,因此從瀏覽器的地址欄中可以看到跳轉後的鏈接地址,很明顯redirect無法訪問到服務器保護起來資源,但是可以從一個網站redirect到其他網站。forward更加高效,所以在滿足需要時儘量使用forward(通過調用RequestDispatcher對象的forward()方法,該對象可以通過ServletRequest對象的getRequestDispatcher()方法獲得),並且這樣也有助於隱藏實際的鏈接;在有些情況下,比如需要訪問一個其它服務器上的資源,則必須使用重定向(通過HttpServletResponse對象調用其sendRedirect()方法實現)。
3、JSP有哪些內置對象?作用分別是什麼?
答:JSP有9個內置對象:
- request:封裝客戶端的請求,其中包含來自GET或POST請求的參數;
- response:封裝服務器對客戶端的響應;
- pageContext:通過該對象可以獲取其他對象;
- session:封裝用戶會話的對象;
- application:封裝服務器運行環境的對象;
- out:輸出服務器響應的輸出流對象;
- config:Web應用的配置對象;
- page:JSP頁面本身(相當於Java程序中的this);
- exception:封裝頁面拋出異常的對象。
4、Tomcat容器是如何創建servlet類實例?用到了什麼原理?
當容器啓動時,會讀取在webapps目錄下所有的web應用中的web.xml文件,然後對xml文件進行解析,
並讀取servlet註冊信息。然後,將每個應用中註冊的servlet類都進行加載,並通過反射的方式實例化。
(有時候也是在第一次請求時實例化)在servlet註冊時加上如果爲正數,則在一開始就實例化,
如果不寫或爲負數,則第一次請求實例化。
四、框架
1、MyBatis
1、#{}和${}的區別是什麼
#{}是預編譯處理,KaTeX parse error: Expected 'EOF', got '#' at position 21: …串替換。
Mybatis在處理#̲{}時,會將sql中的#{}替…{}時,就是把${}替換成變量的值。
使用#{}可以有效的防止SQL注入,提高系統安全性。
2、一對多、多對一、多對多
Mybatis的Mapper編寫一對多,就是在resultMap標籤中配置標籤,用來存儲查詢到的文章列表。
Mybatis的Mapper編寫多對一,就是在resultMap標籤中配置標籤關聯所屬的用戶實體。
2、Shiro
1、Shiro 架構 3 個核心組件:
Subject: 正與系統進行交互的人, 或某一個第三方服務. 所有 Subject 實例都被綁定到(且這是必須的)一個SecurityManager 上。
SecurityManager: Shiro 架構的心臟, 用來協調內部各安全組件, 管理內部組件實例, 並通過它來提供安全管理的各種服務,當 Shiro 與一個 Subject 進行交互時, 實質上是幕後的 SecurityManager 處理所有繁重的 Subject 安全操作。
Realms: 本質上是一個特定安全的 DAO. 當配置 Shiro 時, 必須指定至少一個 Realm 用來進行身份驗證和/或授權,Shiro 提供了多種可用的,Realms 來獲取安全相關的數據. 如關係數據庫(JDBC), INI 及屬性文件等,也可以定義自己 Realm 實現來代表自定義的數據源。
2、Shiro認證過程
①. 應用程序代碼調用 Subject.login 方法,傳遞創建好的包含終端用戶的 Principals(身份)和 Credentials(憑證)的 AuthenticationToken 實例
②. Subject 實例: 通常爲 DelegatingSubject(或子類)委託應用程序的 SecurityManager 通過調用securityManager.login(token) 開始真正的驗證。
③. SubjectManager 接收 token,調用內部的 Authenticator 實例調用 authenticator.authenticate(token).Authenticator 通常是一個 ModularRealmAuthenticator 實例, 支持在身份驗證中協調一個或多個Realm 實例
④. 如果應用程序中配置了一個以上的 Realm, ModularRealmAuthenticator 實例將利用配置好的AuthenticationStrategy 來啓動 Multi-Realm 認證嘗試. 在Realms 被身份驗證調用之前, 期間和以後,AuthenticationStrategy 被調用使其能夠對每個Realm 的結果作出反應.
⑤. 每個配置的 Realm 用來幫助看它是否支持提交的 AuthenticationToken. 如果支持, 那麼支持 Realm 的 getAuthenticationInfo 方法將會伴隨着提交的 token 被調用. getAuthenticationInfo 方法有效地代表一個特定 Realm 的單一的身份驗證嘗試。
3、SpringMVC
1、SpringMVC流程
(1)用戶發送請求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到請求後,調用HandlerMapping處理器映射器,請求獲取Handle;
(3)處理器映射器根據請求url找到具體的處理器,生成處理器對象及處理器攔截器(如果有則生成)一併返回給DispatcherServlet;
(4)DispatcherServlet 調用 HandlerAdapter處理器適配器;
(5)HandlerAdapter 經過適配調用 具體處理器(Handler,也叫後端控制器);
(6)Handler執行完成返回ModelAndView;
(7)HandlerAdapter將Handler執行結果ModelAndView返回給DispatcherServlet;
(8)DispatcherServlet將ModelAndView傳給ViewResolver視圖解析器進行解析;
(9)ViewResolver解析後返回具體View;
(10)DispatcherServlet對View進行渲染視圖(即將模型數據填充至視圖中)
(11)DispatcherServlet響應用戶。
2、SpringMvc怎麼和AJAX相互調用的?
通過Jackson框架就可以把Java裏面的對象直接轉化成Js可以識別的Json對象。具體步驟如下 :
(1)加入Jackson.jar
(2)在配置文件中配置json的映射
(3)在接受Ajax方法裏面可以直接返回Object,List等,但方法前面要加上@ResponseBody註解。
3、如何實現HandlerExceptionResolver接口的自定義異常處理器
通過使用@ControllerAdvice來進行統一異常處理,@ExceptionHandler(value = Exception.class)來指定捕獲的異常 ,這個異常的處理,是全局的,所有類似的異常,都會跑到這個地方處理。
4、Spring
Spring中的bean的作用域有哪些?
1.singleton:唯一bean實例,Spring中的bean默認都是單例的。
2.prototype:每次請求都會創建一個新的bean實例。
3.request:每一次HTTP請求都會產生一個新的bean,該bean僅在當前HTTP request內有效。
4.session:每一次HTTP請求都會產生一個新的bean,該bean僅在當前HTTP session內有效。
5.global-session:全局session作用域,僅僅在基於Portlet的Web應用中才有意義,Spring5中已經沒有了。Portlet是能夠生成語義代碼(例如HTML)片段的小型Java Web插件。它們基於Portlet容器,可以像Servlet一樣處理HTTP請求。但是與Servlet不同,每個Portlet都有不同的會話。
將一個類聲明爲Spring的bean的註解有哪些?
我們一般使用@Autowired註解去自動裝配bean。而想要把一個類標識爲可以用@Autowired註解自動裝配的bean,可以採用以下的註解實現:
1.@Component註解。通用的註解,可標註任意類爲Spring組件。如果一個Bean不知道屬於哪一個層,可以使用@Component註解標註。
2.@Repository註解。對應持久層,即Dao層,主要用於數據庫相關操作。
3.@Service註解。對應服務層,即Service層,主要涉及一些複雜的邏輯,需要用到Dao層(注入)。
4.@Controller註解。對應Spring MVC的控制層,即Controller層,主要用於接受用戶請求並調用Service層的方法返回數據給前端頁面。
五、數據庫
數據庫8個優化:
1、選取最適合的字段屬性
創建表字段時,寬度設得儘可能小,例如郵編字段,設置CHAR(6),對於文本字段,例如漢族少數民族,性別男女可以用ENUM類型,數據庫會當作數據來處理,速度快。字段設置not null,查詢時數據庫不用去比較。
2、使用join來代替子查詢
因爲MySQL不需要在內存中創建臨時表來完成這個邏輯上的需要兩個步驟的查詢工作
3、使用聯合(UNION)來代替手動創建的臨時表
在客戶端的查詢會話結束的時候,臨時表會被自動刪除,從而保證數據庫整齊、高效。使用union來創建查詢的時候,我們只需要用UNION作爲關鍵字把多個select語句連接起來就可以了,要注意的是所有select語句中的字段數目要想同。
4、事務
防止需要執行一組sql時出現一些不可避免的意外而導致的表中的數據不一致或不完整,破壞預想的業務邏輯。
5、鎖定表
儘管事務是維護數據庫完整性的一個非常好的方法,但卻因爲它的獨佔性,有時會影響數據庫的性能,尤其是在很大的應用系統中。由於在事務執行的過程中,數據庫將會被鎖定,因此其它的用戶請求只能暫時等待直到該事務結束。如果一個數據庫系統只有少數幾個用戶來使用,事務造成的影響不會成爲一個太大的問題;但假設有成千上萬的用戶同時訪問一個數據庫系統,例如訪問一個電子商務網站,就會產生比較嚴重的響應延遲。
其實,有些情況下我們可以通過鎖定表的方法來獲得更好的性能。下面的例子就用鎖定表的方法來完成前面一個例子中事務的功能。
LOCK TABLE inventory WRITESELECT Quantity FROM inventory WHERE Item='book';
...
UPDATE inventory SET Quantity=11 WHERE Item='book';
UNLOCKTALES
這裏,我們用一個select語句取出初始數據,通過一些計算,用update語句將新值更新到表中。包含有WRITE關鍵字的LOCKTABLE語句可以保證在UNLOCKTABLES命令被執行之前,不會有其它的訪問來對inventory進行插入、更新或者刪除的操作。
6、使用外鍵
保證每一條新增記錄都指向某個表中已存在的keyid,使得沒有不合法的記錄被更新或插入。
7、使用索引
索引應建立在那些將用於join,where判斷和order by排序的字段上。儘量不要對數據庫中某個含有大量重複的值的字段建立索引。對於一個enum類型的字段來說,出現大量重複值是很有可能的情況。
8、優化查詢語句
函數
數據庫外鍵約束:
1、當取值爲No Action或者Restrict時,則當在父表(即外鍵的來源表)中刪除對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則不允許刪除。當取值爲No Action或者Restrict時,則當在父表(即外鍵的來源表)中更新對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則不允許更新。
2、當取值爲Cascade時,則當在父表(即外鍵的來源表)中刪除對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則也刪除外鍵在子表(即包含外鍵的表)中的記錄。當取值爲Cascade時,則當在父表(即外鍵的來源表)中更新對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則也更新外鍵在子表(即包含外鍵的表)中的記錄。
3、當取值爲Set Null時,則當在父表(即外鍵的來源表)中刪除對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則設置子表中該外鍵值爲null(不過這就要求該外鍵允許取null)。當取值爲Set Null時,則當在父表(即外鍵的來源表)中更新對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則設置子表中該外鍵值爲null(不過這就要求該外鍵允許取null)。