題目整理
Java基礎(chǔ)進(jìn)階階段
基礎(chǔ)概念類
1.JDK1.8新特性?
2.面向?qū)ο蠛兔嫦蜻^程的區(qū)別?
3.什么是值傳遞和引用傳遞?
4.什么是不可變對象?
5.講講類的實例化順序?
6.java 創(chuàng)建對象的幾種方式
7.Java訪問修飾符的作用域
8.switch中能否使用string作為參數(shù)?
9.switch中能否作用在byte,long上?
10.什么是自動拆裝箱?
11.如何正確的退出多層嵌套循環(huán)?
繼承
1.Java支持多繼承么?
2.父類的靜態(tài)方法能否被子類重寫?
3.繼承的好處和壞處?
接口抽象類
1.接口的意義?
2.抽象類的意義?
3.抽 象 的 (abstract) 方 法 是 否 可 同 時 是 靜 態(tài) 的 (static), 是 否 可 同 時 是 本 地 方 法(native)?
4.抽象類和接口區(qū)別?
5.Java中接口可不可以繼承一般類,為什么?
6.重載與重寫區(qū)別?
7.final有哪些用法?
多態(tài)
1.多態(tài)的好處和弊端?
2.代碼中如何實現(xiàn)多態(tài)?
3.Java 中實現(xiàn)多態(tài)的機(jī)制是什么?
內(nèi)部類Lambda
1.內(nèi)部類的作用?
2.一個java文件內(nèi)部可以有類?(非內(nèi)部類)
3.Lambda的使用前提是什么?
4.Lambda與匿名內(nèi)部類區(qū)別?
static關(guān)鍵字
1.是否可以在static環(huán)境中訪問非static變量?
2.static都有哪些用法?
3.靜態(tài)變量和實例變量的區(qū)別?
4.static特點(diǎn)?
數(shù)據(jù)類型
1.String s1=”ab”, String s2=”a”+”b”, String s3=”a”, String s4=”b”, s5=s3+s4請問s5==s2返回什么?
2.3*0.1==0.3返回值是什么?
3.基本數(shù)據(jù)類型的默認(rèn)值?基本數(shù)據(jù)類型所占的字節(jié)以及封裝他們的類?
4.String屬于那個類,以及常用的方法?
5.String, StringBuffer和StringBuilder區(qū)別?
異常類
1.error和exception有什么區(qū)別?
2.運(yùn)行時異常和一般異常有何不同?
3.Java中異常處理機(jī)制的原理?
4.你平時在項目中是怎樣對異常進(jìn)行處理的?
5.throw和throws有什么區(qū)別?
6.異常處理的時候,finally代碼塊的重要性是什么?
7.請列出 5 個運(yùn)行時異常?
8.try catch finally,try里有return,finally還執(zhí)行么?
集合
1、List、Map、Set三個接口,存取元素時,各有什么特點(diǎn)?
2、ArrayList和LinkedList的底層實現(xiàn)原理?他們?yōu)槭裁淳€程不安全?在多線程并發(fā)操作下,我們應(yīng)該用什么替代?
3、HashMap和HashTable有什么區(qū)別?其底層實現(xiàn)是什么?CurrentHashMap的鎖機(jī)制又是如何?如果想將一個Map變?yōu)橛行虻?該如何實現(xiàn)?
4.什么是迭代器(Iterator)?
5.Arraylist 與 LinkedList 區(qū)別?
6.Arraylist 與 LinkedList 應(yīng)用場景?
7.Collection 和 Collections的區(qū)別?
8.為何Map接口不繼承Collection接口?
9.當(dāng)兩個對象的hashcode相同會發(fā)生什么?
10.HashMap和Hashtable有什么區(qū)別?
11.List 和 Set 區(qū)別?
12.Set和List對比?
13.當(dāng)兩個對象的hashcode相同會發(fā)生什么?
14.如果兩個鍵的hashcode相同,你如何獲取值對象?
15.有沒有可能兩個不相等的對象有相同的hashcode?
16.HashMap、LinkedHashMap、TreeMap的區(qū)別?
17.HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底層實現(xiàn)。
18.==和 equals hashCode 的區(qū)別?
19.自然排序Comparble和比較器排序Comparator的異同點(diǎn)?
泛型
1.為什么使用泛型?
2.泛型用在什么地方?
3.如何使用泛型類?
樹
1.什么是二叉樹?
2.什么是二叉查找樹?
3.什么是平衡二叉樹?
序列化
1.什么是 Java 序列化?
2.如何實現(xiàn) Java 序列化?
3.Java 序列話中,如果有些字段不想進(jìn)行序列化怎么辦?
4.對象操作流是字符流還是字節(jié)流?
5.如何在讀寫文件時指定字符集?
6.字符緩沖流特有方法?
7.為什么使用對象流?
多線程
1.什么是線程?
2.線程和進(jìn)程有什么區(qū)別?
3.如何在Java中實現(xiàn)線程?
4.用Runnable還是Thread?
5.Thread 類中的start() 和 run() 方法有什么區(qū)別?
6.Java中Runnable和Callable有什么不同?
7.Java內(nèi)存模型是什么?
8.Java中的volatile 變量是什么?
9.什么是線程安全?Vector是一個線程安全類嗎?
10.Java中如何停止一個線程?
11.Java中notify 和 notifyAll有什么區(qū)別?
12. 什么是線程池? 為什么要使用它?
13.如何寫代碼來解決生產(chǎn)者消費(fèi)者問題?
14.Java多線程中的死鎖?
15.Java中synchronized 和 ReentrantLock 有什么不同?
16.詳談Synchronized?
17.在Java中Lock接口與synchronized塊的區(qū)別是什么?
18.synchronized 的原理是什么?有什么不足?
19.關(guān)于成員變量和局部變量?
20. 如果你提交任務(wù)時,線程池隊列已滿。會時發(fā)會生什么?
21.volatile關(guān)鍵字的作用是?
22.守護(hù)線程和非守護(hù)線程有什么區(qū)別?
23.線程的生命周期?
24.wait和sleep,notify()鎖方面區(qū)別?
25.什么情況下會出現(xiàn)線程安全問題?
26.Java中規(guī)定了線程有哪幾種狀態(tài)?
27.什么是原子性?
28.Java中哪些操作是原子操作?
29.什么是CAS算法?
30.synchronized和CAS的區(qū)別?
31.并發(fā)容器Hashtable和ConcurrentHashMap特點(diǎn)?
反射
1.Java反射機(jī)制的作用?
2.什么是反射機(jī)制?
3.哪里用到反射機(jī)制?
4.反射機(jī)制的優(yōu)缺點(diǎn)?
5.反射中,Class.forName 和 ClassLoader 區(qū)別
6.什么是雙親委派模型?
7.為什么要有雙親委派模型?
8.怎么利用反射使用私有成員?
網(wǎng)絡(luò)通信
1.什么是三次握手?
2.什么是四次揮手?
3.TCP通信注意事項?
web階段
jsp相關(guān)
1.jsp內(nèi)置對象和EL內(nèi)置對象的區(qū)別與聯(lián)系?
2.說一下 jsp 的 4 種作用域?
3.ServletContext 與application的異同?
4.jsp 有哪些內(nèi)置對象?作用分別是什么?
概念相關(guān)
1.post和get區(qū)別?
2.簡單闡述相對路徑和絕對路徑?
3.Cookie和session的區(qū)別?
4.servlet四大域?qū)ο蟮膮^(qū)別?
5.什么是活化與鈍化?
6.EL內(nèi)置對象有哪些?
7.如果有大量的網(wǎng)站訪問量。那么會產(chǎn)生很多的session,該怎么解決?
8.頁面?zhèn)鬟f對象的方法?
9.session 和 application的區(qū)別?
servlet相關(guān)
1.解釋一下什么是servlet?
2.servlet的生命周期?
3.servlet生命周期方法有哪些?
4.servlet過濾器的作用?
5.servlet監(jiān)聽器的作用?
6.web.xml中組件的加載順序?
7.如何確保servlet在應(yīng)用啟動之后被加載到內(nèi)存?
8.HttpServlet為什么聲明為抽象類?
9.redirect(重定向)和forward(請求轉(zhuǎn)發(fā))區(qū)別?
10.sevlet中的屬性域有哪些?
11.Servlet是否線程安全?
12.如何創(chuàng)建線程安全的servlet?(SingleThreadModel方法不算)
13.是否有必要重寫service方法?
14.servlet包裝類有什么用?
15.在servlet中能否產(chǎn)生類似死鎖情況?
16.Servlet API中forward()與redirect()的區(qū)別?
17.ServletContext對象和ServletConfig對象的區(qū)別?
18.PrintWriter和ServletOutPutStream類有什么區(qū)別?
19.在一個servlet能否同時獲取PrintWriter和ServletOutputStream對象?
20.Request對象的主要方法有哪些?
21.jsp和servlet的異同點(diǎn)以及聯(lián)系是什么?
數(shù)據(jù)庫階段
索引相關(guān)
1.什么是索引?
2.索引是個什么樣的數(shù)據(jù)結(jié)構(gòu)呢?
3.在建立索引的時候,都有哪些需要考慮的因素呢?
4.關(guān)心過業(yè)務(wù)系統(tǒng)里面的sql耗時嗎?統(tǒng)計過慢查詢嗎?對慢查詢都怎么優(yōu)化過?
5.區(qū)別B樹,B-,B+,B*?
6.MySQL優(yōu)化策略?
7.key和index的區(qū)別?
8.怎么驗證 mysql 的索引是否滿足需求?
事務(wù)相關(guān)
1.ACID是什么?可以詳細(xì)說一下嗎?
2.同時有多個事務(wù)在進(jìn)行會怎么樣呢?
3.怎么解決這些問題呢?MySQL的事務(wù)隔離級別了解嗎?
4.Innodb使用的是哪種隔離級別呢?
5.對MySQL的鎖了解嗎?
6.MySQL都有哪些鎖呢?像上面那樣子進(jìn)行鎖定豈不是有點(diǎn)阻礙并發(fā)效率了?
7.行級鎖定的優(yōu)點(diǎn)缺點(diǎn)?
8.說一下 mysql 的行鎖和表鎖?
表設(shè)計相關(guān)
1. 為什么要盡量設(shè)定一個主鍵?
2.主鍵使用自增ID還是UUID?
3. 字段為什么要求定義為not null?
4.varchar(10)和int(10)代表什么含義?
5.建表策略?
存儲引擎相關(guān)
1. MySQL支持哪些存儲引擎?
2.InnoDB和MyISAM有什么區(qū)別?
3.什么是存儲過程?有哪些優(yōu)缺點(diǎn)?
4.說一說三個范式?
答案整理
Java基礎(chǔ)進(jìn)階階段
基礎(chǔ)概念類
1.JDK1.8新特性?
提供lambda表達(dá)式極大地減少了代碼的冗余; 在接口中可以使用default和static關(guān)鍵字來修飾接口中的普通方法; 提供新的API LocalDate | LocalTime | LocalDateTime
- Java.util.Date和SimpleDateFormatter線程上都不安全,而LocalDate和LocalTime和 String一樣都是不可改變類,線程上比較安全,還不能修改;
- Java.util.Date月份從0開始,12月是11,而java.time.LocalDate月份和星期都改成了 enum, 就不可能出錯了;
2.面向?qū)ο蠛兔嫦蜻^程的區(qū)別?
面向過程
- 優(yōu)點(diǎn):性能比面向?qū)ο蟾撸驗轭愓{(diào)用時需要實例化,開銷比較大,比較消耗資源。比如,單片機(jī)、嵌入式開發(fā)、Linux/Unix 等一般采用面向過程開發(fā),性能是最重要的因素。
- 缺點(diǎn):沒有面向?qū)ο笠拙S護(hù)、易復(fù)用、易擴(kuò)展。
面向?qū)ο?/strong>
- 優(yōu)點(diǎn):易維護(hù)、易復(fù)用、易擴(kuò)展,由于面向?qū)ο笥蟹庋b、繼承、多態(tài)性的特性,可以設(shè)計出低耦合的系統(tǒng),使系統(tǒng)更加靈活、更加易于維護(hù)。
- 缺點(diǎn):性能比面向過程低。
3.什么是值傳遞和引用傳遞?
- 值傳遞,是對基本型變量而言的,傳遞的是該變量的一個副本,改變副本不影響原變量。
- 引用傳遞,一般是對于對象型變量而言的,傳遞的是該對象地址的一個副本,并不是原對象本身。
一般認(rèn)為,Java 內(nèi)的傳遞都是值傳遞,Java 中實例對象的傳遞是引用傳遞。
4.什么是不可變對象
- 不可變對象指對象一旦被創(chuàng)建,狀態(tài)就不能再改變。任何修改都會創(chuàng)建一個新的對象,如 String、Integer及其它包裝類。
5.講講類的實例化順序?
初始化順序如下:
- 父類靜態(tài)變量
- 父類靜態(tài)代碼塊
- 子類靜態(tài)變量、
- 子類靜態(tài)代碼塊
- 父類非靜態(tài)變量(父類實例成員變量)
- 父類構(gòu)造函數(shù)
- 子類非靜態(tài)變量(子類實例成員變量)
- 子類構(gòu)造函數(shù)
6.java 創(chuàng)建對象的幾種方式
- 采用new
- 通過反射
- 采用clone
- 通過序列化機(jī)制
前2者都需要顯式地調(diào)用構(gòu)造方法。造成耦合性最高的恰好是第一種,因此你發(fā)現(xiàn)無論什么框架,只要涉及到解耦必先減少new的使用
7.Java訪問修飾符的作用域
作用域 當(dāng)前類 同包 子類 其它
- public Y Y Y Y
- protected Y Y Y N
- default Y Y N N
- private Y N N N
8.switch中能否使用string作為參數(shù)?
- 在jdk1.7之前,switch只能支持byte,short,char,int或者其他對應(yīng)的封裝類以及Enum類型.jdk1.7之后開始支持String
9.switch中能否作用在byte,long上?
10.什么是自動拆裝箱?
- 自動裝箱和拆箱,就是基本類型和引用類型之間的轉(zhuǎn)換。
- 把基本數(shù)據(jù)類型轉(zhuǎn)換成包裝類的過程就是打包裝,為裝箱。
- 把包裝類轉(zhuǎn)換成基本數(shù)據(jù)類型的過程就是拆包裝,為拆箱。
11.如何正確的退出多層嵌套循環(huán)?
使用標(biāo)號和break;
繼承
-
Java支持多繼承么?
- Java類中不支持多繼承,但是可以多實現(xiàn),所以接口的擴(kuò)展性比較好,實際開發(fā)中盡量避免繼承的使用
-
父類的靜態(tài)方法能否被子類重寫
- 不能。重寫只適用于實例方法,不能用于靜態(tài)方法,而子類當(dāng)中含有和父類相同簽名的靜態(tài)方法,我們一般稱之為隱藏。
-
繼承的好處和壞處
- 好處:
- 子類能自動繼承父類的對象 2、創(chuàng)建子類的對象時,無須創(chuàng)建父類的對象
- 壞處:
- 破壞封裝,子類與父類之間緊密耦合,子類依賴于父類的實現(xiàn),子類缺乏獨(dú)立性。
- 支持?jǐn)U展,但是往往以增強(qiáng)系統(tǒng)結(jié)構(gòu)的復(fù)雜度為代價
- 不支持動態(tài)繼承。在運(yùn)行時,子類無法選擇不同的父類
- 子類不能改變父類的接口
接口抽象類
1.接口的意義
- 規(guī)范,擴(kuò)展,回調(diào)。
2.抽象類的意義
- 為其他子類提供一個公共的類型
- 封裝子類中重復(fù)定義的內(nèi)容
- 定義抽象方法,子類雖然有不同的實現(xiàn),但是定義時一致的
3.抽 象 的 (abstract) 方 法 是 否 可 同 時 是 靜 態(tài) 的 (static), 是 否 可 同 時 是 本 地 方 法(native)
- abstract關(guān)鍵字不能同時與static或private或final同時修飾一個方法;
4.抽象類和接口區(qū)別?
-
語法區(qū)別:
-
抽象類可以有構(gòu)造方法,接口不能有構(gòu)造方法
-
抽象類中可以有普通成員變量,接口中沒有普通成員變量;
-
抽象類中可以有非抽象的方法,接口中的方法都必須是抽象的;
-
抽象類中的方法可以是public,protected類型,接口中的方法只能是public類型的,切 默認(rèn)為public abstract類型;
-
抽象類中可以有靜態(tài)方法,接口中不能有靜態(tài)方法;
-
抽象類中的靜態(tài)變量訪問類型可以是任意的,但接口中的靜態(tài)變量只能是public static final 類型。
-
.一個類可以實現(xiàn)多個接口,但一個類只能繼承一個抽象類;
-
應(yīng)用區(qū)別:
5.Java中接口可不可以繼承一般類,為什么?
不可以因為接口中只能出現(xiàn)3種成員:
-
公共的靜態(tài)常量
-
公共的抽象方法
-
靜態(tài)內(nèi)部類
而一個類中,就算什么都不寫,也必須帶一個構(gòu)造方法,在extends時就會被子類繼承,如果是接口也會 繼承這個構(gòu)造方法,很明顯構(gòu)造方法不在上面三項之列 而如果類中有一般的方法和成員變量,也會被子類全部繼承,這些更不能出現(xiàn)在接口中了,所以接口是絕 對不可能繼承一個類的
6.重載與重寫區(qū)別
override(重寫)
- 方法名、參數(shù)、返回值相同。
- 子類方法不能縮小父類方法的訪問權(quán)限。
- 子類方法不能拋出比父類方法更多的異常(但子類方法可以不拋出異常)。
- 存在于父類和子類之間。
- 被final修飾的方法,不能被重寫。
overload(重載)
- 參數(shù)類型、個數(shù)、順序至少有一個不相同。
- 不能重載只有返回值不同的方法名。
- 存在于父類和子類、同類中。
7.final有哪些用法?
- 被final修飾的類不可以被繼承
- 被final修飾的方法不可以被重寫
- 被final修飾的變量不可以被改變。如果修飾引用,那么表示引用不可變,引用指向的內(nèi)容可變。
注:修飾變量, final 數(shù)據(jù)類型 變量名=數(shù)據(jù)值; 如果該變量是基本數(shù)據(jù)類型,則值不能修改,如果該變量是引用數(shù)據(jù)類型,則地址值不能改(既只能new一次);
- 被final修飾的方法,JVM會嘗試將其內(nèi)聯(lián),以提高運(yùn)行效率
- 被final修飾的常量,在編譯階段會存入常量池中。
回答出編譯器對final域要遵守的兩個重排序規(guī)則更好:
- 在構(gòu)造函數(shù)內(nèi)對一個final域的寫入,與隨后把這個被構(gòu)造對象的引用賦值給一個引用變量,這兩個操作之間不能重排序。
- 初次讀一個包含final域的對象的引用,與隨后初次讀這個final域,這兩個操作之間不能重排序。
多態(tài)
1.多態(tài)的好處和弊端
許不同類對象對同一消息做出響應(yīng),即同一消息可以根據(jù)發(fā)送對象的不同而采用多種不同的行為方式(發(fā)送消息就是函數(shù)調(diào)用)。即父類型的引用指向子類型的對象。
- 優(yōu)點(diǎn):
- 可替換性:多態(tài)對已存在代碼具有可替換性
- 可擴(kuò)充性:增加新的子類不影響已經(jīng)存在的類結(jié)構(gòu)
- 更加靈活
- 弊端:
2.代碼中如何實現(xiàn)多態(tài)
實現(xiàn)多態(tài)主要有以下三種方式:
-
接口實現(xiàn)
-
繼承父類重寫方法
-
同一類中進(jìn)行方法重載
3.Java 中實現(xiàn)多態(tài)的機(jī)制是什么?
內(nèi)部類Lambda
1.內(nèi)部類的作用?
- 內(nèi)部類可以有多個實例,每個實例都有自己的狀態(tài)信息,并且與其他外圍對象的信息相互獨(dú)立.在單個外圍類當(dāng)中,可以讓多個內(nèi)部類以不同的方式實現(xiàn)同一接口,或者繼承同一個類.創(chuàng)建內(nèi)部類對象的時刻不依賴于外部類對象的創(chuàng)建。
- 內(nèi)部類提供了更好的封裝,除了該外圍類,其他類都不能訪問。
2.一個java文件內(nèi)部可以有類?(非內(nèi)部類)
- 只能有一個public公共類,但是可以有多個default修飾的類。
3.Lambda的使用前提是什么?
- 當(dāng)需要一個接口的實現(xiàn)類對象,且接口中有且僅有一個抽象方法的時候,可以使用lambda完成這個實現(xiàn)類要做的事情;(替代匿名內(nèi)部類)
4.Lambda與匿名內(nèi)部類區(qū)別
- lambda表達(dá)式編譯后并不會生成.class文件,而匿名內(nèi)部類編譯后會產(chǎn)生單獨(dú)的class文件;
- 匿名內(nèi)部類可以用在類,抽象類,接口中,而lambda表達(dá)式只能用在有且僅有一個抽象方法的接口中;
static關(guān)鍵字
1.是否可以在static環(huán)境中訪問非static變量?
- static變量在Java中是屬于類的,它在所有的實例中的值是一樣的。當(dāng)類被Java虛擬機(jī)載入的時候,會對static變量進(jìn)行初始化。如果你的代碼嘗試不用實例來訪問非static的變量,編譯器會報錯,因為這些變量還沒有被創(chuàng)建出來,還沒有跟任何實例關(guān)聯(lián)上。
2.static都有哪些用法?
- 被static所修飾的變量/方法都屬于類的靜態(tài)資源,類實例所共享.
- static也用于靜態(tài)塊,多用于初始化操作.
- 此外static也多用于修飾內(nèi)部類,此時稱之為靜態(tài)內(nèi)部類.
3.靜態(tài)變量和實例變量的區(qū)別?
- 靜態(tài)變量存儲在方法區(qū),屬于類所有。實例變量存儲在堆當(dāng)中,其引用存在當(dāng)前線程棧。
4.static特點(diǎn)
- 如果修飾構(gòu)造代碼塊,僅在類第一次加載的時候,執(zhí)行一次;
- 如果修飾成員變量,這個變量的值屬于類;可以被所有的對象共享;
- 如果修飾成員方法,在方法中不能使用this,super;
- 靜態(tài)的內(nèi)容優(yōu)先于對象存在!
數(shù)據(jù)類型
1.String s1=”ab”, String s2=”a”+”b”, String s3=”a”, String s4=”b”, s5=s3+s4請問s5==s2返回什么?
- 返回false。在編譯過程中,編譯器會將s2直接優(yōu)化為”ab”,會將其放置在常量池當(dāng)中,s5則是被創(chuàng)建在堆區(qū),相當(dāng)于s5=new String(“ab”);
2.3*0.1==0.3返回值是什么
- false,因為有些浮點(diǎn)數(shù)不能完全精確的表示出來
3.基本數(shù)據(jù)類型的默認(rèn)值?基本數(shù)據(jù)類型所占的字節(jié)以及封裝他們的類?
4.String屬于那個類,以及常用的方法?
5.String, StringBuffer和StringBuilder區(qū)別
- String的值是不可改變的,這就導(dǎo)致每次對String的操作都會生成新的String對象,不禁效率底下, 而且浪費(fèi)大量的內(nèi)存空間;
- StringBuilder是可變類,任何對他指向的字符串的操作都不會產(chǎn)生新的對 象,但單線程不安全;
- StringBuffer底層方法使用了synchronized關(guān)鍵字,線程比較安全,但效率 較StringBuilder慢
異常相關(guān)
1.error和exception有什么區(qū)別
- error表示系統(tǒng)級的錯誤,是java運(yùn)行環(huán)境內(nèi)部錯誤或者硬件問題,不能指望程序來處理這樣的問題,除了退出運(yùn)行外別無選擇,它是Java虛擬機(jī)拋出的。
- exception 表示程序需要捕捉、需要處理的異常,是由與程序設(shè)計的不完善而出現(xiàn)的問題,程序必須處理的問題
2.運(yùn)行時異常和一般異常有何不同
- Java提供了兩類主要的異常:runtimeException和checkedException
- 一般異常(checkedException)主要是指IO異常、SQL異常等。對于這種異常,JVM要求我們必須對其進(jìn)行cathc處理,所以,面對這種異常,不管我們是否愿意,都是要寫一大堆的catch塊去處理可能出現(xiàn)的異常。
- 運(yùn)行時異常(runtimeException)我們一般不處理,當(dāng)出現(xiàn)這類異常的時候程序會由虛擬機(jī)接管。比如,我們從來沒有去處理過NullPointerException,而且這個異常還是最常見的異常之一。
- 出現(xiàn)運(yùn)行時異常的時候,程序會將異常一直向上拋,一直拋到遇到處理代碼,如果沒有catch塊進(jìn)行處理,到了最上層,如果是多線程就有Thread.run()拋出,如果不是多線程那么就由main.run()拋出。拋出之后,如果是線程,那么該線程也就終止了,如果是主程序,那么該程序也就終止了。
- 其實運(yùn)行時異常的也是繼承自Exception,也可以用catch塊對其處理,只是我們一般不處理罷了,也就是說,如果不對運(yùn)行時異常進(jìn)行catch處理,那么結(jié)果不是線程退出就是主程序終止。
- 如果不想終止,那么我們就必須捕獲所有可能出現(xiàn)的運(yùn)行時異常。如果程序中出現(xiàn)了異常數(shù)據(jù),但是它不影響下面的程序執(zhí)行,那么我們就該在catch塊里面將異常數(shù)據(jù)舍棄,然后記錄日志。如果,它影響到了下面的程序運(yùn)行,那么還是程序退出比較好些。
3.Java中異常處理機(jī)制的原理
Java通過面向?qū)ο蟮姆绞綄Ξ惓_M(jìn)行處理,Java把異常按照不同的類型進(jìn)行分類,并提供了良好的接口。當(dāng)一個方法出現(xiàn)異常后就會拋出一個異常對象,該對象中包含有異常信息,調(diào)用這個對象的方法可以捕獲到這個異常并對異常進(jìn)行處理。Java的異常處理是通過5個關(guān)鍵詞來實現(xiàn)的:try catch throw throws finally。
一般情況下是用try來執(zhí)行一段程序,如果出現(xiàn)異常,系統(tǒng)會拋出(throws),我們可以通過它的類型來捕捉它,或最后由缺省處理器來處理它(finally)。
- try:用來指定一塊預(yù)防所有異常的程序
- catch:緊跟在try后面,用來捕獲異常
- throw:用來明確的拋出一個異常
- throws:用來標(biāo)明一個成員函數(shù)可能拋出的各種異常
- finally:確保一段代碼無論發(fā)生什么異常都會被執(zhí)行的一段代碼。
4.你平時在項目中是怎樣對異常進(jìn)行處理的。
- 盡量避免出現(xiàn)runtimeException 。例如對于可能出現(xiàn)空指針的代碼,帶使用對象之前一定要判斷一下該對象是否為空,必要的時候?qū)untimeException
也進(jìn)行try catch處理。
- 進(jìn)行try catch處理的時候要在catch代碼塊中對異常信息進(jìn)行記錄,通過調(diào)用異常類的相關(guān)方法獲取到異常的相關(guān)信息,返回到web端,不僅要給用戶良好的用戶體驗,也要能幫助程序員良好的定位異常出現(xiàn)的位置及原因。例如,以前做的一個項目,程序遇到異常頁面會顯示一個圖片告訴用戶哪些操作導(dǎo)致程序出現(xiàn)了什么異常,同時圖片上有一個按鈕用來點(diǎn)擊展示異常的詳細(xì)信息給程序員看的。
5.throw和throws有什么區(qū)別?
- throw關(guān)鍵字用來在程序中明確的拋出異常,相反,throws語句用來表明方法不能處理的異常。每一個方法都必須要指定哪些異常不能處理,所以方法的調(diào)用者才能夠確保處理可能發(fā)生的異常,多個異常是用逗號分隔的。
6.異常處理的時候,finally代碼塊的重要性是什么?
- 無論是否拋出異常,finally代碼塊總是會被執(zhí)行。就算是沒有catch語句同時又拋出異常的情況下,finally代碼塊仍然會被執(zhí)行。最后要說的是,finally代碼塊主要用來釋放資源,比如:I/O緩沖區(qū),數(shù)據(jù)庫連接。
7.請列出 5 個運(yùn)行時異常?
- NullPointerException 空指針
- IndexOutOfBoundsException 索引越界
- ClassCastException 類型轉(zhuǎn)換異常
- ArrayStoreException 當(dāng)你試圖將錯誤類型的對象存儲到一個對象數(shù)組時拋出的異常
- BufferOverflowException 寫入的長度超出了允許的長度
- IllegalArgumentException 方法的參數(shù)無效
- NoClassDefFoundException - JAVA運(yùn)行時系統(tǒng)找不到所引用的類
8.try catch finally,try里有return,finally還執(zhí)行么?**
- finally語句總會執(zhí)行即使try里包含continue,break,return,try塊結(jié)束后,finally塊也會執(zhí)行
- 如果try、catch中有return語句,finally中沒有return,那么在finally中修改除包裝類型和靜態(tài)變量、全局變量以外的數(shù)據(jù)都不會對try、catch中返回的變量有任何的影響(包裝類型、靜態(tài)變量會改變、全局變量)
- 盡量不要在finally中使用return語句,如果使用的話,會忽略try、catch中的返回語句,也會忽略try、catch中的異常,屏蔽了錯誤的發(fā)生。
- finally中避免再次拋出異常,一旦finally中發(fā)生異常,代碼執(zhí)行將會拋出finally中的異常信息,try、catch中的異常將被忽略
集合部分
1、List、Map、Set三個接口,存取元素時,各有什么特點(diǎn)?
- Set集合的add有一個boolean類型的返回值,當(dāng)集合中沒有某個元素時,則可以成功加入該 元素,返回結(jié)果為true;當(dāng)集合中存在與某個元素equals方法相等 的元素時,則無法加入該元素, 取元素時只能用Iterator接口取得所有元素,在逐一遍歷各個元素;
- List表示有先后順序的集合,調(diào)用add()方法,指定當(dāng)前對象在集合中的存放位置;一個對象可 以被反復(fù)存進(jìn)集合中;每調(diào)用一次add()方法,該對象就會被插入集合中一次,其實,并不是把對 象本身存進(jìn)了集合中,而是在集合中使用一個索引變量指向了該對象,當(dāng)一個對象被add多次時, 即有多個索引指向了這個對象。List去元素時可以使用Iterator取出所有元素,在逐一遍歷,還可 以使用get(int index)獲取指定下表的元素;
- Map是雙列元素的集合,調(diào)用put(key,value),要存儲一對key/value,不能存儲重復(fù)的key, 這個是根據(jù)eauals來判斷;取元素時用get(key)來獲取key所對 應(yīng)的value,另外還可以獲取 全部key,全部value
2、ArrayList和LinkedList的底層實現(xiàn)原理?他們?yōu)槭裁淳€程不安全?在多線程并發(fā)操作下,我們應(yīng)該用什么替代?
- ArrayList底層通過數(shù)組實現(xiàn),ArrayList允許按序號索引元素,而插入元素需要對數(shù)組進(jìn)行移位等內(nèi)存操作,所以索引快插入較慢;(擴(kuò)容方式)一旦我們實例化了ArrayList 無參構(gòu)造函數(shù)默認(rèn)數(shù)組長度為10。add方法底層如 果增加的元素超過了10個,那么ArrayList底層會生成一個新的數(shù)組,長度為原來數(shù)組長度的1.5倍+1,然后將原數(shù)組內(nèi)容復(fù)制到新數(shù)組中,并且后續(xù)加的內(nèi)容都會放到新數(shù)組中。當(dāng)新數(shù)組無法容納增加元素時,重復(fù)該過程;
- LinkedList底層通過雙向鏈表實現(xiàn),取元素時需要進(jìn)行前項或后項的遍歷,插入元素時只需要記錄本項的前后 項即可,所以插入快查詢慢;
- ArrayList和LinkedList底層方法都沒有加synchronized關(guān)鍵詞,多線程訪問時會出現(xiàn)多個線程先后更改數(shù)據(jù)造成得到的數(shù)據(jù)是臟數(shù)據(jù);多線程并發(fā)操作下使用Vector來代替,Vector底層也是數(shù)組,但底層方法都加synchronized關(guān)鍵字使線程安全,效率較ArrayList差;
3、HashMap和HashTable有什么區(qū)別?其底層實現(xiàn)是什么?CurrentHashMap的鎖機(jī)制又是如何?如果想將一個Map變?yōu)橛行虻?該如何實現(xiàn)?
- 區(qū)別:
- HashMap沒有實現(xiàn)synchronized線程非安全,HashTable實現(xiàn)了synchronized線程安全;
- HashMap允許key和value為null,而HashTable不允許
- 底層原理:數(shù)組+鏈表實現(xiàn)
- ConcurrentHashMap鎖分段技術(shù):HashTable效率低下的原因,是因為所訪問HashTable的線程都必須競爭同一把鎖,那假如容器中有多把鎖,每一把鎖用于鎖住容器中的一部分?jǐn)?shù)據(jù),那么當(dāng)多線程訪問容器中不同的數(shù)據(jù)時,線程間就不會存在鎖競爭,從而提高并發(fā)訪問率;ConcurrentHashMap使用的就是鎖分段技術(shù),首先將數(shù)據(jù)分成一段一段的存儲,然后給每一段數(shù)據(jù)配一把鎖,當(dāng)一個線程占用鎖訪問其中一個數(shù)據(jù)時,其他段的數(shù)據(jù)也能被其他線程訪問;
- 實現(xiàn)TreeMap
4.什么是迭代器(Iterator)?
- Iterator接口提供了很多對集合元素進(jìn)行迭代的方法。每一個集合類都包含了可以返回迭代器實例的迭代方法。迭代器可以在迭代的過程中刪除底層集合的元素,但是不可以直接調(diào)用集合的remove(Object Obj)刪除,可以通過迭代器的remove()方法刪除
5.Arraylist 與 LinkedList 區(qū)別
- Arraylist:
- 優(yōu)點(diǎn):ArrayList是實現(xiàn)了基于動態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu),因為地址連續(xù),一旦數(shù)據(jù)存儲好了,查詢操作效率會比較高(在內(nèi)存里是連著放的)。
- 缺點(diǎn):因為地址連續(xù), ArrayList要移動數(shù)據(jù),所以插入和刪除操作效率比較低。
- LinkedList:
- 優(yōu)點(diǎn):LinkedList基于鏈表的數(shù)據(jù)結(jié)構(gòu),地址是任意的,所以在開辟內(nèi)存空間的時候不需要等一個連續(xù)的地址,對于新增和刪除操作add和remove,LinedList比較占優(yōu)勢。LinkedList 適用于要頭尾操作或插入指定位置的場景
- 缺點(diǎn):因為LinkedList要移動指針,所以查詢操作性能比較低。
6.Arraylist 與 LinkedList 應(yīng)用場景?
- 當(dāng)需要對數(shù)據(jù)進(jìn)行對此訪問的情況下選用ArrayList,當(dāng)需要對數(shù)據(jù)進(jìn)行多次增加刪除修改時采用LinkedList。
7.Collection 和 Collections的區(qū)別
- Collection是集合類的上級接口,繼承與他的接口主要有Set 和List.Collections是針對集合類的一個幫助類,他提供一系列靜態(tài)方法實現(xiàn)對各種集合的搜索、排序、線程安全化等操作(帶s的基本都是工具類,如Arrays)
8.為何Map接口不繼承Collection接口?
- 盡管Map接口和它的實現(xiàn)也是集合框架的一部分,但Map不是集合,集合也不是Map。因此,Map繼承Collection毫無意義,反之亦然。
- 如果Map繼承Collection接口,那么元素去哪兒?Map包含key-value對,它提供抽取key或value列表集合的方法,但是它不適合“一組對象”規(guī)范。
10.HashMap和Hashtable有什么區(qū)別?
- HashMap是非線程安全的,HashTable是線程安全的。
- HashMap的鍵和值都允許有null值存在,而HashTable則不行。
- 因為線程安全的問題,HashMap效率比HashTable的要高。
- Hashtable是同步的,而HashMap不是。因此,HashMap更適合于單線程環(huán)境,而Hashtable適合于多線程環(huán)境。
一般現(xiàn)在不建議用HashTable
- 是HashTable是遺留類,內(nèi)部實現(xiàn)很多沒優(yōu)化和冗余
- 即使在多線程環(huán)境下,現(xiàn)在也有同步的ConcurrentHashMap替代,沒有必要因為是多線程而用HashTable。
11.List 和 Set 區(qū)別?
List,Set都是繼承自Collection接口
- List特點(diǎn):
- Set特點(diǎn):
- 元素?zé)o放入順序
- 元素不可重復(fù)
- 重復(fù)元素會覆蓋掉
(注意:元素雖然無放入順序,但是元素在set中的位置是有該元素的HashCode決定的,其位置其實是固定的,加入Set 的Object必須定義equals()方法 ,另外list支持for循環(huán),也就是通過下標(biāo)來遍歷,也可以用迭代器,但是set只能用迭代,因為他無序,無法用下標(biāo)來取得想要的值。)
12.Set和List對比?
- Set:檢索元素效率低下,刪除和插入效率高,插入和刪除不會引起元素位置改變。
- List:和數(shù)組類似,List可以動態(tài)增長,查找元素效率高,插入刪除元素效率低,因為會引起其他元素位置改變。
13.當(dāng)兩個對象的hashcode相同會發(fā)生什么?
- 因為hashcde相同,所以它們的bucket位置相同,'碰撞’會發(fā)生。因為HashMap使用鏈表存儲對象,這個Entry(包含有鍵值對的Map.Entry對象)會存儲在鏈表中。
14.如果兩個鍵的hashcode相同,你如何獲取值對象?
- 當(dāng)我們調(diào)用get()方法,HashMap會使用鍵對象的hashcode找到bucket位置,然后會調(diào)用keys.equals()方法去找到鏈表中正確的節(jié)點(diǎn),最終找到要找的值對象。
15.有沒有可能兩個不相等的對象有相同的hashcode?
- 有可能,(通話,重地)兩個不相等的對象可能會有相同的 hashcode 值,這就是為什么在 hashmap 中會有沖突。如果兩個對象相等,必須有相同的hashcode 值,反之不成立。
16.HashMap、LinkedHashMap、TreeMap的區(qū)別?
- HashMap是根據(jù)鍵的hashcode值存儲數(shù)據(jù),根據(jù)鍵可以直接獲取它的值,具有很快的訪問速度,取得的數(shù)據(jù)完全是隨機(jī)的
- LinkedHashMap保存了記錄的插入順序,在使用Iterator進(jìn)行遍歷的時候,先得到的肯定是先插入的數(shù)據(jù),可以在構(gòu)造時帶參數(shù),按照應(yīng)用次數(shù)來進(jìn)行排序
- TreeMap實現(xiàn)SortMap接口,能夠把它保存的記錄根據(jù)鍵排序。默認(rèn)的是升序排序,也可以指定排序的比較器,進(jìn)行遍歷的時候得到的是排序過的記錄。
17.HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底層實現(xiàn)。**
- HashMap是java數(shù)據(jù)結(jié)構(gòu)中兩大結(jié)構(gòu)數(shù)組和鏈表的組合。HashMap底層數(shù)組,數(shù)組中的每一項又是一個鏈表。程序會先根據(jù)key的hashcode()方法返回值決定該Entry在數(shù)組中的
- 存儲位置,如果該位置上沒有元素,就會將元素放置在此位置上,如果兩個Entry的key相同,會調(diào)用equals,返回值是true則覆蓋原來的value值,返回false則會形成Entry鏈,位于頭部。
- ArrrayList的底層實現(xiàn)是數(shù)組,在執(zhí)行add操作時,會先檢查數(shù)組 大小是否可以容納新的元素,如果不夠就會進(jìn)行擴(kuò)容。然后會將原來的數(shù)據(jù)拷貝到新的數(shù)組中。
- LinkedList底層是一個鏈表,其實現(xiàn)增刪改查和數(shù)據(jù)結(jié)構(gòu)中的操作完全相同,而且插入是有序的。
- LinkedHashMap的底層結(jié)構(gòu)式是雙鏈表,其他的邏輯處理與HashMap一致,同樣沒有鎖保護(hù),多線程使用時存在風(fēng)險。
- ConcurrentHashMap是segment數(shù)組結(jié)構(gòu)和HashEntry數(shù)組結(jié)構(gòu)組成的,segment在ConcurrentHashMap中充當(dāng)鎖的角色,HashEntry用于存儲鍵值對數(shù)據(jù)。segment的結(jié)構(gòu)是數(shù)組和鏈表,一個segment中有一個HashEntry,每個HashEntry是一個鏈表結(jié)構(gòu)的元素。對HashEntry中的數(shù)據(jù)進(jìn)行修改時,需要先獲得它所對應(yīng)的segment鎖。每個ConcurrentHashMap默認(rèn)有16個segment。
18.==和 equals hashCode 的區(qū)別?
- 基本數(shù)據(jù)類型: ==比較的是內(nèi)容 引用數(shù)據(jù)類型: ==比的是地址值,equals默認(rèn)比地址值,重寫按照規(guī)則比較,hashCode
19.自然排序Comparble和比較器排序Comparator的異同點(diǎn)?
相同點(diǎn):
返回值的規(guī)則:
-
如果返回值為負(fù)數(shù),表示當(dāng)前存入的元素是較小值,存左邊
-
如果返回值為0,表示當(dāng)前存入的元素跟集合中元素重復(fù)了,不存
-
如果返回值為正數(shù),表示當(dāng)前存入的元素是較大值,存右邊
不同點(diǎn):
1.用到的接口不同
-
自然排序: 自定義類實現(xiàn)Comparable接口,重寫compareTo方法,根據(jù)返回值進(jìn)行排序
-
比較器排序: 創(chuàng)建TreeSet對象的時候傳遞Comparator的實現(xiàn)類對象,重寫compare方法,根據(jù)返回值進(jìn)行排序
2.使用場景不同
-
自然排序能滿足大部分情況
-
存儲沒有修改權(quán)限的類時可以使用
20.Iterator 和 ListIterator 有什么區(qū)別?
-
Iterator可用來遍歷Set和List集合,但是ListIterator只能用來遍歷List。
-
Iterator對集合只能是前向遍歷,ListIterator既可以前向也可以后向。
-
ListIterator實現(xiàn)了Iterator接口,并包含其他的功能,比如:增加元素,替換元素,獲取前一個和后一個元素的索引,等等。
泛型
1.為什么使用泛型?
- 它提供了編譯時類型安全檢測機(jī)制,把運(yùn)行時期的問題提前到了編譯期間
- 避免了強(qiáng)制類型轉(zhuǎn)換
2.泛型用在什么地方?
3.如何使用泛型類?
- 創(chuàng)建泛型類對象時,必須要給這個泛型確定具體的數(shù)據(jù)類型
樹
1.什么是二叉樹?
- 任意節(jié)點(diǎn)的子節(jié)點(diǎn)不超過2
2.什么是二叉查找樹?
- 每個節(jié)點(diǎn)最多有兩個子節(jié)點(diǎn),左邊比當(dāng)前節(jié)點(diǎn)小,右邊比當(dāng)前節(jié)點(diǎn)大
3.什么是平衡二叉樹?
- 二叉樹左右子樹的樹高差不超過1,任意節(jié)點(diǎn)的左右子樹都是平衡二叉樹
- 通過左旋右旋保持樹的平衡
序列化
1.什么是 Java 序列化?
- 序列化就是一種用來處理對象流的機(jī)制,所謂對象流也就是將對象的內(nèi)容進(jìn)行流化。
- 可以對流化后的對象進(jìn)行讀寫操作,也可將流化后的對象傳輸于網(wǎng)絡(luò)之間。
- 序列化是為了解決在對對象流進(jìn)行讀寫操作時所引發(fā)的問題。
- 反序列化的過程,則是和序列化相反的過程。
- 另外,我們不能將序列化局限在 Java 對象轉(zhuǎn)換成二進(jìn)制數(shù)組,例如說,我們將一個 Java 對象,轉(zhuǎn)換成 JSON 字符串,或者 XML 字符串,這也可以理解為是序列化。
2.如何實現(xiàn) Java 序列化?
將需要被序列化的類,實現(xiàn) Serializable 接口,該接口沒有需要實現(xiàn)的方法,implements Serializable 只是為了標(biāo)注該對象是可被序列化的。
序列化
- 然后,使用一個輸出流(如:FileOutputStream)來構(gòu)造一個 ObjectOutputStream(對象流)對象,接著,使用 ObjectOutputStream 對象的 #writeObject(Object obj) 方法,就可以將參數(shù)為 obj 的對象寫出(即保存其狀態(tài))。
反序列化
3.Java 序列話中,如果有些字段不想進(jìn)行序列化怎么辦?
- 對于不想進(jìn)行序列化的變量,使用 transient 關(guān)鍵字修飾。
- 當(dāng)對象被序列化時,阻止實例中那些用此關(guān)鍵字修飾的的變量序列化。
- 當(dāng)對象被反序列化時,被 transient 修飾的變量值不會被持久化和恢復(fù)。
- transient 只能修飾變量,不能修飾類和方法。
4.對象操作流是字符流還是字節(jié)流?
5.如何在讀寫文件時指定字符集?
jdk11之前:
- 使用轉(zhuǎn)換流InputStreamReader(輸入轉(zhuǎn)換流)字節(jié)轉(zhuǎn)換字符橋梁/OutputStreamWriter(輸出轉(zhuǎn)換流)字符轉(zhuǎn)字節(jié)橋梁
jdk11之后
6.字符緩沖流特有方法?
- readLine():讀取一整行,到達(dá)尾處為null
- newLine():跨平臺換行
7.為什么使用對象流?
- 在開發(fā)中,經(jīng)常需要將對象的信息保存到磁盤中,如果使用前面所學(xué)的知識來實現(xiàn),會非常的繁瑣。使用對象流就非常的方便
- 對象操作流可以將對象以字節(jié)的形式寫到本地文件中,直接打開是看不懂的,需要時可以再次用對象操作流讀到內(nèi)存中
多線程
1.什么是線程?
- 線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位,它被包含在進(jìn)程之中,是進(jìn)程中的實際運(yùn)作單位。線程是進(jìn)程的一部分,是進(jìn)程中的單個控制流,是一條執(zhí)行路徑
2.線程和進(jìn)程有什么區(qū)別?
- 線程是進(jìn)程的子集,一個進(jìn)程可以有很多線程,每條線程并行執(zhí)行不同的任務(wù)。不同的進(jìn)程使用不同的內(nèi)存空間,而所有的線程共享一片相同的內(nèi)存空間。
3.如何在Java中實現(xiàn)線程?
- 繼承Thread:
- 實現(xiàn)Runnable接口:
- 實現(xiàn)Runnable接口,將實現(xiàn)類作為參數(shù)傳遞給Thread對象
- 實現(xiàn)Callable接口:
- 實現(xiàn)Callabale接口,創(chuàng)建FutureTask對象,將Callable作為參數(shù)傳遞給FutureTask對象,再將FutureTask對象傳遞給Thread類
4.用Runnable還是Thread?
Java不支持類的多重繼承,但允許你調(diào)用多個接口。所以如果你要繼承其他類,當(dāng)然是調(diào)用Runnable接口好了。
- Thread:
- Runnable,Callable:
- 擴(kuò)展性比較強(qiáng),優(yōu)先使用Runnable接口,需要執(zhí)行完有返回值可以選擇Callable接口
5.Thread 類中的start() 和 run() 方法有什么區(qū)別?
- start()方法被用來啟動新創(chuàng)建的線程,而且start()內(nèi)部調(diào)用了run()方法,這和直接調(diào)用run()方法的效果不一樣。
當(dāng)你調(diào)用run()方法的時候,只會是在原來的線程中調(diào)用,沒有新的線程啟動,start()方法才會啟動新線程。
6.Java中Runnable和Callable有什么不同?
- Runnable和Callable都代表那些要在不同的線程中執(zhí)行的任務(wù)。Runnable從JDK1.0開始就有了,Callable是在JDK1.5增加的。它們的主要區(qū)別是Callable的 call() 方法可以返回值和拋出異常,而Runnable的run()方法沒有這些功能。Callable可以返回裝載有計算結(jié)果的Future對象。
7.Java內(nèi)存模型是什么?
Java內(nèi)存模型規(guī)定和指引Java程序在不同的內(nèi)存架構(gòu)、CPU和操作系統(tǒng)間有確定性地行為。它在多線程的情況下尤其重要。Java內(nèi)存模型對一個線程所做的變動能被其它線程可見提供了保證,它們之間是先行發(fā)生關(guān)系。這個關(guān)系定義了一些規(guī)則讓程序員在并發(fā)編程時思路更清晰。比如,先行發(fā)生關(guān)系確保了:
-
線程內(nèi)的代碼能夠按先后順序執(zhí)行,這被稱為程序次序規(guī)則。
-
對于同一個鎖,一個解鎖操作一定要發(fā)生在時間上后發(fā)生的另一個鎖定操作之前,也叫做管程鎖定規(guī)則。
-
前一個對volatile的寫操作在后一個volatile的讀操作之前,也叫volatile變量規(guī)則。
-
一個線程內(nèi)的任何操作必需在這個線程的start()調(diào)用之后,也叫作線程啟動規(guī)則。
-
一個線程的所有操作都會在線程終止之前,線程終止規(guī)則。
-
一個對象的終結(jié)操作必需在這個對象構(gòu)造完成之后,也叫對象終結(jié)規(guī)則。
-
可傳遞性
8.Java中的volatile 變量是什么?
- volatile是一個特殊的修飾符,只有成員變量才能使用它。在Java并發(fā)程序缺少同步類的情況下,多線程對成員變量的操作對其它線程是透明的。volatile變量可以保證下一個讀取操作會在前一個寫操作之后發(fā)生,就是上一題的volatile變量規(guī)則。
9.什么是線程安全?Vector是一個線程安全類嗎?
- 多個線程可能會同時運(yùn)行同一段代碼。如果每次運(yùn)行結(jié)果和單線程運(yùn)行的結(jié)果是一樣的,而且其他的變量的值也和預(yù)期的是一樣的,就是線程安全的。一個線程安全的計數(shù)器類的同一個實例對象在被多個線程使用的情況下也不會出現(xiàn)計算失誤。很顯然你可以將集合類分成兩組,線程安全和非線程安全的。Vector 是用同步方法來實現(xiàn)線程安全的, 而和它相似的ArrayList不是線程安全的。
10.Java中如何停止一個線程?
- 當(dāng)run() 或者 call() 方法執(zhí)行完的時候線程會自動結(jié)束,如果要手動結(jié)束一個線程,你可以用volatile 布爾變量或設(shè)置某個變量達(dá)到一定值的時候,來退出run()方法的循環(huán)或者是取消任務(wù)來中斷線程。
11.Java中notify 和 notifyAll有什么區(qū)別?
- notify()方法不能喚醒某個具體的線程,所以只有一個線程在等待的時候它才有用武之地。
- notifyAll()喚醒所有線程并允許他們爭奪鎖確保了至少有一個線程能繼續(xù)運(yùn)行
12. 什么是線程池? 為什么要使用它?
- 創(chuàng)建線程要花費(fèi)昂貴的資源和時間,如果任務(wù)來了才創(chuàng)建線程那么響應(yīng)時間會變長,而且一個進(jìn)程能創(chuàng)建的線程數(shù)有限。為了避免這些問題,在程序啟動的時候就創(chuàng)建若干線程來響應(yīng)處理,它們被稱為線程池,里面的線程叫工作線程。從JDK1.5開始,Java API提供了Executor框架讓你可以創(chuàng)建不同的線程池。比如單線程池,每次處理一個任務(wù);數(shù)目固定的線程池或者是緩存線程池(一個適合很多生存期短的任務(wù)的程序的可擴(kuò)展線程池)
13.如何寫代碼來解決生產(chǎn)者消費(fèi)者問題?
- 在現(xiàn)實中你解決的許多線程問題都屬于生產(chǎn)者消費(fèi)者模型,就是一個線程生產(chǎn)任務(wù)供其它線程進(jìn)行消費(fèi),你必須知道怎么進(jìn)行線程間通信來解決這個問題。比較低級的辦法是用wait和notify來解決這個問題,比較贊的辦法是用Semaphore 或者 BlockingQueue來實現(xiàn)生產(chǎn)者消費(fèi)者模型
14.Java多線程中的死鎖
死鎖是指兩個或兩個以上的進(jìn)程在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法推進(jìn)下去。這是一個嚴(yán)重的問題,因為死鎖會讓你的程序掛起無法完成任務(wù),死鎖的發(fā)生必須滿足以下四個條件:
-
互斥條件:一個資源每次只能被一個進(jìn)程使用。
-
請求與保持條件:一個進(jìn)程因請求資源而阻塞時,對已獲得的資源保持不放。
-
不剝奪條件:進(jìn)程已獲得的資源,在末使用完之前,不能強(qiáng)行剝奪。
-
循環(huán)等待條件:若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。
避免死鎖最簡單的方法就是阻止循環(huán)等待條件,將系統(tǒng)中所有的資源設(shè)置標(biāo)志位、排序,規(guī)定所有的進(jìn)程申請資源必須以一定的順序(升序或降序)做操作來避免死鎖。
15.Java中synchronized 和 ReentrantLock 有什么不同?
- 這兩種方式最大區(qū)別就是對于Synchronized來說,它是java語言的關(guān)鍵字,是原生語法層面的互斥,需要jvm實現(xiàn)。而ReentrantLock它是JDK 1.5之后提供的API層面的互斥鎖,需要lock()和unlock()方法配合try/finally語句塊來完成。
16.詳談Synchronized
當(dāng)Synchronized關(guān)鍵字修飾一個方法的時候,該方法叫做同步方法:java中的每個對象都有一個鎖(lock)或者叫做監(jiān)視器(monitor),當(dāng)訪問某個對象的synchronized方法的時候,表示將對象上鎖,此時其它任何線程都無法再去訪問synchronized方法了,直到之前的那個線程執(zhí)行方法完畢后(或者是拋出了異常),那么將該對象的鎖釋放掉,其他線程才有可能再去訪問該synchronized方法。
- 注意1:
- 如果一個對象有多個synchronized方法,某一個時刻某個線程已經(jīng)進(jìn)入到了某個synchronized方法,那么在該方法沒有執(zhí)行完畢前,其它線程是無法訪問該對象的任何synchronzed方法的。
- 注意2:
- 如果某個Synchronized方法是static的,那么當(dāng)線程訪問該方法時,它鎖的并不是Synchronized方法所在的對象,而是Synchronized方法所在的對象所對象的Class對象,因為java中無論一個類有多少個對象,這些對象會對應(yīng)唯一一個class對象,因此當(dāng)線程分別訪問同一個類的兩個對象的兩個static Synchronized方法的時候,他們執(zhí)行的順序也是順序的,也就是說一個線程先去執(zhí)行方法,執(zhí)行完畢后另一個線程才開始執(zhí)行。
- 注意3:
- jdk1.6之后對synchronized(偏向鎖(根本就不加鎖)、輕量級鎖(CAS),重量級鎖(悲觀鎖))進(jìn)行了大量的優(yōu)化
17.在Java中Lock接口與synchronized塊的區(qū)別是什么?
- 用法不一樣。synchronized既可以加在方法上,也可以加載特定的代碼塊上,括號中表示需要鎖的對象。而Lock需要顯示地指定起始位置和終止位置。synchronzied是托管給jvm執(zhí)行的,Lock鎖定是通過代碼實現(xiàn)的。
- 在性能上來說,如果競爭資源不激烈,兩者的性能是差不多的,而當(dāng)競爭資源非常激烈時(即有大量線程同時競爭),此時Lock的性能要遠(yuǎn)遠(yuǎn)優(yōu)于synchronized。所以說,在具體使用時要根據(jù)適當(dāng)情況選擇。
- 鎖的機(jī)制不一樣。synchronized獲得鎖和釋放的方式都是在塊結(jié)構(gòu)中,而且是自動釋放鎖。而Lock則需要開發(fā)人員手動去釋放,并且必須在finally塊中釋放,否則會引起死鎖問題的發(fā)生。
- Lock是一個接口,而synchronized是Java中的關(guān)鍵字,synchronized是內(nèi)置的語言實現(xiàn);
- synchronized在發(fā)生異常時,會自動釋放線程占有的鎖,因此不會導(dǎo)致死鎖現(xiàn)象發(fā)生;而Lock在發(fā)生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現(xiàn)象,因此使用Lock時需要在finally塊中釋放鎖
18.synchronized 的原理是什么?有什么不足?
- 原理:
- synchronized是 Java 內(nèi)置的關(guān)鍵字,它提供了一種獨(dú)占的加鎖方式。
- synchronized的獲取和釋放鎖由JVM實現(xiàn),用戶不需要顯示的釋放鎖,非常方便。
- 不足:
- 當(dāng)線程嘗試獲取鎖的時候,如果獲取不到鎖會一直阻塞。
- 如果獲取鎖的線程進(jìn)入休眠或者阻塞,除非當(dāng)前線程異常,否則其他線程嘗試獲取鎖必須一直等待。
19.關(guān)于成員變量和局部變量
- 如果一個變量是成員變量,那么多個線程對同一個對象的成員變量進(jìn)行操作的時候,他們對該成員變量是彼此影響的,也就是說一個線程對成員變量的改變會影響到另外一個線程;如果一個變量是局部變量,那么每個線程都會有一個該局部變量的拷貝,一個線程對該局部變量的改變不會影響到其它的線程。
20. 如果你提交任務(wù)時,線程池隊列已滿。會時發(fā)會生什么?
- 如果一個任務(wù)不能被調(diào)度執(zhí)行那么ThreadPoolExecutor’s submit()方法將會拋出一個RejectedExecutionException異常。
21.volatile關(guān)鍵字的作用是?
- 保證變量的可見性。
- 在java內(nèi)存結(jié)構(gòu)中,每個線程都是有自己獨(dú)立的內(nèi)存空間(此處指的線程棧)。當(dāng)需要對一個共享變量操作時,線程會將這個數(shù)據(jù)從主存空間復(fù)制到自己的獨(dú)立空間內(nèi)進(jìn)行操作,然后在某個時刻將修改后的值刷新到主存空間。這個中間時間就會發(fā)生許多奇奇怪怪的線程安全問題了,volatile就出來了,它保證讀取數(shù)據(jù)時只從主存空間讀取,修改數(shù)據(jù)直接修改到主存空間中去,這樣就保證了這個變量對多個操作線程的可見性了。換句話說,被volatile修飾的變量,能保證該變量的 單次讀或者單次寫 操作是原子的。
- 但是線程安全是兩方面需要的 原子性(指的是多條操作)和可見性。volatile只能保證可見性,synchronized是兩個均保證的。
- volatile輕量級,只能修飾變量;synchronized重量級,還可修飾方法。
- volatile不會造成線程的阻塞,而synchronized可能會造成線程的阻塞。
22.守護(hù)線程和非守護(hù)線程有什么區(qū)別?
- 程序運(yùn)行完畢,JVM 會等待非守護(hù)線程完成后關(guān)閉,但是 JVM 不會等待守護(hù)線程
23.線程的生命周期?
線程的生命周期包含5個階段,包括:新建、就緒、運(yùn)行、阻塞、銷毀。
-
新建:就是剛使用new方法,new出來的線程;
-
就緒:就是調(diào)用的線程的start()方法后,這時候線程處于等待CPU分配資源階段,誰先搶的CPU資源,誰開始執(zhí)行;
-
運(yùn)行:當(dāng)就緒的線程被調(diào)度并獲得CPU資源時,便進(jìn)入運(yùn)行狀態(tài),run方法定義了線程的操作和功能;
-
阻塞:在運(yùn)行狀態(tài)的時候,可能因為某些原因?qū)е逻\(yùn)行狀態(tài)的線程變成了阻塞狀態(tài),比如sleep()、wait()之后線程就處于了阻塞狀態(tài),這個時候需要其他機(jī)制將處于阻塞狀態(tài)的線程喚醒,比如調(diào)用notify或者notifyAll()方法。喚醒的線程不會立刻執(zhí)行run方法,它們要再次等待CPU分配資源進(jìn)入運(yùn)行狀態(tài);
-
銷毀:如果線程正常執(zhí)行完畢后或線程被提前強(qiáng)制性的終止或出現(xiàn)異常導(dǎo)致結(jié)束,那么線程就要被銷毀,釋放資源;
24.wait和sleep,notify()鎖方面區(qū)別?
- wait:讓線程等待,同時立即釋放鎖
- sleep():讓線程休眠,但是不會釋放鎖
- notify()或notifyAll(): 喚醒等待的線程,但是不會立即釋放鎖
25.什么情況下會出現(xiàn)線程安全問題?
- 多線程環(huán)境
- 有共享數(shù)據(jù)
- 有對共享數(shù)據(jù)的操作
26.Java中規(guī)定了線程有哪幾種狀態(tài)?
27.什么是原子性?
- 所謂的原子性就是完成功能的所有操作要么都執(zhí)行,要么都不執(zhí)行
28.Java中哪些操作是原子操作?
- 除了long和double之外的所有原始類型的賦值
- 所有volatile變量的賦值
- java.concurrent.Atomic *類的所有操作
29.什么是CAS算法?
- 當(dāng)預(yù)期值E==主內(nèi)存中的值V,此時可以進(jìn)行修改,將V改成新值
- 當(dāng)預(yù)期值E!=主內(nèi)存中的值V時,將主內(nèi)存中的已經(jīng)改變的值更新到自己的工作內(nèi)存中,再次嘗試比較,直到預(yù)期值E等于主內(nèi)存中的值V,才可以修改。這個過程稱為自旋
30.synchronized和CAS的區(qū)別?
- 相同點(diǎn):
- 在多線程情況下,都可以保證共享數(shù)據(jù)的安全性。
- 不同點(diǎn):
- synchronized總是從最壞的角度出發(fā),認(rèn)為每次獲取數(shù)據(jù)的時候,別人都有可能修改。所以在每 次操作共享數(shù)據(jù)之前,都會上鎖。(悲觀鎖)
- CAS是從樂觀的角度出發(fā),假設(shè)每次獲取數(shù)據(jù)別人都不會修改,所以不會上鎖。只不過在修改共享數(shù)據(jù)的時候,會檢查一下,別人有沒有修改過這個數(shù)據(jù)。如果別人修改過,那么我再次獲取現(xiàn)在最新的值。如果別人沒有修改過,那么我現(xiàn)在直接修改共享數(shù)據(jù)的值.(樂觀鎖)
31.并發(fā)容器Hashtable和ConcurrentHashMap特點(diǎn)?
- Hashtable:
- ConcurrentHashMap:
反射類加載器
1.Java反射機(jī)制的作用?
- 在運(yùn)行時判斷任意一個對象所屬的類。
- 在運(yùn)行時判斷任意一個類所具有的成員變量和方法。
- 在運(yùn)行時任意調(diào)用一個對象的方法
- 在運(yùn)行時構(gòu)造任意一個類的對象
2.什么是反射機(jī)制?
- 簡單說,反射機(jī)制值得是程序在運(yùn)行時能夠獲取自身的信息。在java中,只要給定類的名字,那么就可以通過反射機(jī)制來獲得類的所有信息。
3.哪里用到反射機(jī)制?
- Spring 框架的 IoC 基于反射創(chuàng)建對象和設(shè)置依賴屬性。
- Spring MVC 的請求調(diào)用對應(yīng)方法,也是通過反射。
- JDBC 的 Class#forName(String className) 方法,也是使用反射。
4.反射機(jī)制的優(yōu)缺點(diǎn)?
- 靜態(tài)編譯:
- 動態(tài)編譯:
- 運(yùn)行時確定類型,綁定對象。動態(tài)編譯最大限度的發(fā)揮了java的靈活性,體現(xiàn)了多態(tài)的應(yīng)用,有利于降低類之間的耦合性。一句話,反射機(jī)制的優(yōu)點(diǎn)就是可以實現(xiàn)動態(tài)創(chuàng)建對象和編譯,體現(xiàn)出很大的靈活性,特別是在J2EE的開發(fā)中它的靈活性就表現(xiàn)的十分明顯。比如,一個大型的軟件,不可能一次就把把它設(shè)計的很完美,當(dāng)這個程序編譯后,發(fā)布了,當(dāng)發(fā)現(xiàn)需要更新某些功能時,我們不可能要用戶把以前的卸載,再重新安裝新的版本,假如這樣的話,這個軟件肯定是沒有多少人用的。采用靜態(tài)的話,需要把整個程序重新編譯一次才可以實現(xiàn)功能的更新,而采用反射機(jī)制的話,它就可以不用卸載,只需要在運(yùn)行時才動態(tài)的創(chuàng)建和編譯,就可以實現(xiàn)該功能。它的缺點(diǎn)是對性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它滿足我們的要求。這類操作總是慢于只直接執(zhí)行相同的操作
5.反射中,Class.forName 和 ClassLoader 區(qū)別
- java中class.forName()和classLoader都可用來對類進(jìn)行加載。
- class.forName()前者除了將類的.class文件加載到j(luò)vm中之外,還會對類進(jìn)行解釋,執(zhí)行類中的static塊。
- 而classLoader只干一件事情,就是將.class文件加載到j(luò)vm中,不會執(zhí)行static中的內(nèi)容,只有在newInstance才會去執(zhí)行static塊。
6.什么是雙親委派模型?
- 如果一個類加載器收到了類加載請求,它并不會自己先去加載,而是把這個請求委托給父類的加載器去執(zhí)行,如果父類加載器還存在其父類加載器,則進(jìn)一步向上委托,依次遞歸,請求最終將到達(dá)頂層的啟動類加載器,如果父類加載器可以完成類加載任務(wù),就成功返回,倘若父類加載器無法完成此加載任務(wù),子加載器才會嘗試自己去加載,這就是雙親委派模式
7.為什么要有雙親委派模型?
- 為了保證類的全局唯一性,如果自定義類與Java核心類庫中的類重名了,會被編譯但不會不執(zhí)行
8.怎么利用反射使用私有成員?
- setAccessible(boolean flag)
網(wǎng)絡(luò)通信
1.什么是三次握手?
2.什么是四次揮手?
-
客戶端向服務(wù)器發(fā)出取消連接請求
-
服務(wù)器向客戶端返回一個響應(yīng),表示收到客戶端取消請求
-
服務(wù)器向客戶端發(fā)出確認(rèn)信息
-
客戶端再次發(fā)送確認(rèn)信息,連接取消
3.TCP通信注意事項?
-
accept方法是阻塞的,作用就是等待客戶端連接
-
客戶端創(chuàng)建對象并連接服務(wù)器,此時是通過三次握手協(xié)議,保證跟服務(wù)器之間的連接
-
針對客戶端來講,是往外寫的,所以是輸出流 針對服務(wù)器來講,是往里讀的,所以是輸入流
-
read方法也是阻塞的
-
客戶端在關(guān)流的時候,還多了一個往服務(wù)器寫結(jié)束標(biāo)記的動作
-
最后一步斷開連接,通過四次揮手協(xié)議保證連接終止
web階段
jsp相關(guān)
1.jsp內(nèi)置對象和EL內(nèi)置對象的區(qū)別與聯(lián)系
jsp內(nèi)置對象:
EL表達(dá)式內(nèi)置對象:
pageContext對象是二者唯一相同的對象,其他都是各自獨(dú)立的對象
2.說一下 jsp 的 4 種作用域?
JSP中的四種作用域包括page、request、session和application,具體來說:
-
page代表與一個頁面相關(guān)的對象和屬性。
-
request代表與Web客戶機(jī)發(fā)出的一個請求相關(guān)的對象和屬性。一個請求可能跨越多個頁面,涉及多個Web組件;需要在頁面顯示的臨時數(shù)據(jù)可以置于此作用域。
-
session代表與某個用戶與服務(wù)器建立的一次會話相關(guān)的對象和屬性。跟某個用戶相關(guān)的數(shù)據(jù)應(yīng)該放在用戶自己的session中。
-
application代表與整個Web應(yīng)用程序相關(guān)的對象和屬性,它實質(zhì)上是跨越整個Web應(yīng)用程序,包括多個頁面、請求和會話的一個全局作用域。
3.ServletContext 與application的異同
- 相同:
- 其實servletContext和application 是一樣的,就相當(dāng)于一個類創(chuàng)建了兩個不同名稱的變量。在 servlet中ServletContext就是application對象。大家只要打開jsp編譯過后生成的Servlet中 jspService()方法就可以看到如下的聲明: ServletContextapplication = null;application= pageContext.getServletContext();
- 不同:
- 兩者的區(qū)別就是application用在jsp中,servletContext用在servlet中。application和page requestsession 都是JSP中的內(nèi)置對象,在后臺用ServletContext存儲的屬性數(shù)據(jù)可以用 application對象獲得。 而且application的作用域是整個Tomcat啟動的過程。 例如:ServletContext.setAttribute("username",username); 則在JSP網(wǎng)頁中可以使用 application.getAttribute("username"); 來得到這個用戶名。
4.jsp 有哪些內(nèi)置對象?作用分別是什么?
JSP有9個內(nèi)置對象:
-
request:封裝客戶端的請求,其中包含來自GET或POST請求的參數(shù);
-
response:封裝服務(wù)器對客戶端的響應(yīng);
-
pageContext:通過該對象可以獲取其他對象;
-
session:封裝用戶會話的對象;
-
application:封裝服務(wù)器運(yùn)行環(huán)境的對象;
-
out:輸出服務(wù)器響應(yīng)的輸出流對象;
-
config:Web應(yīng)用的配置對象;
-
page:JSP頁面本身(相當(dāng)于Java程序中的this);
-
exception:封裝頁面拋出異常的對象。
概念相關(guān)
1.post和get區(qū)別?
-
-
get:
-
數(shù)據(jù)顯示在地址欄
-
不安全
-
get方式提交有大小限制(約4kb)
2.相對路徑和絕對路徑?
-
相對路徑
概念:
寫法:
-
絕對路徑
概念:
寫法:
3.Cookie和session的區(qū)別?
session是基于cookie
多次請求之間共享數(shù)據(jù)
- cookie:
-
數(shù)據(jù)存儲于客戶端--不安全
-
只能存字符串
-
大小有限制
- session:
4.servlet四大域?qū)ο蟮膮^(qū)別?
-
pageContext:當(dāng)前jsp頁面內(nèi)共享數(shù)據(jù)
-
request:一次請求內(nèi)共享數(shù)據(jù),例如:請求轉(zhuǎn)發(fā)和包含都是一次請求,可以使用request傳遞數(shù)據(jù)
-
session:一次會話范圍內(nèi)共享數(shù)據(jù)
-
servletContext:整個應(yīng)用共享數(shù)據(jù)

