Java面試題集錦
- Java基礎
1、ArrayList、Vector和LinkedList有什麼區別?
答:ArrayList底層實現是數組,查找快,增刪慢,線程不安全
Vector 和ArrayList內部實現一樣,線程安全
LinkedList內部實現是鏈表,查找慢,增刪快,封裝了許多增刪操作的方法
2、說說final、 finally和finalize的區別。
答: final可以修飾類、變量、方法
1)final修飾的類不能被繼承
2)final修飾的方法不能被子類重寫
3)final修飾的變量爲常量,不能再次賦值
4)public static final 共同修飾的成員變量,我們成爲全局常量,該變量應該所有字母大寫
public static final string COUNTRY = "china";
finally需要結合try..catch語句一起使用
finalize()方法在對象被回收之前調用
3、jsp的生命週期
答:JSP生命週期就是從創建到銷燬的整個過程,類似於servlet生命週期,區別在於JSP生命週期還包括將JSP文件編譯成servlet。
以下是JSP生命週期中所走過的幾個階段:
JSP編譯階段:
servlet容器編譯servlet源文件,生成servlet類
JSP初始化階段:
加載與JSP對應的servlet類,創建其實例,並調用它的初始化方法
JSP執行階段:
調用與JSP對應的servlet實例的服務方法
JSP銷燬階段:
調用與JSP對應的servlet實例的銷燬方法,然後銷燬servlet實例
很明顯,JSP生命週期的四個主要階段和servlet生命週期非常相似,下面給出圖示:
4、簡述servlet的生命週期
答:(1)加載和實例化
當客戶端發送一個請求時,Servlet容器會查找內存中是否存在該Servlet實例,若存在,則直接讀取該實例響應請求;若不存在,就創建一個Servlet實例。
(2) 初始化
實例化後,Servlet容器將調用init()方法進行初始化(一些準備工作或資源預加載工作)。
(3)請求處理
初始化後,Servlet處於能響應請求的就緒狀態。當接收到客戶端請求時,調用service()的方法處理客戶端請求,HttpServlet的service()方法會根據不同的請求,轉調不同的doXxx()方法。
(4)銷燬
當Servlet容器關閉時,Servlet實例也隨即銷燬。其間,Servlet容器會調用destroy()方法去判斷該Servlet是否應當被釋放(或回收資源)。
原文: https://blog.csdn.net/hu1010037197/article/details/80215093
servlet生命週期圖:
5、path和classpath環境變量的區別
答:path環境變量
當我們需要運行一個可執行命令的時候,系統首先會在當前目錄找,然後去註冊表找,如果都沒有,最後會去path環境變量所配置的目錄下去找。
查看和修改path環境變量的兩種方式:
1)在dos命令行窗口,查看:set path 修改:set path=%path%;c:\java\bin
2)在我的電腦-->屬性-->高級-->環境變量中查看和修改
classpath環境變量
JVM在運行一個程序時,首先會加載字節碼,這時就需要找到所要運行的字節碼文件
此時,虛擬機只會去classpath環境變量中配置的目錄下去找
在命令行中,"."表示當前目錄
path和classpath的區別:
操作系統執行一個.exe可執行文件的時候會去path下配置的目錄下去找
java虛擬機在運行一個類的時候,會去classpath下配置的目錄下去找
將 javac.exe 和 java.exe 可執行文件所在的目錄追加到path環境變量中
將需要運行的 class 文件所在的目錄追加到classpath環境變量中
6、String,StringBulider和StringBuffer有什麼區別?
答:StringBuilder:存儲快,線程不安全,適用於單線程;
StringBuffer:存儲慢,線程安全,適用於多線程
執行效率:StringBulider > StringBuffer > String
7、各協議端口號
表1-3 常用TCP服務和端口 |
表1-4 常見UDP服務和端口 |
||||
TCP端口 |
服務名 |
功 能 |
UDP端口 |
服務名 |
功 能 |
7 |
echo |
echo字符(用於測試) |
7 |
echo |
在另一個數據包中返回用戶的數據 |
9 |
discard |
丟棄字符串(用於測試) |
9 |
discard |
什麼也不做 |
13 |
daytime |
日期服務 |
13 |
daytime |
返回日期 |
19 |
chargen |
字符生成器 |
19 |
chargen |
字符生成器 |
21 |
ftp |
文件傳輸協議(FTP) |
37 |
time |
返回時間 |
22 |
ssh |
安全shell(虛擬終端或文件傳輸) |
53 |
domain |
域名服務(DNS) |
23 |
telnet |
遠程登錄 |
69 |
tftp |
普通文件傳輸協議 |
25 |
smtp |
電子郵件 |
111 |
sunrpc |
SUN的遠程過程調用(RPC) |
37 |
time |
時間服務 |
123 |
ntp |
網絡時間協議(Network Time Protocol,NTP) |
42 |
nameserve |
TCP名字服務 |
161 |
snmp |
簡單網絡管理協議 |
43 |
whois |
NIC whois服務 |
512 |
biff |
新郵件提示 |
53 |
domain |
域名服務(DNS) |
513 |
who |
收集關於用戶登錄到同一子網的其他機器的廣播 |
79 |
finger |
用戶信息 |
514 |
syslog |
系統日誌工具 |
80 |
http |
WWW(萬維網) |
517 |
talk |
發送talk請求 |
110 |
pop3 |
郵局協議3(POP3) |
518 |
ntalk |
一個“新”的talk請求 |
111 |
sunrpc |
SUN的遠程過程調用(RPC) |
520 |
route |
路由信息協議 |
113 |
auth |
遠程用戶名認證服務 |
533 |
netwall |
寫每個用戶的終端 |
119 |
nntp |
網絡新聞傳輸協議(NNTP) |
2049 |
NFS |
網絡文件系統協議(NFS) |
143 |
imap |
交互式郵件訪問協議 |
|||
443 |
https |
用SSL加密的HTTP |
|||
512 |
exec |
在遠程UNIX主機上執行命令 |
|||
513 |
login |
登錄到遠程UNIX主機(rlogin) |
|||
514 |
shell |
從遠程UNIX主機獲得shell(rsh) |
|||
TCP端口 |
服務名 |
功 能 |
|||
515 |
printer |
遠程打印 |
|||
1080 |
socks |
SOCKS應用代理服務 |
|||
2049 |
NFS |
TCP之上的NFS(NFS over TCP) |
|||
6000~6001 |
X |
X Window系統 |
8 、面向對象得特徵有哪些?
封裝:
封裝就是把描述一個對象的屬性和行爲的代碼放到一個類中,屬性用變量定義,行爲用方法進行定義,方法可以直接訪問同一個對象中的屬性。對象是封裝的最基本單位。
抽象:
抽象就是找出一些事物的相似和共性之處,然後將這些事物歸爲一個類,這個類只考慮這些事物的相似和共性之處,而忽略與目標無關的那些方面。比如:人是一個抽象的概念,人都有姓名和年齡這兩個屬性,我們將有姓名和年齡兩個屬性的事物稱爲人。
繼承:
繼承是子類自動共享父類數據和方法的機制,這是類之間的一種關係,提高了軟件的可重用性和可擴展性。
多態:
多態性是指允許不同類的對象對同一消息作出響應。多態性包括參數化多態性和包含多態
性。多態性語言具有靈活、抽象、行爲共享、代碼共享的優勢,很好的解決了應用程序函數
同名問題。
補充:多態是同一個行爲具有多個不同表現形式或形態的能力。
多態就是同一個接口,使用不同的實例而執行不同操作,如圖所示:
多態性是對象多種表現形式的體現。
9、接口和抽象類的區別?
接口特性
1)接口中每一個方法也是隱式抽象的,接口中的方法會被隱式的指定爲 public abstract(只能是 public abstract,其他修飾符都會報錯)。
2)接口中可以含有變量,但是接口中的變量會被隱式的指定爲 public static final 變量(並且只能是 public,用 private 修飾會報編譯錯誤)。
3)接口中的方法是不能在接口中實現的,只能由實現接口的類來實現接口中的方法。
抽象類和接口的區別
1)抽象類中的方法可以有方法體,就是能實現方法的具體功能,但是接口中的方法不行。
2)抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是 public static final 類型的。
3)接口中不能含有靜態代碼塊以及靜態方法(用 static 修飾的方法),而抽象類是可以有靜態代碼塊和靜態方法。
4)一個類只能繼承一個抽象類,而一個類卻可以實現多個接口。
(補充)接口和抽象類的區別:
抽象類:只聲明方法而不去實現該方法的類就是抽象類
接口:是特殊的抽象類。在接口中,所有方法都是抽象的。
(1)接口是公開的,不能有私有的方法或變量,而抽象類是可以有私有方法或私有變量的;
(2)實現接口時一定要實現接口裏定義的所有抽象方法,而實現抽象類可以有選擇地重寫需要用到的方法;
(3)接口可以實現多重繼承,而一個類只能繼承一個超類,但可繼承多個接口
(4)在abstract class 中可以有自己的數據成員,也可以有非abstarct的成員方法,
而在interface中,所有的成員方法都是abstract的,並且不能實現它(沒有方法體)。
(5)實現抽象類和接口的類必須實現其中的所有方法。抽象類中可以有非抽象方法。接口中則不能有實現方法。
10、什麼是面向對象?
答:類是對對象的抽象,對象是類的實例。我們生活的社會是由各種形態不同的事物所組成,而事物與事物之間都存在着各種各樣的聯繫,正是這樣的思想構成了面向對象編程思想的基礎。在程序中用對象來描述現實的事物,每一個事物都在程序中都對應一個具體的對象,我們在程序中對對象進行操作來模擬現實中事物之間的關係,這就是所謂的萬物皆對象。
11、服務器類型:
Server Type |
Server Name |
應用服務器 |
Jboss、JfOX3.0、openBJB、Resin、GlassFish、EasyBeans |
JSP 服務器 |
Tomcat、Bejy Tiger、Geronimo、Jetty、Jonas、Jrun、Orion、Resin |
Java EE 服務器 |
TongWeb、Apusic Application Server、IBM Websphere 、Sun Application Server、Oracle 的 Oracle9i/AS、Sun Java System Application Server、 Bea Weblogic、JBoss、開源GlassFish |
12、Session和Cookie的區別?
答:1)session保存在服務器,客戶端不知道其中的信息;cookie保存在客戶端,服務器能夠知道其中的信息。
2)session中保存的是對象,cookie中保存的是字符串。
3)session不能區分路徑,同一個用戶在訪問一個網站期間,所有的session在任何一個地方都可以訪問到。而cookie中如果設置了路徑參數,那麼同一個網站中不同路徑下的cookie互相是訪問不到的。
4)session默認需要藉助cookie才能正常工作。如果客戶端完全禁止cookie,session這種方法將失效。
但是如果服務器端啓用了url編碼,也就是用URLEncoder.encode("index.jsp?id=3","UTF-8");把所有的url編碼了,則會在url後面出現如下類似的東西:
index.jsp:jsessionid=fdsaffjdlksfd124324lkdjsf?id=3
服務器通過這個進行session的判斷。
5)session在用戶會話結束後就會關閉了,但cookie因爲保存在客戶端,可以長期保存。
6)COOKIE:是服務端向客戶端寫入的小的片段信息。session信息保存在服務器緩存區,不會在客戶端顯現。當你第一次登陸一個網站,服務器向你的機器寫得片段信息。你可以在Internet選項中找到存放cookie的文件夾。如果不刪除,cookie就一直在這個文件夾中。下次訪問時會自動發送對應的Cookie到服務器端。
13、Overload與Override的區別?
答:重載 Overload 表示同一個類中可以有多個名稱相同的方法,但這些方法的參數列表各
不相同(即參數個數或類型不同)。它是一個類中多態性的一種表現。
重寫 Override 表示子類中的方法可以與父類中的某個方法的名稱和參數完全相同,我們說該方法被重寫。它是父類與子類之間多態性的一種表現。
14、JSP和Servlet有什麼區別?
答:servlet是運行在服務器上的java應用程序,而jsp其實就是servlet程序,它可以寫java、html、JavaScript和css等等。在服務器端,jsp首先會被轉化成servlet,然後再按照servlet的順序執行。
jsp只是servlet的變種。
15、Jsp九大內置對象:
變量名 |
對象類型 |
page |
this |
pageContext |
PageContext |
request |
HttpServletRequest |
response |
HttpServletResponse |
session |
HttpSession |
application |
ServletContext |
config |
ServletConfig |
out |
JspWriter |
exception |
Throwable |
16、JSP頁面的靜態包含和動態包含有什麼區別?
答:參考https://www.cnblogs.com/wxgblogs/p/5602689.html
動態包含:<jsp:include page="被包含頁面">
父頁面和包含進來的頁面單獨編譯,單獨翻譯成servlet後,在前臺拼成一個HTML頁面。
靜態包含:<%@include file="被包含頁面"%>
父頁面和包含進來的頁面,代碼合併後,才一起翻譯成servlet,反饋到前臺,形成一個HTML頁面。
17、list、set和map的區別?
答:list:是有序的允許有重複元素的collection
set:是無序的不允許有重複元素的collection
(list和set都是collection的子類)
map:將鍵映射到值的對象(是雙列集合)
map和collection沒有任何關係
18、什麼是構造函數?
答:構造函數:
(1)構造函數的名稱與類名相同,參數可以有一個或多個,不同的構造函數參數類型可以不同;
(2)構造函數沒有返回值,不能用void來修飾;
(3)構造函數不能被直接調用,必須通過new運算符在創建對象時纔會被調用。而一般函數是在程序執行到它的時候纔會被調用。
特徵:函數的名稱與類名相同;
沒有返回值類型聲明;
不能在方法中使用return語句返回一個值。
注意:沒有返回值類型聲明不等同於”void”,void也是一種返回值類型聲明,那就是沒有返回值。
19、什麼是多線程?
答:多線程:
線程:(thread)在一個程序中,能獨立運行的程序片段就叫“線程”。它負責在單個程序裏執行多任務。
進程:每個正在系統上運行的程序都是一個進程。每個進程包含一到多個線程。
多線程:在單個程序中同時運行多個線程完成不同的工作,稱爲多線程.多線程主要是爲了節約CPU時間。
使用多線程的好處:
(1)可把佔據時間長的程序中的任務放到後臺去處理
(2)可使程序的運行速度加快
(3)可釋放資源和內存佔用
20、什麼是反射?
答:反射機制:
定義:JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;
對於任意一個對象,都能夠調用它的任意一個方法和屬性;
這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
功能:在運行時判斷任意一個對象所屬的類;
在運行時構造任意一個類的對象;
在運行時判斷任意一個類所具有的成員變量和方法;
在運行時調用任意一個對象的方法;
生成動態代理。
21、什麼是JDBC?它有什麼作用?
答:JDBC(Java Data Base Connectivity,java數據庫連接)是一種用於執行SQL語句的Java API,可以爲多種關係數據庫提供統一訪問,它由一組用Java語言編寫的類和接口組成。
簡單地說,JDBC 可做三件事:與數據庫建立連接、發送 SQL 語句並處理結果
22、==和equals方法的區別?
==操作符專門用來比較兩個變量的值是否相等,也就是用於比較變量所對應的內存中所存儲的數值是否相同,要比較兩個基本類型的數據或兩個引用變量是否相等,只能用==操作符。
(1)equals方法是用於比較兩個獨立對象的內容是否相同
(2)字符串的比較基本上都是使用equals方法。
(3)如果一個類沒有自己定義equals方法,它默認的equals方法(從Object 類繼承的)就是使用==操作符
23、靜態變量和實例變量的區別:
靜態變量:
(1)靜態變量前要加static關鍵字,可以通過類名.變量名的方式訪問;
(2)靜態變量屬於類,只要類被加載,不用創建人和實例對象,就可以使用了;
實例變量:
(1)實例變量是某個對象的屬性
(2)實例變量必須在創建對象後纔會被分配空間,才能被使用
24、Integer與int的區別:
(1)int是java提供的8種原始數據類型之一。
(2)Java爲每個原始類型提供了封裝類,Integer是java爲int提供的封裝類。
(3)int的默認值爲0,而Integer的默認值爲null,即Integer可以區分出未賦值和值爲0的區別,int則無法表達出未賦值的情況
25、ceil:天花板,向上取整,Math.ceil(11.3)的結果爲12,Math.ceil(-11.3)的結果是-11;
floor:地板,向下取整,Math.floor(11.6)的結果爲11,Math.floor(-11.6)的結果是-12;
round:表示四捨五入,Math.round(11.5)的結果爲12,Math.round(-11.5)的結果爲-11。
26、求n!
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.print("求正整數的階乘,請輸入一個正整數:");
long num = scan.nextLong();
test(num);
}
static long test(long num){
long sum = 1; //階乘的總和
if(num > 0 ){
for (int i = 1; i <= num; i++) {
sum *= i;
System.out.print(i+((i!=num)?"*":"="));//如果是最後一位的話,就不打印"*"號,打印"="號
}
System.out.print(sum);
return sum;
}else if(num == 0){
System.out.println(1);
return 1;
}else{
System.err.println("你的輸入有誤!");
return -1; //返回負數,說明有誤
}
}
27、forward和redirect的區別?
forward:請求轉發,是容器內的跳轉,瀏覽器只向服務器發送一次請求,地址欄無變化,它比redirect更高效,並且有助於隱藏實際的連接;
redirect:請求重定向,是容器外的跳轉,瀏覽器向服務器發送兩次請求,地址欄有變化,在瀏覽器地址欄裏可以看到跳轉後的連接地址。
28、判斷:
int a = 5;
Integer b = new Integer(5);
Integer c = new Integer(5);
判斷a==b,b==c,a.equals(b),c.equals(b)
答:a==b? true
b==c? false
a.equals(b)? false
c.equals(b)? true
29、java中的常用類、包和接口:
類:1.java.lang.Object
2.java.lang.String
3.java.lang.System
4.java.io.file
5.java.io.FileInputStream
包:1.java.lang包
2.java.io包
3.java.swt包
4.java.util包
5.java.sql包
接口:1.java.util.List<E>
2.java.util.Map<E>
3.java.util.Iterator<E>
4.java.sql.CallableStatement
5.java.lang.Comparable<T>
30、VO和PO的區別?
答: vo和po:
vo(value object):值對象,對應頁面中表單的屬性
po(persistant object):持久化對象,映射數據庫表
PO對象和VO對象相同點:都是javabean的對象,有set和get方法
PO對象和VO對象不同點:PO對象映射的是數據庫的表,當數據庫表的字段發生變化,PO對象同時要修改
VO對象對應頁面中表單的屬性,當表單屬性發生變化的時候,VO對象可以對應頁面的屬性同時發生變化
總結:VO對象對應表現層
PO對象對應持久層
31、異常的捕獲順序:
答:按照從小到大的順序捕獲。
在寫異常處理的時候,一定要把異常範圍小的放在前面,範圍大的放在後面,Exception這個異常的根類一定要放在最後一個catch裏面,如果放在前面或者中間,任何異常都會和Exception匹配的,就會報已捕獲到...異常的錯誤。
32、ajax之post提交:
(1)初始化XmlHttpRequest對象
function ajaxFunction(){
var xmlHttp;
try { // Firefox, Opera 8.0+, Safari
xmlHttp = new XMLHttpRequest();
}
catch (e) {
try {// Internet Explorer
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
}
}
}
return xmlHttp;
}
(2)
window.onload=function(){
document.getElementById("ok").onclick=function(){
//1、創建ajax引擎
var xmlHttp=ajaxFunction();
//2、服務器返回相應結果
xmlHttp.onreadystatechange = function(){
if(xmlHttp.readyState == 4){
if(xmlHttp.status == 200 || xmlHttp.status == 304){
var data = xmlHttp.responseText;
alert(data);
}
}
}
//3、打開與服務器的連接
var url="../testServlet?c=10×tamp="
xmlHttp.open("post",url+new Date().getTime(),true);
xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
//4、發送請求數據
xmlHttp.send("a=8&b=9");
}
}
33、內存溢出與內存泄漏的區別?
答:參考https://www.cnblogs.com/Sharley/p/5285045.html
內存溢出(out of memory),是指程序在申請內存時,沒有足夠的內存空間供其使用,出現out of memory;比如申請了一個integer,但給它存了long才能存下的數,那就是內存溢出。
內存泄露(memory leak),是指程序在申請內存後,無法釋放已申請的內存空間,一次內存泄露危害可以忽略,但內存泄露堆積後果很嚴重,無論多少內存,遲早會被佔光。
34、如何對兩個整數變量的值進行互換(不引入第三方變量)?
x=x+y;
y=x-y;
x=x-y;
35、兩個集合如何取交集?
答:用雙層for循環去比較,value值相同,counter加1。
36、List,ArrayList和LinkedList有什麼區別?
答:List是一個有序、允許有重複元素的集合,它是ArrayList和LinkedList的父類;
ArrayList底層實現是數組,查找快,增刪慢,線程不安全;
Vector 和ArrayList內部實現一樣,線程安全;
LinkedList內部實現是鏈表,查找慢,增刪快,封裝了許多增刪操作的方法。
37、Jquery去除div標籤中的內容如何實現?
答:$(“#id”).empty() 或者 $(“#id”).html(“”);
38、HashMap和HashTable有何區別?
答:1)繼承的類不同:HashMap繼承自AbstractMap,HashTable繼承Dictionary;
2)執行效率不同:HashMap線程不安全,是Hashtable的輕量級實現,效率高。HashTable線程安全,效率低;
3)put()對key和value的要求不同:
HashMap允許Entry的key或value爲null;
HashTable不允許Entry的key或value爲null
4)有無contains方法:HashMap無contains(),HashTable有contains().
39、如何防止form表單提交?
答:參考https://blog.csdn.net/Huozhiwu_11/article/details/78742886
1)用js禁掉提交按鈕;
2)在數據庫裏創建唯一索引來有效防重;
3)在表單數據入庫前,先校驗數據庫中是否存在與插入數據相同的記錄,存在進行事務回滾,不存在執行事務提交;
40、String字符串底層 String s = new String(“abc”);創建了幾個對象?
答:一共創建了3個對象,實際上"abc"本身就是文字池中的一個對象,在運行 new String()時,把文字池pool中的字符串"abc"複製到堆中,並把這個對象的應用交給s,所以創建了兩個String對象,一個在pool中,一個在堆中。
41、java中有哪些臨界值?
答:比如8中基本數據類型的取值範圍:
數組長度array.lenght,超過數組定義的長度,報ArraylndexOutOfBoundException(數組角標越界異常)
42、同步和異步有什麼區別?
答:同步交互(Sync):指發送一個請求,需要等待返回,然後才能夠發送下一個請求,有個等待過程(同步可看作單線程);
異步交互(Async):指發送一個請求,不需要等待返回,隨時可以再發送下一個請求,即不需要等待(異步可看作多線程)。
例如:喫飯和說話,只能一件事一件事的來,因爲只有一張嘴。
和聽音樂是異步的,因爲,聽音樂並不引響我們喫飯。
43、對外提供服務是那種方式?
答:webservice、http或RMI
44、jdk1.6,jdk1.7和jdk1.8有什麼區別?
答:參考http://blog.csdn.net/sysmedia/article/details/53608681
45、請談談static
答:static方法就是沒有this的方法。在static方法內部不能調用非靜態方法,反過來是可以的。而且可以在沒有創建任何對象的前提下,僅僅通過類本身來調用static方法。這實際上正是static方法的主要用途。
被static關鍵字修飾的方法或者變量不需要依賴於對象來進行訪問,只要類被加載了,就可以通過類名去進行訪問。
static可以用來修飾類的成員方法、類的成員變量,另外可以編寫static代碼塊來優化程序性能。
1)static方法
靜態方法中不能訪問類的非靜態成員變量和非靜態成員方法,但是在非靜態成員方法中是可以訪問靜態成員方法/變量的。
即使沒有顯示地聲明爲static,類的構造器實際上也是靜態方法。
2)static變量
static變量也稱作靜態變量,靜態變量和非靜態變量的區別是:靜態變量被所有的對象所共享,在內存中只有一個副本,它在類加載時會被初始化。而非靜態變量是對象所擁有的,在創建對象的時候被初始化,存在多個副本,各個對象擁有的副本互不影響。
static成員變量的初始化順序按照定義的順序進行初始化。
3)static代碼塊
static關鍵字還有一個比較關鍵的作用就是用來形成靜態代碼塊以優化程序性能(只會在類加載的時候執行一次)。static塊可以置於類中的任何地方,類中可以有多個static塊。在類初次被加載的時候,會按照static塊的順序來執行每個static塊,並且只會執行一次。
4)static是不允許用來修飾局部變量
46、什麼是微服務?
答:微服務架構是將單個的整體應用分割成更小的項目關聯的獨立的服務。一個服務通常實現一組獨立的特性或功能,包含自己的業務邏輯和適配器。各個微服務之間的關聯通過暴露API來實現。
47、爲什麼要用微服務架構?
答:1)由於每個服務都是獨立並且微小的,由單獨的團隊負責,可以採取敏捷開發模式,自由的選擇合適的技術,甚至可以重寫舊服務,當然都要遵守統一的API約定。
2)每一個微服務都是獨立部署的,可以進行快速迭代部署,根據各自服務需求選擇合適的虛擬機和使用最匹配的服務資源要求的硬件。
3)整體應用程序被分解成可管理的模塊和服務,單個的服務可以更快的開發,更簡單的理解和維護。
4)、一些需要進行負載均衡的服務可以部署在多個雲虛擬機上,加入Nginx這樣的負載均衡器在多個實例之間分發請求,這樣不需要整個應用進行負載均衡了。
5)每個後端服務暴露一套REST API,大部分服務調用其他服務提供的API。每個服務都有自己的數據庫模式,而不是共享單個數據庫模式。儘管這會造成某些數據的冗餘,但是對於微服務架構這個獨立的數據庫模式是必要的,確保了獨立服務之間的鬆散耦合。
微服務的缺點:
1)微服務應用作爲分佈式系統帶來了複雜性
2)多個獨立數據庫,事務的實現更具挑戰性
3)測試微服務變得複雜,當一個服務依賴另外一個服務時,測試時需要另外一個服務的支持
4)部署基於微服務的應用也很複雜,整體應用程序部署只需要部署在一組相同的服務器上,在這些服務前面加入傳統的負載均衡器即可。
1、JVM包含哪些部分?什麼是GC算法?內存溢出是在什麼情況下發生的?
答:jvm包含方法區、java堆、java棧和本地方法棧
Method area中存放了所有加載的類的信息,如:名稱、修飾符,類中的靜態變量,final類型的常量,field信息,類中的方法等;
Jvm stack存放的是變量;
Jvm heap存放對象實例
Native method stack存儲每個本地方法調用的狀態
GC:當內存中的某個對象不再被使用了,就會進行垃圾回收,GC會消耗一些資源和時間。
內存溢出:當方法區域需要使用的內存超過其允許的大小時,就會拋出OutOfMemory信息。
Jvm初始分配的內存由-Xms指定,默認是物理內存的1/64;最大分配內存由-Xmx指定,默認是物理內存的1/4.
2、JVM優化方法。
答:參考http://uule.iteye.com/blog/2114697
1、線程池和連接池有什麼區別?
答:線程池:
把併發執行的任務傳遞給一個線程池,來替代爲每個併發執行的任務都啓動一個新的線程,只要池裏有空閒的線程,任務就會分配給一個線程執行。在線程池的內部,任務被插入一個阻塞隊列(blocking queue),線程池裏的線程會去取這個隊列裏的任務。當一個新任務插入隊列時,一個空閒線程就會成功的從隊列中取出任務並執行它。
線程池經常應用在多線程服務器上。每個通過網絡到達服務器的鏈接都會被包裝成一個任務並且傳遞給線程池。線程池的線程會併發的處理連接上的請求。
連接池:是一個等待數據庫連接的隊列。
過程大概是這樣:客戶端向服務器端請求連接, 服務器端先看連接池中是否有空的連接,如果有空的連接就讓該客戶端連接,如果沒有空的連接,那就看現有連接數是否達到連接池限定的個數,如果沒有達到就爲該客戶端創建一個連接,如果達到了那就讓該客戶端排隊,等其他客戶端斷開連接了,就讓該客戶端連接。
連接池會設定一個等待時間,超過這個時間就就是連接超時了, 一般服務器性能和網速都會有影響。SQLSERVER支持同時255個連接。
2、Java高併發訪問怎麼解決?
答:(1)儘量使用緩存,包括用戶緩存、信息緩存等,可以大量減少與數據庫的交互,提高性能。
(2)用jprofiler等工具找出性能瓶頸,減少額外的開銷。
(3)優化數據庫,包括sql語句(多做索引)和數據結構(分庫、分表)的優化,提高查詢效率。
(4)對統計的功能儘量做緩存,按天或定時統計相關報表,避免進行實時統計。
(5)將動態頁面生成靜態html來顯示,減少容器的解析。
(6)使用集羣解決單臺服務器的瓶頸問題。
3、多臺服務器分佈式部署,如何保證數據的唯一性?
答:在數據庫表中加version字段,引入樂觀鎖。
4、用Redis和Memcached緩存處理高併發時,如何將數據持久化?
答:Redis持久化有兩種方式:
(1)AOF(append-only file),在執行寫命令時,將被執行的命令複製到AOF文件末尾,以此來記錄數據發生的變化。
(2)RDB持久化,在指定時間間隔內內存中的數據集快照寫入磁盤(以快照方式寫入二進制文件,默認文件名爲dump.rdb)。
- 用IO流讀取大文件(512M)用什麼類?
答:ConcurrentHashMap
- Kafka推送數據一定安全嗎?
答:不一定,當推送速度達到毫秒級時,會產生重複推送。
(1)kafka的數據交換是在哪裏完成的?在內存中完成數據交換
(2)kafka緩存的數據在哪裏?kafka使用broker來接受producer和consumer的請求,並把message持久化到本地磁盤。
(3)kafka數據怎麼丟?
1)對於broker,落盤的數據,除非磁盤壞了,會丟;
2)對於內存中沒有flush(清洗)的數據,broker重啓會丟。
3)producer到broker;
4)broker到consumer;
(4)kafka數據重複處理:
1)kafka採用基於時間的SLA(服務水平保證),消息保存一定時間(通常爲7天)後會被刪除。重複數據一般出現在consumer端,這時可以採用log.cleanup.policy=delete定期刪除機制。
2)將數據存儲到redis中,在redis中去重;
3)調用kafka的api來編碼去重;
7、如何理解分佈式?什麼是負載均衡?
答:分佈式是以縮短單個任務的執行時間來提升效率的,而集羣則是提高單位時間內執行的任務書來提升效率的。
分佈式:指將不同業務部署在不同的服務器上;
集羣:指將幾臺服務器集中在一起,實現同一業務。
負載均衡:負載均衡是由多臺服務器以對稱的方式組成一個服務器集合,每臺服務器都
具有等價的地位,都可以單獨對外提供服務而無須其他服務器的輔助。通過某種負載分擔技術,將外部發送來的請求均勻分配到對稱結構中的某一臺服務器上,而接收到請求的服務器獨立地迴應客戶的請求。均衡負載能夠平均分配客戶請求到服務器列陣,籍此提供快速獲取重要數據,解決大量併發訪問服務問題。這種羣集技術可以用最少的投資獲得接近於大型
主機的性能。
8、synchronized的修飾對象有哪些?
答:synchronized是JAVA中的關鍵字,是一種同步鎖。
它修飾的對象有:
1)修飾一個代碼塊,被修飾的代碼塊稱爲同步代碼塊,其作用範圍是大括號{}括起來的代碼,作用對象是調用這個代碼塊的對象
2)修飾一個方法,被修飾的方法稱爲同步方法,其作用範圍是整個方法,作用的對象是調用這個方法的對象
3)修飾一個靜態的方法,其作用範圍是整個靜態方法,作用對象是這個類的所有對象
靜態方法是屬於類的而不屬於對象的。synchronized修飾的靜態方法鎖定的是這個類的所有對象(實例)。
4)修飾一個類,其作用範圍是synchronized後面括號括起來的部分,作用對象是這個類的所有對象
9、兩個線程訪問兩個synchronized方法會怎麼樣?
答:分四種情況:
1)兩個併發線程調用同一實例的synchronized方法,第二個Thread會被第一個Thread阻塞,第一個Thread執行完後再執行第二Thread。兩個Thread是互斥的。
2)兩個併發線程調用不同實例的synchronized方法,會給兩個實例創建兩個鎖,兩個線程互不影響。
3)兩個併發線程,一個訪問對象的synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該對象中的非synchronized(this)同步代碼塊。
4)兩個併發線程,一個訪問對象的synchronized非靜態方法,一個訪問對象的synchronized靜態方法:因靜態方法是屬於類的,所以Thread2會被阻塞,2個Thread用的是同一把鎖。
總結:無論synchronized關鍵字加在方法上還是對象(實例)上,如果它作用的對象是非靜態的,則它取得的鎖是對象;如果synchronized作用的對象是一個靜態方法或一個類,則它取得的鎖是對類,該類所有的對象同一把鎖。
10、談談緩存機制?
答:緩存就是將程序或系統經常要調用的對象存放在內存中,以便再次使用時可以快速調用,而不必去創建新的重複的實例。這樣做可以減少系統開銷,提高系統效率。
在項目中使用緩存,通常都是先檢查緩存中是否存在目標數據,如果存在直接返回緩存內容,如果不存在就直接查詢數據庫然後再緩存查詢結果。
緩存主要可分爲二大類:
1)文件緩存,是指把數據存儲在磁盤上,不管你是以XML格式,序列化文件DAT格式還是其它文件格式;
2)內存緩存,就是實現一個類中靜態Map,對這個Map進行常規的增刪改查。
11、緩存穿透是什麼?如果一個線程在緩存中沒有查到Key,去DB中去取了,這時又有很多線程來取此Key,也一起去DB去取,怎麼辦?
緩存雪崩
緩存雪崩是因爲數據未加載到緩存中,或者緩存同一時間內大面積失效,從而導致所有請求都去查數據庫,導致數據庫CPU和內存負載過高,甚至宕機。
解決思路:
1)採用加鎖計數,或者使用合理的隊列數量來避免緩存失效時對數據庫造成太大的壓力。這種辦法雖然能緩解數據庫的壓力,但是同時又降低了系統的吞吐量。
2)分析用戶行爲,儘量讓失效時間點均勻分佈。避免緩存雪崩的出現。
3)如果是因爲某臺緩存服務器宕機,可以考慮做主備,比如:redis主備,但是雙緩存涉及到更新事務的問題,update可能讀到髒數據,需要好好解決。
緩存穿透
緩存穿透是指用戶查詢數據,在數據庫沒有查到,自然在緩存中也不會有。這樣就導致用戶查詢的時候,在緩存中找不到,每次都要去數據庫中查詢。
解決思路:
1)如果查詢數據庫也爲空,直接設置一個默認值存放到緩存,這樣第二次到緩衝中獲取就有值了,而不會繼續訪問數據庫,這種辦法最簡單粗暴。
2)根據緩存數據Key的規則。例如我們公司是做機頂盒的,緩存數據以Mac爲Key,Mac是有規則,如果不符合規則就過濾掉,這樣可以過濾一部分查詢。在做緩存規劃的時候,Key有一定規則的話,可以採取這種辦法。這種辦法只能緩解一部分的壓力,過濾和系統無關的查詢,但是無法根治。
3)採用布隆過濾器,將所有可能存在的數據哈希到一個足夠大的BitSet中,不存在的數據將會被攔截掉,從而避免了對底層存儲系統的查詢壓力。
大併發的緩存穿透會導致緩存雪崩。
緩存併發
如果網站併發訪問高,一個緩存失效,可能會出現多個進程同時查詢DB,同時設置緩存的情況,這也可能造成DB壓力過大,還有緩存頻繁更新的問題。
對緩存查詢加鎖,如果KEY不存在,就加鎖,然後查DB入緩存,然後解鎖;其他進程如果發現有鎖就等待,然後等解鎖後返回數據或者進入DB查詢。只不過利用鎖的方式,會造成部分請求等待。
緩存失效
在高併發訪問的時候,平常我們在設定一個緩存的過期時間時,可能會設置1分鐘,5分鐘...,但併發很高時可能會出在某一個時間同時生成了很多的緩存,並且過期時間都一樣,這個時候就可能引發緩存同時失效,請求全部轉發到DB,DB可能會壓力過重。
那如何解決這些問題呢?
一個簡單方案就是,將緩存失效時間分散開,比如我們可以在原有的失效時間基礎上增加一個隨機值,比如1-5分鐘隨機,這樣每一個緩存的過期時間的重複率就會降低,就很難引發集體失效的事件。
- MQ消息隊列
1、ActiveMQ、RobbitMQ等消息隊列它們有哪些對象?實現原理是什麼?
答:有生產者和消費者。Queue的原理是先進先出
2、談談你對消息的理解?
答:消息是JMS(JAVA消息服務)中的一種類型對象
1)消息包含:消息頭、消息屬性、消息自身
消息頭主要定義消息的Topic、消息序列、消息類型
2)消息傳送是建立在Observer設計模式基礎上的
3)消息傳送有兩種模型
發佈/訂閱(Publish/Subscribe)模型:客戶端發送消息到一個名爲主題(topic)的虛擬通道中,每個訂閱該主題的消費者都會接收到每條消息的一個副本。
點對點(Point to point)模式:客戶端通過隊列(queue)這個虛擬通道來同步和異步發送、接收消息,發送到隊列的消息只能被一個接收者所接收,即使有多個消費者時也只能有一個消費者處理消息。
4)在消息接收上分爲推模型和拉模型,它們使用輪詢或事件驅動方式來進行消息接入。對消息服務而言,還要考慮消息消費模式:消息分派還是消息獲取,消息的訂閱與過濾機制、消息接入應用是同步處理還是異步處理。
5)什麼時候用到消息機制?
A、異構系統集成,整合現有資源,提高資源的利用率
B、異步請求處理,減輕或消除系統瓶頸,提高用戶生產率和系統的整體可伸縮性
C、組件解偶,增加系統的靈活性
Struts2
1、Struts在項目中的作用?
答:1)Struts 在項目主要起控制作用,只要用於web層(即視圖層和控制層);
2)Struts把Servlet、JSP、自定義標籤和信息資源(message resources)整合到一起實現了MVC結構,使項目結構更清晰,分工更明細。
3)Struts在項目中主要負責視圖層、控制層,在視圖層提供了大量的標籤庫,提高視圖層的開發速度。在控制層使用中央控制器(Actionsupport)和配置文件(struts.xml),實現攔截用戶請求、封裝請求參數及頁面導航。
答:參考https://blog.csdn.net/Huozhiwu_11/article/details/88889067
1)Intercepter是基於java反射機制的,是AOP的一種實現,而Filter是基於函數回調的。
2)Intercepter不依賴servlet容器,而Filter依賴於servlet容器。
3)Intercepter只對Action請求起作用,而Filter幾乎對所有請求都起作用。
4)Intercepter可以訪問Action上下文、值棧裏的對象,而Filter不能。
5)在Action的生命週期中,Intercepter可以多次調用,而Filter只能在容器初始化時被調用一次。
攔截器(Intercepter) :是基於AOP的一種實現,就是在你的service或方法前調用一個方法,或在方法後調用一個方法,來達到攔截目的(比如:動態代理就是攔截器的簡單實現)。在你調用方法前打印出字符串,也可以在你調用方法後打印出字符串,甚至在你拋出異常的時候做業務邏輯的操作。
下面通過demo來看一下過濾器和攔截器的區別:
使用攔截器進行/admin 目錄下jsp頁面的過濾
<package name="newsDemo" extends="struts-default" namespace="/admin">
<interceptors>
<interceptor name="auth" class="com.test.news.util.AccessInterceptor" />
<interceptor-stack name="authStack">
<interceptor-ref name="auth" />
</interceptor-stack>
</interceptors>
<action name="newsAdminView!*" class="newsAction" method="{1}">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="authStack"/>
</action>
下面是我實現的Interceptor class:
package com.test.news.util;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.test.news.action.AdminLoginAction;
public class AccessInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = -4291195782860785705L;
@Override
public String intercept(ActionInvocation actionInvocation) throws Exception {
ActionContext actionContext = actionInvocation.getInvocationContext();
Map session = actionContext.getSession();
//except login action
Object action = actionInvocation.getAction();
if (action instanceof AdminLoginAction) {
return actionInvocation.invoke();
}
//check session
if(session.get("user")==null ){
return "logout";
}
return actionInvocation.invoke();
}
}
Intercepter主要特點在於:針對你不要的東西進行攔截,比如說,在一個BBS裏面你希望人家不要留“TMD”的這個詞,那你就可能採用Intercepter。
過濾器(filter):在用戶發送request請求前,提前過濾掉一些信息,或者設置一些參數,然後再傳入servlet或struts的action處理業務邏輯。比如過濾掉非法url(不是login.do的地址請求,如果用戶沒有登陸都過濾掉),或者在傳入servlet或struts的action前統一設置字符集,或去除掉一些非法字符。
使用過濾器進行/admin 目錄下jsp頁面的過濾,首先在web.xml進行過濾器配置:
<filter>
<filter-name>access filter</filter-name>
<filter-class> com.test.news.util.AccessFilter </filter-class>
</filter>
<filter-mapping>
<filter-name>access filter</filter-name>
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
下面是過濾的實現類:
package com.test.news.util;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class AccessFilter implements Filter {
public void destroy() { }
public void init(FilterConfig arg0) throws ServletException { }
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)arg0;
HttpServletResponse response = (HttpServletResponse)arg1;
HttpSession session = request.getSession();
if(session.getAttribute("user")== null && request.getRequestURI().indexOf("login.jsp")==-1 ){
response.sendRedirect("login.jsp");
return ;
}
filterChain.doFilter(arg0, arg1);
}
}
Filter主要特點在於:取你需要的東西,忽視那些不需要的東西。
3、Struts2中讀取配置文件的順序?
答: web.xml--->default.properties--->struts-default.xml--->truts-plugin.xml--->struts.xml
Spring
1、Spring在項目中的作用?
答:1)Spring是一個全方位的整合框架,在項目中對hibernate(持久層)和struts(表現層)進行整合,解決層與層之間的耦合問題;
2)Spring的作用貫穿了整個中間層,將Web層、Service層、DAO層及PO無縫整合;
3)Spring的IoC機制負責對象創建和依賴關係注入,上層框架不會滲透到下層組件,提高組件移植性和重用性,使得程序更靈活,上層框架不依賴實現而是依賴於抽象(委託接口)、使得實現類的變化不會影響上層組件,解決了層與層之間的藕合帶來的維護或升級困難;
4)Spring 提供對AOP編程支持,實現對程序進行權限攔截和運行監控等功能,實現插件式編程。
5)Spring提供了對聲明式事務的支持,只需要通過配置就可以完成對事務的管理。
Spring核心:
參考https://blog.csdn.net/Huozhiwu_11/article/details/88888391
控制反轉(IoC / Inversion of Control):應用程序(調用者)本身不負責依賴對象(被調用者)的創建和維護,而是由外部容器負責創建組裝。這樣控制權就由應用程序轉移到了外部容器,控制權的轉移就是所謂的反轉。
依賴注入(DI / Dependency Injection):在程序運行時,由外部容器將創建好的依賴對象注入到調用者組件中。
2、什麼是AOP?有哪些應用場景?
答:參考http://www.cnblogs.com/xrq730/p/4919025.html
應用場景:權限認證、日誌記錄、事務處理和性能統計等
3、Spring是單例還是多例的?
答:默認是單實例的,scope=“singleton”。也可以設置成scope=“prototype”原型模式,針對每次不同的請求,bean容器均會生成一個全新的bean實例來供調用者使用。
4、Spring2.5和Spring3.0有什麼區別?
答:參考http://blog.csdn.net/abigfrog/article/details/4748685
5、Spring如何管理事務?Spring實例在何時創建?
答:編程式事務管理:將事務管理代碼嵌入到業務方法中來控制事務的提交和回滾,在編程式事務中,必須在每個業務操作中包含額外的事務管理代碼。
聲明式事務管理:大多數情況下比編程式事務管理更好用。它將事務管理代碼從業務方法中分離出來,以聲明的方式來實現事務管理。事務管理作爲一種橫切關注點,可以通過AOP方法模塊化。Spring通過Spring AOP框架支持聲明式事務管理。
Spring管理事務:
參考https://blog.csdn.net/trigl/article/details/50968079
https://blog.csdn.net/chinacr07/article/details/78817449
創建bean時機(分兩種情況):
第一:如果使用BeanFactory作爲Spring Bean的工廠類,則所有的bean都是在被調用的時候實例化;
第二:如果你使用ApplicationContext作爲Spring Bean的工廠類,則又分爲以下幾種情況: 1)如果bean的scope=“singleton”,並且lazy-init=“false”(lazy-init:延遲初始化,默認是false),則ApplicationContext啓動的時候就實例化該Bean;
2)如果bean的scope=“singleton”,並且lazy-init=“true”,bean是在被調用的時候被實例化;
3)如果bean的scope=“prototype”,會每次調用時生產一個。
參考http://blog.csdn.net/jkl852qaz/article/details/52850298
https://blog.csdn.net/java_gchsh/article/details/78111200
SpringMVC
1、SpringMVC的原理是什麼?
答:1)客戶端發出一個http請求給web服務器,web服務器對http請求進行解析,如果匹配DispatcherServlet的請求映射路徑(在web.xml中指定),web容器將請求轉交給DispatcherServlet。
2)DipatcherServlet接收到這個請求之後將根據請求的信息(包括URL、Http方法、請求報文頭和請求參數Cookie等)以及HandlerMapping的配置找到處理請求的處理器(Handler)。
3-4)DispatcherServlet根據HandlerMapping找到對應的Handler,將處理權交給Handler(Handler將具體的處理進行封裝),再由具體的HandlerAdapter對Handler進行具體的調用。
5)Handler對數據處理完成以後將返回一個ModelAndView()對象給DispatcherServlet。
6)Handler返回的ModelAndView()只是一個邏輯視圖並不是一個正式的視圖,DispatcherSevlet通過ViewResolver將邏輯視圖轉化爲真正的視圖View。
7)Dispatcher通過model解析出ModelAndView()中的參數進行解析最終展現出完整的view並返回給客戶端。
2、SpringMVC和Struts2的MVC有什麼區別?
答:1)Struts2是類級別的攔截, 一個類對應一個request上下文,SpringMVC是方法級別的攔截,一個方法對應一個request上下文,而方法同時又跟一個url對應,所以說從架構本身上SpringMVC就容易實現restful url,而struts2的架構實現起來要費勁,因爲Struts2中Action的一個方法可以對應一個url,而其類屬性卻被所有方法共享,這也就無法用註解或其他方式標識其所屬方法了。
- 由上邊原因,SpringMVC的方法之間基本上獨立的,獨享request response數據,請求數據通過參數獲取,處理結果通過ModelMap交回給框架,方法之間不共享變量,而Struts2搞的就比較亂,雖然方法之間也是獨立的,但其所有Action變量是共享的,這不會影響程序運行,卻給我們編碼 讀程序時帶來麻煩,每次來了請求就創建一個Action,一個Action對象對應一個request上下文。
3)由於Struts2需要針對每個request進行封裝,把request,session等servlet生命週期的變量封裝成一個一個Map,供給每個Action使用,並保證線程安全,所以在原則上,是比較耗費內存的。
- 攔截器實現機制上,Struts2有以自己的interceptor機制,SpringMVC用的是獨立的AOP方式,這樣導致Struts2的配置文件量還是比SpringMVC大。
- SpringMVC的入口是servlet,而Struts2是filter(這裏要指出,filter和servlet是不同的。以前認爲filter是servlet的一種特殊),這就導致了二者的機制不同,這裏就牽涉到servlet和filter的區別了。
- SpringMVC集成了Ajax,使用非常方便,只需一個註解@ResponseBody就可以實現,然後直接返回響應文本即可,而Struts2攔截器集成了Ajax,在Action中處理時一般必須安裝插件或者自己寫代碼集成進去,使用起來也相對不方便。
- SpringMVC驗證支持JSR303,處理起來相對更加靈活方便,而Struts2驗證比較繁瑣,感覺太煩亂。
- spring MVC和Spring是無縫的。從這個項目的管理和安全上也比Struts2高(當然Struts2也可以通過不同的目錄結構和相關配置做到SpringMVC一樣的效果,但是需要xml配置的地方不少)。
- 設計思想上,Struts2更加符合OOP的編程思想, SpringMVC就比較謹慎,在servlet上擴展。
- SpringMVC開發效率和性能高於Struts2。
11)SpringMVC可以認爲已經100%零配置。
3、View和ModelAndView有什麼區別?
答:View:視圖;ModelAndView包含數據模型和視圖;ViewResolver:視圖解析器
4、SpringMVC中方法的返回值有哪些?
答:SpringMVC中返回值類型有:ModelAndView, Model, ModelMap, Map, View, String, void。
5、SpringMVC實現原理是什麼?
答:1)啓動服務器,根據web.xml的配置加載前端控制器(也稱總控制器) DispatcherServlet 。在加載時會完成一系列的初始化動作。
2)根據servlet的映射請求(上面的HelloWorld實例中針對.do 請求),並參照“控制器配置文件”(即springMVC-servlet.xml 這樣的配置文件),把具體的請求分發給特定的後端控制器進行處理(比如上例會分發給HelloWorld 控制器進行處理)
3)後端控制器調用相應的邏輯層代碼,完成處理並返回視圖對象( ModelAndView )給前端處理器。
4)前端控制器根據後端控制器返回的ModelAndView 對象,前端控器器根據視圖對象返回具體頁面給客戶端。
6、AOP環繞通知
aop通知有:前置通知、後置通知、環繞通知和異常通知
環繞通知其實就是動態代理的另一種實現,它是對匹配方法的一種包裹,可以實現其他的通知。
該類型的通知使用的是@Around註解,並且使用ProceedingJoinPoint代替之前的JoinPoint來獲取方法的參數和簽名等信息,同時通過它的實例對象來調用匹配的方法,因此這個類型的參數是必須有的。另外,該通知還必須有返回值,它的方法可以對應JDK中的動態代理中的invoke()方法,它的返回值就是Target的返回值。
環繞通知和其他通知的區別:
1)目標方法的調用由環繞通知決定,即你可以決定是否調用目標方法,而前置和後置通知是不能決定的,他們只是在方法的調用前後執行通知而已,即目標方法肯定是要執行的。
2)環繞通知可以控制返回對象,即你可以返回一個與目標對象完全不同的返回值,雖然這很危險,但是你卻可以辦到。而後置方法是無法辦到的,因爲他是在目標方法返回值後調用。
Hibernate
1、Hibernate在項目中的作用?
答:1)Hibernate對JDBC進行了封裝,實現了對象的持久化;
2)它實現了ORM(Object/Relation Mapping),提供了從 Java類到數據表的映射,也提供了數據查詢和恢復等機制;
3)實現了連接池(一個等待數據庫連接的隊列);
4)操作數據庫
2、Hibernate一級緩存和二級緩存有什麼區別?
答:緩存:就是要將一些經常使用的數據緩存到內存或者各種儲存介質中,當再次使用時可以不用去數據庫中查詢,減少與數據庫的交互,提高性能。
一級緩存:是Session級別的,它在一個事務中才會啓作用,session關閉時就失效了。一級緩存時hibernate自帶的,不可以卸載;
二級緩存:是sessionFactory級別的,它的生命週期作用於應用程序的整個過程。適合放在二級緩存中的數據爲:很少被修改的數據,不是很重要的數據,不會被併發訪問的數據,以及參考數據。不適合放在二級緩存中的數據爲:經常被修改的數據,財務數據,與其他應用共享的數據。二級緩存是一個可插拔的緩存插件。
3、hibernate中對象的三種狀態:
自由態:通過new關鍵字創建的實體對象處於自由態
通過save()或saveOrUpdate()可轉化爲持久態
持久態:被保存到數據庫中的實體對象
通過delete()可轉化爲自由態
通過clear()、close()或evict()可轉化爲遊離態
遊離態:脫離hibernate緩存管理的對象
通過update()或saveOrUpdate()可轉化爲持久態
通過delete()可直接轉化爲自由態
4、get和load加載的區別?
答:hibernate中,get()方法是直接加載,load()方法是延遲加載;
5、hibernate離線時如何去掉重複記錄?
答:使用離線查詢對象DetachedCriteria。該對象不是由session創建,而是由forClass或forEntityName來創建。
Mybatis
1、MyBatis配置文件中“#”和“$”有何區別?
答:(1)#會將傳入的數據當做字符串,自動加上引號;$是將傳入的數據直接顯示。
(2)#能防止sql注入,而$不能
(3)$一般傳入數據庫對象。
2、MyBatis和Hibernate有什麼區別?
答:1)hibernate是全自動,而mybatis是半自動。
hibernate完全可以通過對象關係模型實現對數據庫的操作,擁有完整的JavaBean對象與數據庫的映射結構來自動生成sql。而mybatis僅有基本的字段映射,對象數據以及對象實際關係仍然需要通過手寫sql來實現和管理。
2)hibernate數據庫移植性遠大於mybatis。
hibernate通過它強大的映射結構和hql語言,大大降低了對象與數據庫(oracle、 mysql等)的耦合性,而mybatis由於需要手寫sql,因此與數據庫的耦合性直接取決於程序員寫sql的方法,如果sql不具通用性而用了很多某 數據庫特性的sql語句的話,移植性也會隨之降低很多,成本很高。
3)hibernate擁有完整的日誌系統,mybatis則欠缺一些。
hibernate日誌系統非常健全,涉及廣泛,包括:sql記錄、關係異常、優化警告、緩存提示、髒數據警告等;而mybatis則除了基本記錄功能外,功能薄弱很多。
4)mybatis相比hibernate需要關心很多細節
hibernate配置要比mybatis複雜的多,學習成本也比mybatis高。但也正因爲 mybatis使用簡單,才導致它要比hibernate關心很多技術細節。mybatis由於不用考慮很多細節,開發模式上與傳統jdbc區別很小,因 此很容易上手並開發項目,但忽略細節會導致項目前期bug較多,因而開發出相對穩定的軟件很慢,而開發出軟件卻很快。hibernate則正好與之相反。 但是如果使用hibernate很熟練的話,實際上開發效率絲毫不差於甚至超越mybatis。
5)sql直接優化上,mybatis要比hibernate方便很多
由於mybatis的sql都是寫在xml裏,因此優化sql比hibernate方便很多。而 hibernate的sql很多都是自動生成的,無法直接維護sql;雖有hql,但功能還是不及sql強大,見到報表等變態需求時,hql也歇菜,也就 是說hql是有侷限的;hibernate雖然也支持原生sql,但開發模式上卻與orm不同,需要轉換思維,因此使用上不是非常方便。總之寫sql的靈 活度上hibernate不及mybatis。
1、JDBC連接mysql數據庫源碼
create database test character set utf-8;
use test;
create table users{
id int(4) primary_key auto_increment,
name varchar(20),
password varchar(20)
}character set utf-8;
insert into users(id,name,password) values(1,'zhangsan','zs');
insert into users(id,name,password) values(2,'lisi','ls');
insert into users(id,name,password) values (3,'wangwu','ww');
public class jdbcConnect(){
Class.forName(com.mysql.jdbc.Driver());
String url="jdbc:mysql://localhost:3306/test";
String user="root";
String password="root";
Connection con=DriverManager.getConnection(url,user,password);
Statement statement=con.createStatement();
String sql="select * form users";
ResultSet rs=statement.executeQuery(sql);
while(rs.next()){
Integer id=rs.getInt(id);
String name=rs.getString(name);
String password=rs.getString(password);
system.out.println("id|name|password",id+"|"+name+"|"+password);
}
rs.close();
statement.close();
con.close();
}
2、mysql中字段區分大小寫嗎?
答:默認情況下不區分。可以使用show Variables like '%table_names'查看lower_case_table_names的值,0代表區分,1代表不區分。
3、分表是水平分表還是垂直分的?它們有什麼區別?
答:水評分表:一張表的數據劃分到不同的數據庫中,兩個數據庫的表結構一樣(以時間節點劃分)。
垂直分表:按照業務邏輯把存儲內容比較多的字段分到新表中,可使表存儲更多數據(以字段劃分)。
4、索引和聚合索引有什麼區別?
答:索引作用:1)創建唯一索引可以保證數據記錄的唯一性;
2)加快數據檢索速度;
3)加速表之間的鏈接;
4)在使用order by和group by子句中進行檢索數據時,可以減少查詢中排序和分組的時間;
5)使用索引可以在檢索數據時使用優化隱藏器,提高系統性能。
5、Mysql和Oacle是怎麼分頁的?
答:Mysql分頁:
select * from table_name t limit 5,10;
Oracle分頁:
Select * from (
Select A.*,Rownum RN from (
Select * from table_name
) A where Rownum <= 40
) where RN >= 21
6、函數和存儲過程有什麼區別?
答:1)函數標識符爲function,存儲過程爲procedure;
2)函數中有返回值,而存儲過程沒有返回值;
3)函數有返回值類型,調用時,除在select中,必須將返回值賦給變量;過程無返回值,不能將結果直接賦給變量;
4)函數可以在select語句中直接使用,而過程不能。
7、數據庫優化有哪些方法?
答:(1)sql層面優化;
(2)分庫分表;
(3)用view和存儲過程處理複雜邏輯
8、Mysql中索引有哪些類型?
答:普通索引(INDEX):最基本的索引,沒有任何限制
唯一索引(UNIQUE):與"普通索引"類似,不同的就是:索引列的值必須唯一,但允許有空值。
主鍵索引(PRIMARY):它是一種特殊的唯一索引,不允許有空值。
全文索引(FULLTEXT ):僅可用於 MyISAM 表, 用於在一篇文章中,檢索文本信息的, 針對較大的數據,生成全文索引很耗時好空間。
組合索引:爲了更多的提高mysql效率可建立組合索引,遵循”最左前綴“原則。
MySQL目前主要有以下幾種索引類型:FULLTEXT,HASH,BTREE,RTREE。
9、Redis和Memcached緩存原理
答:Redis運行原理:
參考http://blog.csdn.net/jinfeiteng2008/article/details/53711752
搭建redis環境:
參考http://www.cnblogs.com/liuhongfeng/p/4704443.html
使用redis參考http://www.cnblogs.com/liuhongfeng/p/5033559.html
1、單態模式
單態設計模式,又稱單例模式,是指針對某個類在程序運行期間只存在一個實例對象
// 數據產生器, 該類的實例對象負責產生數字 發號碼
// 需求 針對某個類在程序的整個運行期間只能有一個實例對象
/*
* 單態設計模式,又稱單例模式 針對某個類在程序的整個運行期間只能有一個實例對象
* 實現步驟
* 1 將類的構造方法聲明爲私有
* 2 定義一個成員變量記住該類的一個實例對象,
* 由於要被靜態方法調用,所以變量要聲明爲static
* 由於不想被外界改變,所以變量要聲明爲 private
* 3 提供共有的方法返回類的實例對象(之前定義的變量)
* 由於該類無法實例化,調用者只能通過 類名.方法名的方式來訪問,所以該方法要聲明爲 static
*/
public class NumberProcessor {
private int num = 0;
// 定義成員變量記住類的單例,不允許直接訪問
private static NumberProcessor instance = new NumberProcessor();
// 不讓外界new實例對象
private NumberProcessor() {}
// 提供一個方法 返回該類的實例對象
public static NumberProcessor getInstance() {
return instance;
}
// 發號碼
public int makeNumber() {
num++;
return num;
}
}
// 單例的實現方式二:
public class NumberProcessor {
private int num = 0;
// 定義成員變量記住類的單例,不允許外界修改變量,但可以訪問
private final static NumberProcessor INSTANCE = new NumberProcessor();
// 不讓外界new實例對象
private NumberProcessor() {}
// 發號碼
public int makeNumber() {
num++;
return num;
}
}
懶漢(飽漢)模式單例:
//懶漢式單例類.會延遲加載,在第一次調用的時候才實例化自己,線程不安全
public class Singleton {
private Singleton() {}
private static Singleton single=null;
//靜態工廠方法
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
餓漢(飢漢)模式單例:
//餓漢式單例類.在類初始化時,已經自行實例化,線程安全
public class Singleton1 {
private Singleton1() {}
private static final Singleton1 single = new Singleton1();
//靜態工廠方法
public static Singleton1 getInstance() {
return single;
}
}
靜態代理:由程序員創建或工具生成代理類的源碼,再編譯代理類。所謂靜態也就是在程序運行前就已經存在代理類的字節碼文件,代理類和委託類的關係在運行前就確定了。
動態代理:動態代理類的源碼是在程序運行期間由JVM根據反射等機制動態的生成,所以不存在代理類的字節碼文件。代理類和委託類的關係是在程序運行時確定。
2、模板方法設計模式
定義抽象父類作爲模板,其中定義模板方法(方法需要final),在模板方法中調用其他功能方法,實際上就是規定功能方法的一個執行順序,在模板類中功能方法不實現,聲明爲abstract抽象的
所有子類都針對模板類進行繼承,實現所有的功能方法,由於不能修改模板方法,所以每個子類的功能方法的調用順序都是固定的,所有的子類的功能方法調用順序要想被修改,只需修改模板方法即可
/**
* 模板方法設計模式:
* 定義抽象的父類作爲模板,在父類中定義模板方法(此方法要final,不允許子類重寫)
* 在模板方法中規定其他方法(抽象方法,留給子類實現)的調用順序,以保證整個程序的正常運行。
*
* 不同的子類繼承模板父類,實現所有的抽象方法,繼承父類的模板方法,
* 在功能調用時針對模板方法進行調用,子類實現的所有方法都會按照一種事先定義好的流程來運行
*
*/
// 打印的模板 抽象的父類 指定打印的流程
public abstract class AbstractPrint {
// 模板方法,規定了其他方法的調用順序
public final void run() {
// 開啓打印機
this.start(); // this 指向子類是對象,所以會調用子類的start方法
// 打印
this.print();
// 關閉打印機
this.close();
}
public abstract void start();
public abstract void print();
public abstract void close();
}
public class StringPrint extends AbstractPrint {
public void start() {
System.out.print("<<");
}
public void print(){
System.out.print("hello");
}
public void close(){
System.out.println(">>");
}
}
public class Demo1 {
public static void main(String[] args) {
StringPrint sp = new StringPrint();
sp.run();
}
}
3、策略模式
程序提供的功能需要依賴將來的調用者實現,在程序中只規定算法,不針對算法進行實現
可以將需要的功能定義爲接口中的方法,並對外聲明,實現方法需要傳入接口類型,此時調用者爲了調用我們的功能
必須要實現接口,創建實現類實例傳入
調用者實現接口的事情是被程序的設計者所強制的
// 數字打印機
public class NumberPrinter {
// 持有數字
private int[] arr;
public NumberPrinter(int[] arr) {
this.arr = arr;
}
public void print(NumberFilter filter) {
for(int i=0; i<arr.length; i++) {
int num = arr[i];
if(filter.accept(num)) {
System.out.print(num + ",");
}
}
}
}
public interface NumberFilter {
boolean accept(int num);
}
/**
* 設計模式之策略模式
* 在程序的功能實現過程中,我們只規定算法名稱,具體的算法留給將來的程序實現
* 在一個程序中提供的功能得以實現需要藉助調用者的幫忙,並且是強制性的,此時可以在方法的參數中定義接口,讓調用者來實現
*/
public class Demo1 {
public static void main(String[] args) {
int[] arr = {1,4,5687,34,23,456,67};
NumberPrinter np = new NumberPrinter(arr);
np.print(new NumberFilter() {
public boolean accept(int num) {
if(num>50)
return true;
return false;
}
});
}
}
1、二分算法的原理?
答:二分算法,也稱折半查找法。原理:將n個元素分成個數大致相同的兩半,取a[n/2]與預查找的x作比較,如果x=a[n/2]則找到x,算法終止;如果x< a[n/2],則我們只需要在數組a的左半部分繼續搜索x(假設數組呈升序排列);如果x> a[n/2],則只需要在數組a的右半部分查找x。
Public static int BinarySearch(int[] array,int key){
Int left=0;
Int right=array.length-1;
Int middle=0;
Whie(left<right){
Middle=(left+right)/2;
Int middlevalue=array[middle];
If(middlevalue<key){
Left=middle+1;
}else if(middlevalue>key){
Right=middle-1;
}else{
Return middle;
}
}
Return –(left+1);
}
2、冒泡排序算法原理?
答:依次比較相鄰的兩個元素,如果第一個數比第二個數大,就交換兩個數的位置。每輪比較之後,最值出現在頭角標位置。如此循環,n輪過後,就形成一個有序的數列;
public class BubbleSort{
public void sort(int[] a){
int temp = 0;
for (int x = 0;x < a.length - 1; x++){
for (int y = 0; y < a.length -x- 1;y++){
if (a[y] < a[y+1]){
temp = a[y];
a[y] = a[y+ 1];
a[y + 1] = temp;
}
}
}
}
}
3、選擇排序算法原理?
答:以一個角標上的元素爲主,依次與其他各元素進行比較,滿足條件,就交換位置。第一次循環結束後,最值出現在頭角標位置上。以此類推,再用該方式進行下一輪循環,直至形成有序數列。
public class SelectSort{
public void sort(int[] a){
int temp = 0;
for (int x = 0; x < a.length - 1; x++){
for (int y = x++; y < a.length; y++){
if (a[x] > a[y]){
temp = a[x];
a[x] = a[y];
a[y] = temp;
}
}
}
}
}
4、遞歸之奶牛問題
public class Demo2 {
/**
* 奶牛問題: 農場有一頭奶牛,從第三年開始每一年生一頭奶牛,問10年後農場中有多少頭奶牛
*
* 漢羅塔 :
*/
public static void main(String[] args) {
int year = 10;
int cowNum = getCowNum(year);
System.out.println(cowNum);
}
// 求一頭牛在指定的年份內到底能產生多少頭牛,包括自己
public static int getCowNum(int maxAge) {
int cowNum = 1;
// 計算能生多少頭牛
for(int i=3; i<=maxAge; i++) {
// 每年生一頭, 計算出生的這頭牛能產生多少牛,包括自己
cowNum += getCowNum(maxAge-i);
}
return cowNum;
}
}
package cn.itcast.demo2;
public class Demo3 {
public static void main(String[] args) {
// 面向對象解決奶牛問題
new Cow(7);
System.out.println(Cow.getCowNum());
}
}
class Cow {
private int age;
private static int cowNum; // 記住內存中 Cow 實例對象的數量,多少頭牛,該變量要靜態
private int maxAge;
public Cow(int maxAge) {
// 新創建一個 Cow 對象 相當於生了一頭牛 讓 cowNum ++
cowNum++;
this.maxAge = maxAge;
while(this.age<maxAge) {
this.grow();
}
}
public void grow() {
this.age++;
// 每長一歲就生一頭牛,前提是3歲以後
if(this.age>=3) {
new Cow(this.maxAge-this.age);
}
}
public static int getCowNum() {
return cowNum;
}
}
5、猴子運香蕉問題:一隻猴子旁邊有100根香蕉,猴子距離家50米,猴子一次頂多搬50根香蕉,但猴子每走一米就要喫掉一根香蕉。問猴子最多能拿多少根香蕉回家?
答:16根。應注意往回走時,也喫香蕉。
先拿50根,走一米放下,拿一根往回走,再取剩下的50根,與原來的放在一起,
拿 50根走一米,放下,拿一根往回走,再取剩下的47根,與原來的放在一起,
拿50根走一米,放下,拿一根往回走,再取剩下的44根,與......
每走一米喫3根,16米後喫48根,還剩52根,
直接拿50根往家走,不用回來,剩下的34米喫34根,
最後拿到家的只有16根。