5.什么是活化與鈍化?
服務(wù)器自動完成(注意使用本地Tomcat才行)
6.EL內(nèi)置對象有哪些?

注意:EL 表達(dá)式內(nèi)置對象和,JSP 內(nèi)置對象不是一回事,el表達(dá)式中想要使用jsp 中的對象需要使用pageContext 獲取
7.如果有大量的網(wǎng)站訪問量。那么會產(chǎn)生很多的session,該怎么解決?
session默認(rèn)保存在內(nèi)存中,內(nèi)存資源寶貴,session數(shù)據(jù)量大導(dǎo)致內(nèi)存利用率高,以下方案解決session內(nèi)存存儲問題:
- 可以設(shè)置session超時時間,達(dá)到超時時間session自動清空
<session-config>
<session-timeout>20</session-timeout>
</session-config>
- 將session中的數(shù)據(jù)序列化到硬盤中
- 不使用session,使用cookie(此方法存在安全性問題)
8.頁面?zhèn)鬟f對象的方法?
- Request、session、application、cookie等
9.session 和 application的區(qū)別?
- 兩者的作用范圍不同:
- Session對象是用戶級的,而Application是應(yīng)用程序級別的
- 一個用戶一個session對象,每個用戶的session對象不同,在用戶所訪問的網(wǎng)站多個頁面之間共享同一個session對象
- 一個Web應(yīng)用程序一個application對象,每個Web應(yīng)用程序的application對象不同,但一個Web應(yīng)用程序的多個用戶之間共享同一個application對象。
- 兩者的生命周期不同:
- session對象的生命周期:用戶首次訪問網(wǎng)站創(chuàng)建,用戶離開該網(wǎng)站 (不一定要關(guān)閉瀏覽器) 消亡。
- application對象的生命周期:啟動Web服務(wù)器創(chuàng)建,關(guān)閉Web服務(wù)器銷毀。
Servlet相關(guān)
1.解釋一下什么是servlet
- Servlet有良好的生存期的定義,包括加載和實例化、初始化、處理請求以及服務(wù)結(jié)束。這個生存期由javax.servlet.Servlet 接口的init,service 和destroy方法表達(dá)。
- Web容器加載Servlet,Servlet被服務(wù)器實例化后,生命周期開始。通過調(diào)用servlet的init()方法進(jìn)行servlet的初始化。通過調(diào)用service()方法實現(xiàn),根據(jù)請求的不同調(diào)用不同的doXXX方法(doGet,doPost)方法。結(jié)束服務(wù),web容器調(diào)用servlet的destroy()方法。
2.servlet的生命周期?
servlet容器負(fù)責(zé)管理servlet的生命周期,servlet生命周期如下:
- 加載和實例化 Servlet 容器裝載和實例化一個 Servlet。創(chuàng)建出該 Servlet 類的一個實例。
- 初始化 在 Servlet 實例化完成之后,容器負(fù)責(zé)調(diào)用該 Servlet 實例的 init() 方法,在處理用戶請求之前,來做一些額外的初始化工作。
- 處理請求 當(dāng) Servlet 容器接收到一個 Servlet 請求時,便運(yùn)行與之對應(yīng)的 Servlet 實例的 service() 方法,service() 方法再派遣運(yùn)行與請求相對應(yīng)的 doXX(doGet,doPost) 方法來處理用戶請求。
- 銷毀 當(dāng) Servlet 容器決定將一個 Servlet 從服務(wù)器中移除時 ( 如 Servlet 文件被更新 ),便調(diào)用該 Servlet 實例的 destroy() 方法,在銷毀該 Servlet 實例之前, 來做一些其他的工作。
加載實例化,初始化,銷毀,在整個生命周期中只會執(zhí)行一次
補(bǔ)充:
3.servlet生命周期方法有哪些?
共有3個方法:
- public void init(ServletConfig config):
- 這個方法是由servlet容器調(diào)用用來初始化servlet的,這個方法在servlet生命周期中僅被調(diào)用一次。
- public void service(ServletRequest request, ServletResponse response):
- servlet容器為每個客戶端創(chuàng)建線程,然后都會執(zhí)行service方法,但執(zhí)行此方法前init方法必須已經(jīng)被執(zhí)行了。
- public void destroy():
- servlet從servlet容器中被移除時會調(diào)用此方法,僅被調(diào)用一次。
4.servlet過濾器的作用?
- 打印一些請求參數(shù)到日志中
- 授權(quán)請求訪問資源
- 在將請求提交給servlet之前,對request請求頭或請求體進(jìn)行一些格式化的處理
- 將響應(yīng)數(shù)據(jù)進(jìn)行壓縮再返回給瀏覽器。
- 解決亂碼問題。
5.servlet監(jiān)聽器的作用?
- 監(jiān)聽客戶端的請求,服務(wù)器端的操作等 。通過監(jiān)聽器,可以自動激發(fā)一些操作,比如監(jiān)聽在線的用戶數(shù)量( 當(dāng)增加一個HttpSession時,就自動觸發(fā)sessionCreated(HttpSessionEvent se)方法,在這個方法中就可以統(tǒng)計在線人數(shù)了 ),另外還可以用來初始化一些資源,比如數(shù)據(jù)庫連接池等(web.xml中配置的context-param只能是字符串不能使對象,這時就得使用ServletContextListener了,注意,有讀者可能說ServletConext的setAttribute不是可以設(shè)置對象嗎?但是這是在servlet創(chuàng)建之后才能調(diào)用的方法,如果希望web應(yīng)用一啟動就產(chǎn)生初始參數(shù)必須使用監(jiān)聽器)。
6.web.xml中組件的加載順序?
- context-param -> listener -> filter -> servlet
- 而同個類型之間的實際程序調(diào)用的時候的順序是根據(jù)對應(yīng)的 mapping 的順序進(jìn)行調(diào)用的
7.如何確保servlet在應(yīng)用啟動之后被加載到內(nèi)存?
- 通常情況下都是客戶端請求一個servlet,這個servlet才會被加載到內(nèi)存,但對于某些很大加載很耗時的servlet我們希望應(yīng)用啟動時就加載它們,這時我們可以在web.xml文件中配置或者使用webServlet注解(servlet3.0)告訴容器系統(tǒng)一啟動就加載:
<servlet> <servlet-name>foo</servlet-name> <servlet-class>com.foo.servlets.Foo</servlet-class> <load-on-startup>5</load-on-startup> </servlet>
- load-on-startup節(jié)點(diǎn)中必須配置一個整數(shù),整數(shù)代表應(yīng)用一啟動就會被加載,負(fù)數(shù)表示當(dāng)客戶端請求之后才加載,正數(shù)的值越小,說明越先被加載。
8.HttpServlet為什么聲明為抽象類?
- httpServlet類雖然是抽象類但卻沒有抽象方法,之所以這樣設(shè)計,是因為doget,dopost等方法并沒有業(yè)務(wù)邏輯,開發(fā)者至少應(yīng)該重寫一個service中的方法,這就是我們不能實例化HttpServlet的原因。
9.redirect(重定向)和forward(請求轉(zhuǎn)發(fā))區(qū)別?
重定向:
轉(zhuǎn)發(fā):
補(bǔ)充:
servlet中怎么定義forward 和redirect?
- 轉(zhuǎn)發(fā):request.getRequestDispatcher (“demo.jsp"). forward(request, response);
- 重定向:response.sendRedirect(“demo.jsp");
10.sevlet中的屬性域有哪些?
servlet提供了一些域?qū)ο蠓奖銉?nèi)部servlet之間的通信,我們可以通過set/get方法為web應(yīng)用設(shè)置或取出屬性值。servlet提供3個域(和jsp區(qū)分開來):
- request scope
- session scope
- application scope
分別由ServletRequest,HttpSession,ServletContext對象提供對應(yīng)的set/get/remove方法去操作者三個域。
注:這跟web.xml中為servletConfig(針對單個servlet)和servletContext(針對web應(yīng)用)定義的初始化參數(shù)不一樣。
11.Servlet是否線程安全?
- HttpServlet的init和destroy方法在servlet聲明周期中僅 調(diào)用一次,所以不用擔(dān)心它們的線程安全。但是service方法以及doget,dopost等方法是存在線程安全問題的,因為servlet容器為每一個客戶端請求都創(chuàng)建一個線程,這些線程在同一時刻可能訪問同一個servlet的service方法,所以我們在使用這些方法時務(wù)必小心。
12.如何創(chuàng)建線程安全的servlet?(SingleThreadModel方法不算)
- 盡量使用局部變量,減少全局變量的使用。
- 對于共享變量,加上關(guān)鍵字synchronized。
注:servlet中常見線程安全與不安全的對象
- 線程安全:ServletRequest,ServletResponse
- 線程不安全:ServletContext,HttpSession。
對于 ServletContext,我們應(yīng)盡量減少該對象中屬性的修改。
而HttpSession對象在用戶會話期間存在,只能在處理屬于同一個Session的請求的線程中被訪問,因此Session對象的屬性訪問理論上是線程安全的。但是當(dāng)用戶打開多個同屬于一個進(jìn)程的瀏覽器窗口,在這些窗口的訪問屬于同一個Session,會出現(xiàn)多次請求,需要多個工作線程來處理請求,可能造成同時多線程讀寫屬性
13.是否有必要重寫service方法?
- 一般情況下是沒有必要的,因為service方法會根據(jù)請求的類型(get、post等)將請求分發(fā)給doxxx方法去執(zhí)行。即使我們需要在處理請求之前需要做一些額外的事,我們也可以通過過濾器或監(jiān)聽器完成。
14.servlet包裝類有什么用?
- servletAPI提供了兩個包裝類:HttpServletRequestWrapper類和HttpServletResponseWrapper類,這些包裝類幫助開發(fā)者給出request和response的一般實現(xiàn)。我們可以繼承它們并選擇我們需要復(fù)寫的方法進(jìn)行復(fù)寫(包裝設(shè)計模式),而不用復(fù)寫所有的方法。
15.在servlet中能否產(chǎn)生類似死鎖情況?
- 可以的,你在doPost方法中調(diào)用doGet方法,在doGet方法中調(diào)用doPost方法,將產(chǎn)生死鎖(最終會拋出stackoverflow異常)。
16.Servlet API中forward()與redirect()的區(qū)別?
- forward 是服務(wù)器轉(zhuǎn)發(fā),一次請求和響應(yīng),瀏覽器地址欄不會顯示出轉(zhuǎn)發(fā)后的地址;forward比較高效,而且有助于隱藏實際地址。
- eg: getServletContext().getRequest Dispatcher(“/servlet/secondservlet”).forward(request, response);
- redirect 是重定向,兩次請求和響應(yīng),瀏覽器會得到跳轉(zhuǎn)地址,對新地址重新發(fā)送請求。
17.ServletContext對象和ServletConfig對象的區(qū)別?
- 每個servlet都會有自己獨(dú)有的servletConfig對象而servletContext對象是整個web應(yīng)用共享的。
- servletConfig提供servlet的初始化參數(shù)(init-param),僅該servlet可以訪問。而servletContext提供的初始化參數(shù)整個web應(yīng)用的所有servlet都可以訪問。
- servletContext對象提供了setAttribute方法設(shè)置共享參數(shù),而servletConfig并沒有對應(yīng)的set方法。
18.PrintWriter和ServletOutPutStream類有什么區(qū)別?
- PrintWriter是字符流,ServletOutputStream是字節(jié)流??梢酝ㄟ^ PrintWriter向瀏覽器輸出字符數(shù)組或者是字符串。也可以通過ServletOutPutStream向瀏覽器端輸出字節(jié)數(shù)組。
- PrintWriter對象在servlet中可以通過response.getWriter()方法獲取
- ServletOutputStream對象通過response.getOutputStream方法獲取。
19.在一個servlet能否同時獲取PrintWriter和ServletOutputStream對象?
- 不可以,如果同時獲取,將會拋出java.lang.IllegalStateException異常。
20.Request對象的主要方法有哪些?
- setAttribute(String name,Object):設(shè)置名字為name的request 的參數(shù)值
- getAttribute(String name):返回由name指定的屬性值
- getAttributeNames():返回request對象所有屬性的名字集合,結(jié)果是一個枚舉的實例
- getCookies():返回客戶端的所有Cookie對象,結(jié)果是一個Cookie數(shù)組
- getCharacterEncoding():返回請求中的字符編碼方式
- getContentLength():返回請求的Body的長度
- getHeader(String name):獲得HTTP協(xié)議定義的文件頭信息
- getHeaders(String name):返回指定名字的request Header的所有值,結(jié)果是一個枚舉的實例
- getHeaderNames():返回所以request Header的名字,結(jié)果是一個枚舉的實例
- getInputStream():返回請求的輸入流,用于獲得請求中的數(shù)據(jù)
- getMethod():獲得客戶端向服務(wù)器端傳送數(shù)據(jù)的方法
- getParameter(String name):獲得客戶端傳送給服務(wù)器端的有name指定的參數(shù)值
- getParameterNames():獲得客戶端傳送給服務(wù)器端的所有參數(shù)的名字,結(jié)果是一個枚舉的實例
- getParametervalues(String name):獲得有name指定的參數(shù)的所有值
- getProtocol():獲取客戶端向服務(wù)器端傳送數(shù)據(jù)所依據(jù)的協(xié)議名稱
- getQueryString():獲得查詢字符串
- getRequestURI():獲取發(fā)出請求字符串的客戶端地址
- getRemoteAddr():獲取客戶端的IP 地址
- getRemoteHost():獲取客戶端的名字
- getSession([Boolean create]):返回和請求相關(guān)Session
- getServerName():獲取服務(wù)器的名字
- getServletPath():獲取客戶端所請求的腳本文件的路徑
- getServerPort():獲取服務(wù)器的端口號
- removeAttribute(String name):刪除請求中的一個屬性
21.jsp和servlet的異同點(diǎn)以及聯(lián)系是什么?
-
jsp經(jīng)編譯后就變成了servlet(jsp本質(zhì)就是servlet,jvm只能識別java的類,不能識別jsp代碼,web容器將jsp的代碼編譯成jvm能夠識別的java類)
-
jsp更擅長表現(xiàn)于頁面顯示,servlet更擅長于邏輯控制
-
setvlet中沒有內(nèi)置對象,jsp中的內(nèi)置對象都是必須通過HttpServletRequest對象,HttpServletResponse對象及HttpServlet對象得到
-
jsp是servlet的一種簡化,使用jsp只需要完成程序員需用輸出到客戶端的內(nèi)容,jsp中的java腳本如何鑲嵌到一個類中,由jsp容器完成,而servlet則是個完整的java類,這個類的service方法用于生成對客戶端的響應(yīng)
數(shù)據(jù)庫階段
索引相關(guān)
1.什么是索引?
- 索引是一種數(shù)據(jù)結(jié)構(gòu),可以幫助我們快速的進(jìn)行數(shù)據(jù)的查找
2.索引是個什么樣的數(shù)據(jù)結(jié)構(gòu)呢?
- 索引的數(shù)據(jù)結(jié)構(gòu)和具體存儲引擎的實現(xiàn)有關(guān), 在MySQL中使用較多的索引有Hash索引,B+樹索引等,而我們經(jīng)常使用的InnoDB存儲引擎的默認(rèn)索引實現(xiàn)為:B+樹索引.
3.在建立索引的時候,都有哪些需要考慮的因素呢?
- 建立索引的時候一般要考慮到字段的使用頻率,經(jīng)常作為條件進(jìn)行查詢的字段比較適合.如果需要建立聯(lián)合索引的話,還需要考慮聯(lián)合索引中的順序.此外也要考慮其他方面,比如防止過多的所有對表造成太大的壓力.這些都和實際的表結(jié)構(gòu)以及查詢方式有關(guān).
4.關(guān)心過業(yè)務(wù)系統(tǒng)里面的sql耗時嗎?統(tǒng)計過慢查詢嗎?對慢查詢都怎么優(yōu)化過?
在業(yè)務(wù)系統(tǒng)中,除了使用主鍵進(jìn)行的查詢,其他的我都會在測試庫上測試其耗時,慢查詢的統(tǒng)計主要由運(yùn)維在做,會定期將業(yè)務(wù)中的慢查詢反饋給我們.
慢查詢的優(yōu)化首先要搞明白慢的原因是什么? 是查詢條件沒有命中索引?是load了不需要的數(shù)據(jù)列?還是數(shù)據(jù)量太大?
所以優(yōu)化也是針對這三個方向來的,
-
首先分析語句,看看是否load了額外的數(shù)據(jù),可能是查詢了多余的行并且拋棄掉了,可能是加載了許多結(jié)果中并不需要的列,對語句進(jìn)行分析以及重寫.
-
分析語句的執(zhí)行計劃,然后獲得其使用索引的情況,之后修改語句或者修改索引,使得語句可以盡可能的命中索引.
-
如果對語句的優(yōu)化已經(jīng)無法進(jìn)行,可以考慮表中的數(shù)據(jù)量是否太大,如果是的話可以進(jìn)行橫向或者縱向的分表.
5.區(qū)別B樹,B-,B+,B*?
- B樹:二叉樹,每個結(jié)點(diǎn)只存儲一個關(guān)鍵字,等于則命中,小于走左結(jié)點(diǎn),大于走右結(jié)點(diǎn);
- B-樹:多路搜索樹,每個結(jié)點(diǎn)存儲M/2到M個關(guān)鍵字,非葉子結(jié)點(diǎn)存儲指向關(guān)鍵字范圍的子結(jié)點(diǎn); 所有關(guān)鍵字在整顆樹中出現(xiàn),且只出現(xiàn)一次,非葉子結(jié)點(diǎn)可以命中;
- B+樹:在B-樹基礎(chǔ)上,為葉子結(jié)點(diǎn)增加鏈表指針,所有關(guān)鍵字都在葉子結(jié)點(diǎn)中出現(xiàn),非葉子結(jié)點(diǎn)作為葉子結(jié)點(diǎn)的索引;B+樹總是到葉子結(jié)點(diǎn)才命中;
- B*樹:在B+樹基礎(chǔ)上,為非葉子結(jié)點(diǎn)也增加鏈表指針,將結(jié)點(diǎn)的最低利用率從1/2提高到2/3;
6.MySQL優(yōu)化策略?
- 開啟查詢緩存,優(yōu)化查詢
- explain你的select查詢,這可以幫你分析你的查詢語句或是表結(jié)構(gòu)的性能瓶頸。EXPLAIN 的查詢結(jié)果還會告訴你你的索引主鍵被如何利用的,你的數(shù)據(jù)表是如何被搜索和排序的
- 當(dāng)只要一行數(shù)據(jù)時使用limit 1,MySQL數(shù)據(jù)庫引擎會在找到一條數(shù)據(jù)后停止搜索,而不是繼續(xù)往后查少下一條符合記錄的數(shù)據(jù)
- 為搜索字段建索引
- 使用 ENUM 而不是 VARCHAR,如果你有一個字段,比如“性別”,“國家”,“民族”,“狀態(tài)”或“部門”,你知道這些字段的取值是有限而且固定的,那么,你應(yīng)該使用 ENUM 而不是VARCHAR。
- Prepared StatementsPrepared Statements很像存儲過程,是一種運(yùn)行在后臺的SQL語句集合,我們可以從使用 prepared statements 獲得很多好處,無論是性能問題還是安全問題。Prepared Statements 可以檢查一些你綁定好的變量,這樣可以保護(hù)你的程序不會受到“SQL注入式”攻擊
- 垂直分表
- 選擇正確的存儲引擎
7.key和index的區(qū)別?
- key 是數(shù)據(jù)庫的物理結(jié)構(gòu),它包含兩層意義和作用,一是約束(偏重于約束和規(guī)范數(shù)據(jù)庫的結(jié)構(gòu)完整性),二是索引(輔助查詢用的)。包括primary key, unique key, foreign key 等
- index是數(shù)據(jù)庫的物理結(jié)構(gòu),它只是輔助查詢的,它創(chuàng)建時會在另外的表空間(mysql中的innodb表空間)以一個類似目錄的結(jié)構(gòu)存儲。索引要分類的話,分為前綴索引、全文本索引等;
8.怎么驗證 mysql 的索引是否滿足需求?
- 使用 explain 查看 SQL 是如何執(zhí)行查詢語句的,從而分析你的索引是否滿足需求。
- explain 語法:explain select * from table where type=1。
事務(wù)相關(guān)
1.ACID是什么?可以詳細(xì)說一下嗎?
- A=Atomicity
- 原子性,就是上面說的,要么全部成功,要么全部失敗.不可能只執(zhí)行一部分操作.
- C=Consistency
- 系統(tǒng)(數(shù)據(jù)庫)總是從一個一致性的狀態(tài)轉(zhuǎn)移到另一個一致性的狀態(tài),不會存在中間狀態(tài).
- I=Isolation
- 隔離性: 通常來說:一個事務(wù)在完全提交之前,對其他事務(wù)是不可見的.注意前面的通常來說加了紅色,意味著有例外情況.
- D=Durability
- 持久性,一旦事務(wù)提交,那么就永遠(yuǎn)是這樣子了,哪怕系統(tǒng)崩潰也不會影響到這個事務(wù)的結(jié)果.
2.同時有多個事務(wù)在進(jìn)行會怎么樣呢?
多事務(wù)的并發(fā)進(jìn)行一般會造成以下幾個問題:
-
臟讀: A事務(wù)讀取到了B事務(wù)未提交的內(nèi)容,而B事務(wù)后面進(jìn)行了回滾.
-
不可重復(fù)讀: 當(dāng)設(shè)置A事務(wù)只能讀取B事務(wù)已經(jīng)提交的部分,會造成在A事務(wù)內(nèi)的兩次查詢,結(jié)果竟然不一樣,因為在此期間B事務(wù)進(jìn)行了提交操作.
-
幻讀: A事務(wù)讀取了一個范圍的內(nèi)容,而同時B事務(wù)在此期間插入了一條數(shù)據(jù).造成"幻覺".
3.怎么解決這些問題呢?MySQL的事務(wù)隔離級別了解嗎?
MySQL的四種隔離級別如下:
4.Innodb使用的是哪種隔離級別呢?
- InnoDB默認(rèn)使用的是可重復(fù)讀隔離級別.
5.對MySQL的鎖了解嗎?
- 當(dāng)數(shù)據(jù)庫有并發(fā)事務(wù)的時候,可能會產(chǎn)生數(shù)據(jù)的不一致,這時候需要一些機(jī)制來保證訪問的次序,鎖機(jī)制就是這樣的一個機(jī)制.
6.MySQL都有哪些鎖呢?像上面那樣子進(jìn)行鎖定豈不是有點(diǎn)阻礙并發(fā)效率了?
從鎖的類別上來講,有共享鎖和排他鎖.
-
共享鎖: 又叫做讀鎖. 當(dāng)用戶要進(jìn)行數(shù)據(jù)的讀取時,對數(shù)據(jù)加上共享鎖.共享鎖可以同時加上多個.
-
排他鎖: 又叫做寫鎖. 當(dāng)用戶要進(jìn)行數(shù)據(jù)的寫入時,對數(shù)據(jù)加上排他鎖.排他鎖只可以加一個,他和其他的排他鎖,共享鎖都相斥.
用上面的例子來說就是用戶的行為有兩種,一種是來看房,多個用戶一起看房是可以接受的. 一種是真正的入住一晚,在這期間,無論是想入住的還是想看房的都不可以.
鎖的粒度取決于具體的存儲引擎,InnoDB實現(xiàn)了行級鎖,頁級鎖,表級鎖.
他們的加鎖開銷從大到小,并發(fā)能力也是從大到小.
7.行級鎖定的優(yōu)點(diǎn)缺點(diǎn)?
缺點(diǎn):
-
-
比頁級或表級鎖定占用更多的內(nèi)存。
-
當(dāng)在表的大部分中使用時,比頁級或表級鎖定速度慢,因為你必須獲取更多的鎖。
-
如果你在大部分?jǐn)?shù)據(jù)上經(jīng)常進(jìn)行GROUP BY操作或者必須經(jīng)常掃描整個表,比其它鎖定明顯慢很多。
-
用高級別鎖定,通過支持不同的類型鎖定,你也可以很容易地調(diào)節(jié)應(yīng)用程序,因為其鎖成本小于行級鎖定。
8.說一下 mysql 的行鎖和表鎖?
- MyISAM 只支持表鎖,InnoDB 支持表鎖和行鎖,默認(rèn)為行鎖。
表設(shè)計相關(guān)
1. 為什么要盡量設(shè)定一個主鍵?
- 主鍵是數(shù)據(jù)庫確保數(shù)據(jù)行在整張表唯一性的保障,即使業(yè)務(wù)上本張表沒有主鍵,也建議添加一個自增長的ID列作為主鍵.設(shè)定了主鍵之后,在后續(xù)的刪改查的時候可能更加快速以及確保操作數(shù)據(jù)范圍安全.
2.主鍵使用自增ID還是UUID?
- 推薦使用自增ID,不要使用UUID.
- 因為在InnoDB存儲引擎中,主鍵索引是作為聚簇索引存在的,也就是說,主鍵索引的B+樹葉子節(jié)點(diǎn)上存儲了主鍵索引以及全部的數(shù)據(jù)(按照順序),如果主鍵索引是自增ID,那么只需要不斷向后排列即可,如果是UUID,由于到來的ID與原來的大小不確定,會造成非常多的數(shù)據(jù)插入,數(shù)據(jù)移動,然后導(dǎo)致產(chǎn)生很多的內(nèi)存碎片,進(jìn)而造成插入性能的下降.
補(bǔ)充:
- 關(guān)于主鍵是聚簇索引,如果沒有主鍵,InnoDB會選擇一個唯一鍵來作為聚簇索引,如果沒有唯一鍵,會生成一個隱式的主鍵.
3. 字段為什么要求定義為not null?
- null值會占用更多的字節(jié),且會在程序中造成很多與預(yù)期不符的情況.
4.varchar(10)和int(10)代表什么含義?
- varchar的10代表了申請的空間長度,也是可以存儲的數(shù)據(jù)的最大長度,而int的10只是代表了展示的長度,不足10位以0填充.也就是說,int(1)和int(10)所能存儲的數(shù)字大小以及占用的空間都是相同的,只是在展示時按照長度展示.
5.建表策略?
-
對于大數(shù)據(jù)字段,獨(dú)立表進(jìn)行存儲,以便提高性能(例如:簡介字段);
-
使用varchar類型代替char,因為varchar會動態(tài)分配長度,char指定長度是固定的;
-
給表創(chuàng)建主鍵,對于沒有主鍵的表,在查詢和索引定義上有一定的影響;
-
避免表字段運(yùn)行為null,建議設(shè)置默認(rèn)值(例如:int類型設(shè)置默認(rèn)值為0)在索引查詢上,效率立顯;
-
建立索引,最好建立在唯一和非空的字段上,建立太多的索引對后期插入、更新都存在一定的影響(考慮實際情況來創(chuàng)建);
存儲引擎相關(guān)
1. MySQL支持哪些存儲引擎?
- MySQL支持多種存儲引擎,比如InnoDB,MyISAM,Memory,Archive等等.在大多數(shù)的情況下,直接選擇使用InnoDB引擎都是最合適的,InnoDB也是MySQL的默認(rèn)存儲引擎.
2.InnoDB和MyISAM有什么區(qū)別?
-
InnoDB支持事物,而MyISAM不支持事物
-
InnoDB支持行級鎖,而MyISAM支持表級鎖
-
InnoDB支持MVCC, 而MyISAM不支持
-
InnoDB支持外鍵,而MyISAM不支持
-
InnoDB不支持全文索引,而MyISAM支持。
3.什么是存儲過程?有哪些優(yōu)缺點(diǎn)?
存儲過程是一些預(yù)編譯的SQL語句。1、更加直白的理解:存儲過程可以說是一個記錄集,它是由一些T-SQL語句組成的代碼塊,這些T-SQL語句代碼像一個方法一樣實現(xiàn)一些功能(對單表或多表的增刪改查),然后再給這個代碼塊取一個名字,在用到這個功能的時候調(diào)用他就行了。2、存儲過程是一個預(yù)編譯的代碼塊,執(zhí)行效率比較高,一個存儲過程替代大量T_SQL語句 ,可以降低網(wǎng)絡(luò)通信量,提高通信速率,可以一定程度上確保數(shù)據(jù)安全
但是,在互聯(lián)網(wǎng)項目中,其實是不太推薦存儲過程的,比較出名的就是阿里的《Java開發(fā)手冊》中禁止使用存儲過程,我個人的理解是,在互聯(lián)網(wǎng)項目中,迭代太快,項目的生命周期也比較短,人員流動相比于傳統(tǒng)的項目也更加頻繁,在這樣的情況下,存儲過程的管理確實是沒有那么方便,同時,復(fù)用性也沒有寫在服務(wù)層那么好.
4.說一說三個范式?
- 第一范式: 每個列都不可以再拆分.
- 第二范式: 非主鍵列完全依賴于主鍵,而不能是依賴于主鍵的一部分.
- 第三范式: 非主鍵列只依賴于主鍵,不依賴于其他非主鍵.
在設(shè)計數(shù)據(jù)庫結(jié)構(gòu)的時候,要盡量遵守三范式,如果不遵守,必須有足夠的理由.比如性能. 事實上我們經(jīng)常會為了性能而妥協(xié)數(shù)據(jù)庫的設(shè)計.
|