題目整理
Java基礎(chǔ)進階階段
基礎(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)的機制是什么?
內(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特點?
數(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.運行時異常和一般異常有何不同?
3.Java中異常處理機制的原理?
4.你平時在項目中是怎樣對異常進行處理的?
5.throw和throws有什么區(qū)別?
6.異常處理的時候,finally代碼塊的重要性是什么?
7.請列出 5 個運行時異常?
8.try catch finally,try里有return,finally還執(zhí)行么?
集合
1、List、Map、Set三個接口,存取元素時,各有什么特點?
2、ArrayList和LinkedList的底層實現(xiàn)原理?他們?yōu)槭裁淳€程不安全?在多線程并發(fā)操作下,我們應(yīng)該用什么替代?
3、HashMap和HashTable有什么區(qū)別?其底層實現(xiàn)是什么?CurrentHashMap的鎖機制又是如何?如果想將一個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的異同點?
泛型
1.為什么使用泛型?
2.泛型用在什么地方?
3.如何使用泛型類?
樹
1.什么是二叉樹?
2.什么是二叉查找樹?
3.什么是平衡二叉樹?
序列化
1.什么是 Java 序列化?
2.如何實現(xiàn) Java 序列化?
3.Java 序列話中,如果有些字段不想進行序列化怎么辦?
4.對象操作流是字符流還是字節(jié)流?
5.如何在讀寫文件時指定字符集?
6.字符緩沖流特有方法?
7.為什么使用對象流?
多線程
1.什么是線程?
2.線程和進程有什么區(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)者消費者問題?
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.守護線程和非守護線程有什么區(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特點?
反射
1.Java反射機制的作用?
2.什么是反射機制?
3.哪里用到反射機制?
4.反射機制的優(yōu)缺點?
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的異同點以及聯(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是什么?可以詳細說一下嗎?
2.同時有多個事務(wù)在進行會怎么樣呢?
3.怎么解決這些問題呢?MySQL的事務(wù)隔離級別了解嗎?
4.Innodb使用的是哪種隔離級別呢?
5.對MySQL的鎖了解嗎?
6.MySQL都有哪些鎖呢?像上面那樣子進行鎖定豈不是有點阻礙并發(fā)效率了?
7.行級鎖定的優(yōu)點缺點?
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)缺點?
4.說一說三個范式?
答案整理
Java基礎(chǔ)進階階段
基礎(chǔ)概念類
1.JDK1.8新特性?
提供lambda表達式極大地減少了代碼的冗余; 在接口中可以使用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)點:性能比面向?qū)ο蟾?,因為類調(diào)用時需要實例化,開銷比較大,比較消耗資源。比如,單片機、嵌入式開發(fā)、Linux/Unix 等一般采用面向過程開發(fā),性能是最重要的因素。
- 缺點:沒有面向?qū)ο笠拙S護、易復(fù)用、易擴展。
面向?qū)ο?/strong>
- 優(yōu)點:易維護、易復(fù)用、易擴展,由于面向?qū)ο笥蟹庋b、繼承、多態(tài)性的特性,可以設(shè)計出低耦合的系統(tǒng),使系統(tǒng)更加靈活、更加易于維護。
- 缺點:性能比面向過程低。
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
- 通過序列化機制
前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),所以接口的擴展性比較好,實際開發(fā)中盡量避免繼承的使用
-
父類的靜態(tài)方法能否被子類重寫
- 不能。重寫只適用于實例方法,不能用于靜態(tài)方法,而子類當(dāng)中含有和父類相同簽名的靜態(tài)方法,我們一般稱之為隱藏。
-
繼承的好處和壞處
- 好處:
- 子類能自動繼承父類的對象 2、創(chuàng)建子類的對象時,無須創(chuàng)建父類的對象
- 壞處:
- 破壞封裝,子類與父類之間緊密耦合,子類依賴于父類的實現(xiàn),子類缺乏獨立性。
- 支持?jǐn)U展,但是往往以增強系統(tǒng)結(jié)構(gòu)的復(fù)雜度為代價
- 不支持動態(tài)繼承。在運行時,子類無法選擇不同的父類
- 子類不能改變父類的接口
接口抽象類
1.接口的意義
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),以提高運行效率
- 被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)點:
- 可替換性:多態(tài)對已存在代碼具有可替換性
- 可擴充性:增加新的子類不影響已經(jīng)存在的類結(jié)構(gòu)
- 更加靈活
- 弊端:
2.代碼中如何實現(xiàn)多態(tài)
實現(xiàn)多態(tài)主要有以下三種方式:
-
接口實現(xiàn)
-
繼承父類重寫方法
-
同一類中進行方法重載
3.Java 中實現(xiàn)多態(tài)的機制是什么?
內(nèi)部類Lambda
1.內(nèi)部類的作用?
- 內(nèi)部類可以有多個實例,每個實例都有自己的狀態(tài)信息,并且與其他外圍對象的信息相互獨立.在單個外圍類當(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表達式編譯后并不會生成.class文件,而匿名內(nèi)部類編譯后會產(chǎn)生單獨的class文件;
- 匿名內(nèi)部類可以用在類,抽象類,接口中,而lambda表達式只能用在有且僅有一個抽象方法的接口中;
static關(guān)鍵字
1.是否可以在static環(huán)境中訪問非static變量?
- static變量在Java中是屬于類的,它在所有的實例中的值是一樣的。當(dāng)類被Java虛擬機載入的時候,會對static變量進行初始化。如果你的代碼嘗試不用實例來訪問非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特點
- 如果修飾構(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,因為有些浮點數(shù)不能完全精確的表示出來
3.基本數(shù)據(jù)類型的默認(rèn)值?基本數(shù)據(jù)類型所占的字節(jié)以及封裝他們的類?
4.String屬于那個類,以及常用的方法?
5.String, StringBuffer和StringBuilder區(qū)別
- String的值是不可改變的,這就導(dǎo)致每次對String的操作都會生成新的String對象,不禁效率底下, 而且浪費大量的內(nèi)存空間;
- StringBuilder是可變類,任何對他指向的字符串的操作都不會產(chǎn)生新的對 象,但單線程不安全;
- StringBuffer底層方法使用了synchronized關(guān)鍵字,線程比較安全,但效率 較StringBuilder慢
異常相關(guān)
1.error和exception有什么區(qū)別
- error表示系統(tǒng)級的錯誤,是java運行環(huán)境內(nèi)部錯誤或者硬件問題,不能指望程序來處理這樣的問題,除了退出運行外別無選擇,它是Java虛擬機拋出的。
- exception 表示程序需要捕捉、需要處理的異常,是由與程序設(shè)計的不完善而出現(xiàn)的問題,程序必須處理的問題
2.運行時異常和一般異常有何不同
- Java提供了兩類主要的異常:runtimeException和checkedException
- 一般異常(checkedException)主要是指IO異常、SQL異常等。對于這種異常,JVM要求我們必須對其進行cathc處理,所以,面對這種異常,不管我們是否愿意,都是要寫一大堆的catch塊去處理可能出現(xiàn)的異常。
- 運行時異常(runtimeException)我們一般不處理,當(dāng)出現(xiàn)這類異常的時候程序會由虛擬機接管。比如,我們從來沒有去處理過NullPointerException,而且這個異常還是最常見的異常之一。
- 出現(xiàn)運行時異常的時候,程序會將異常一直向上拋,一直拋到遇到處理代碼,如果沒有catch塊進行處理,到了最上層,如果是多線程就有Thread.run()拋出,如果不是多線程那么就由main.run()拋出。拋出之后,如果是線程,那么該線程也就終止了,如果是主程序,那么該程序也就終止了。
- 其實運行時異常的也是繼承自Exception,也可以用catch塊對其處理,只是我們一般不處理罷了,也就是說,如果不對運行時異常進行catch處理,那么結(jié)果不是線程退出就是主程序終止。
- 如果不想終止,那么我們就必須捕獲所有可能出現(xiàn)的運行時異常。如果程序中出現(xiàn)了異常數(shù)據(jù),但是它不影響下面的程序執(zhí)行,那么我們就該在catch塊里面將異常數(shù)據(jù)舍棄,然后記錄日志。如果,它影響到了下面的程序運行,那么還是程序退出比較好些。
3.Java中異常處理機制的原理
Java通過面向?qū)ο蟮姆绞綄Ξ惓_M行處理,Java把異常按照不同的類型進行分類,并提供了良好的接口。當(dāng)一個方法出現(xiàn)異常后就會拋出一個異常對象,該對象中包含有異常信息,調(diào)用這個對象的方法可以捕獲到這個異常并對異常進行處理。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.你平時在項目中是怎樣對異常進行處理的。
- 盡量避免出現(xiàn)runtimeException 。例如對于可能出現(xiàn)空指針的代碼,帶使用對象之前一定要判斷一下該對象是否為空,必要的時候?qū)untimeException
也進行try catch處理。
- 進行try catch處理的時候要在catch代碼塊中對異常信息進行記錄,通過調(diào)用異常類的相關(guān)方法獲取到異常的相關(guān)信息,返回到web端,不僅要給用戶良好的用戶體驗,也要能幫助程序員良好的定位異常出現(xiàn)的位置及原因。例如,以前做的一個項目,程序遇到異常頁面會顯示一個圖片告訴用戶哪些操作導(dǎo)致程序出現(xiàn)了什么異常,同時圖片上有一個按鈕用來點擊展示異常的詳細信息給程序員看的。
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 個運行時異常?
- NullPointerException 空指針
- IndexOutOfBoundsException 索引越界
- ClassCastException 類型轉(zhuǎn)換異常
- ArrayStoreException 當(dāng)你試圖將錯誤類型的對象存儲到一個對象數(shù)組時拋出的異常
- BufferOverflowException 寫入的長度超出了允許的長度
- IllegalArgumentException 方法的參數(shù)無效
- NoClassDefFoundException - JAVA運行時系統(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三個接口,存取元素時,各有什么特點?
- Set集合的add有一個boolean類型的返回值,當(dāng)集合中沒有某個元素時,則可以成功加入該 元素,返回結(jié)果為true;當(dāng)集合中存在與某個元素equals方法相等 的元素時,則無法加入該元素, 取元素時只能用Iterator接口取得所有元素,在逐一遍歷各個元素;
- List表示有先后順序的集合,調(diào)用add()方法,指定當(dāng)前對象在集合中的存放位置;一個對象可 以被反復(fù)存進集合中;每調(diào)用一次add()方法,該對象就會被插入集合中一次,其實,并不是把對 象本身存進了集合中,而是在集合中使用一個索引變量指向了該對象,當(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ù)組進行移位等內(nèi)存操作,所以索引快插入較慢;(擴容方式)一旦我們實例化了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),取元素時需要進行前項或后項的遍歷,插入元素時只需要記錄本項的前后 項即可,所以插入快查詢慢;
- 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的鎖機制又是如何?如果想將一個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接口提供了很多對集合元素進行迭代的方法。每一個集合類都包含了可以返回迭代器實例的迭代方法。迭代器可以在迭代的過程中刪除底層集合的元素,但是不可以直接調(diào)用集合的remove(Object Obj)刪除,可以通過迭代器的remove()方法刪除
5.Arraylist 與 LinkedList 區(qū)別
- Arraylist:
- 優(yōu)點:ArrayList是實現(xiàn)了基于動態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu),因為地址連續(xù),一旦數(shù)據(jù)存儲好了,查詢操作效率會比較高(在內(nèi)存里是連著放的)。
- 缺點:因為地址連續(xù), ArrayList要移動數(shù)據(jù),所以插入和刪除操作效率比較低。
- LinkedList:
- 優(yōu)點:LinkedList基于鏈表的數(shù)據(jù)結(jié)構(gòu),地址是任意的,所以在開辟內(nèi)存空間的時候不需要等一個連續(xù)的地址,對于新增和刪除操作add和remove,LinedList比較占優(yōu)勢。LinkedList 適用于要頭尾操作或插入指定位置的場景
- 缺點:因為LinkedList要移動指針,所以查詢操作性能比較低。
6.Arraylist 與 LinkedList 應(yīng)用場景?
- 當(dāng)需要對數(shù)據(jù)進行對此訪問的情況下選用ArrayList,當(dāng)需要對數(shù)據(jù)進行多次增加刪除修改時采用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特點:
- Set特點:
- 元素?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é)點,最終找到要找的值對象。
15.有沒有可能兩個不相等的對象有相同的hashcode?
- 有可能,(通話,重地)兩個不相等的對象可能會有相同的 hashcode 值,這就是為什么在 hashmap 中會有沖突。如果兩個對象相等,必須有相同的hashcode 值,反之不成立。
16.HashMap、LinkedHashMap、TreeMap的區(qū)別?
- HashMap是根據(jù)鍵的hashcode值存儲數(shù)據(jù),根據(jù)鍵可以直接獲取它的值,具有很快的訪問速度,取得的數(shù)據(jù)完全是隨機的
- LinkedHashMap保存了記錄的插入順序,在使用Iterator進行遍歷的時候,先得到的肯定是先插入的數(shù)據(jù),可以在構(gòu)造時帶參數(shù),按照應(yīng)用次數(shù)來進行排序
- TreeMap實現(xiàn)SortMap接口,能夠把它保存的記錄根據(jù)鍵排序。默認(rè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ù)組 大小是否可以容納新的元素,如果不夠就會進行擴容。然后會將原來的數(shù)據(jù)拷貝到新的數(shù)組中。
- LinkedList底層是一個鏈表,其實現(xiàn)增刪改查和數(shù)據(jù)結(jié)構(gòu)中的操作完全相同,而且插入是有序的。
- LinkedHashMap的底層結(jié)構(gòu)式是雙鏈表,其他的邏輯處理與HashMap一致,同樣沒有鎖保護,多線程使用時存在風(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ù)進行修改時,需要先獲得它所對應(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的異同點?
相同點:
返回值的規(guī)則:
-
如果返回值為負(fù)數(shù),表示當(dāng)前存入的元素是較小值,存左邊
-
如果返回值為0,表示當(dāng)前存入的元素跟集合中元素重復(fù)了,不存
-
如果返回值為正數(shù),表示當(dāng)前存入的元素是較大值,存右邊
不同點:
1.用到的接口不同
-
自然排序: 自定義類實現(xiàn)Comparable接口,重寫compareTo方法,根據(jù)返回值進行排序
-
比較器排序: 創(chuàng)建TreeSet對象的時候傳遞Comparator的實現(xiàn)類對象,重寫compare方法,根據(jù)返回值進行排序
2.使用場景不同
-
自然排序能滿足大部分情況
-
存儲沒有修改權(quán)限的類時可以使用
20.Iterator 和 ListIterator 有什么區(qū)別?
-
Iterator可用來遍歷Set和List集合,但是ListIterator只能用來遍歷List。
-
Iterator對集合只能是前向遍歷,ListIterator既可以前向也可以后向。
-
ListIterator實現(xiàn)了Iterator接口,并包含其他的功能,比如:增加元素,替換元素,獲取前一個和后一個元素的索引,等等。
泛型
1.為什么使用泛型?
- 它提供了編譯時類型安全檢測機制,把運行時期的問題提前到了編譯期間
- 避免了強制類型轉(zhuǎn)換
2.泛型用在什么地方?
3.如何使用泛型類?
- 創(chuàng)建泛型類對象時,必須要給這個泛型確定具體的數(shù)據(jù)類型
樹
1.什么是二叉樹?
2.什么是二叉查找樹?
- 每個節(jié)點最多有兩個子節(jié)點,左邊比當(dāng)前節(jié)點小,右邊比當(dāng)前節(jié)點大
3.什么是平衡二叉樹?
- 二叉樹左右子樹的樹高差不超過1,任意節(jié)點的左右子樹都是平衡二叉樹
- 通過左旋右旋保持樹的平衡
序列化
1.什么是 Java 序列化?
- 序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內(nèi)容進行流化。
- 可以對流化后的對象進行讀寫操作,也可將流化后的對象傳輸于網(wǎng)絡(luò)之間。
- 序列化是為了解決在對對象流進行讀寫操作時所引發(fā)的問題。
- 反序列化的過程,則是和序列化相反的過程。
- 另外,我們不能將序列化局限在 Java 對象轉(zhuǎ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 序列話中,如果有些字段不想進行序列化怎么辦?
- 對于不想進行序列化的變量,使用 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():讀取一整行,到達尾處為null
- newLine():跨平臺換行
7.為什么使用對象流?
- 在開發(fā)中,經(jīng)常需要將對象的信息保存到磁盤中,如果使用前面所學(xué)的知識來實現(xiàn),會非常的繁瑣。使用對象流就非常的方便
- 對象操作流可以將對象以字節(jié)的形式寫到本地文件中,直接打開是看不懂的,需要時可以再次用對象操作流讀到內(nèi)存中
多線程
1.什么是線程?
- 線程是操作系統(tǒng)能夠進行運算調(diào)度的最小單位,它被包含在進程之中,是進程中的實際運作單位。線程是進程的一部分,是進程中的單個控制流,是一條執(zhí)行路徑
2.線程和進程有什么區(qū)別?
- 線程是進程的子集,一個進程可以有很多線程,每條線程并行執(zhí)行不同的任務(wù)。不同的進程使用不同的內(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:
- 擴展性比較強,優(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是一個線程安全類嗎?
- 多個線程可能會同時運行同一段代碼。如果每次運行結(jié)果和單線程運行的結(jié)果是一樣的,而且其他的變量的值也和預(yù)期的是一樣的,就是線程安全的。一個線程安全的計數(shù)器類的同一個實例對象在被多個線程使用的情況下也不會出現(xiàn)計算失誤。很顯然你可以將集合類分成兩組,線程安全和非線程安全的。Vector 是用同步方法來實現(xiàn)線程安全的, 而和它相似的ArrayList不是線程安全的。
10.Java中如何停止一個線程?
- 當(dāng)run() 或者 call() 方法執(zhí)行完的時候線程會自動結(jié)束,如果要手動結(jié)束一個線程,你可以用volatile 布爾變量或設(shè)置某個變量達到一定值的時候,來退出run()方法的循環(huán)或者是取消任務(wù)來中斷線程。
11.Java中notify 和 notifyAll有什么區(qū)別?
- notify()方法不能喚醒某個具體的線程,所以只有一個線程在等待的時候它才有用武之地。
- notifyAll()喚醒所有線程并允許他們爭奪鎖確保了至少有一個線程能繼續(xù)運行
12. 什么是線程池? 為什么要使用它?
- 創(chuàng)建線程要花費昂貴的資源和時間,如果任務(wù)來了才創(chuàng)建線程那么響應(yīng)時間會變長,而且一個進程能創(chuàng)建的線程數(shù)有限。為了避免這些問題,在程序啟動的時候就創(chuàng)建若干線程來響應(yīng)處理,它們被稱為線程池,里面的線程叫工作線程。從JDK1.5開始,Java API提供了Executor框架讓你可以創(chuàng)建不同的線程池。比如單線程池,每次處理一個任務(wù);數(shù)目固定的線程池或者是緩存線程池(一個適合很多生存期短的任務(wù)的程序的可擴展線程池)
13.如何寫代碼來解決生產(chǎn)者消費者問題?
- 在現(xiàn)實中你解決的許多線程問題都屬于生產(chǎn)者消費者模型,就是一個線程生產(chǎn)任務(wù)供其它線程進行消費,你必須知道怎么進行線程間通信來解決這個問題。比較低級的辦法是用wait和notify來解決這個問題,比較贊的辦法是用Semaphore 或者 BlockingQueue來實現(xiàn)生產(chǎn)者消費者模型
14.Java多線程中的死鎖
死鎖是指兩個或兩個以上的進程在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法推進下去。這是一個嚴(yán)重的問題,因為死鎖會讓你的程序掛起無法完成任務(wù),死鎖的發(fā)生必須滿足以下四個條件:
-
互斥條件:一個資源每次只能被一個進程使用。
-
請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
-
不剝奪條件:進程已獲得的資源,在末使用完之前,不能強行剝奪。
-
循環(huán)等待條件:若干進程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。
避免死鎖最簡單的方法就是阻止循環(huán)等待條件,將系統(tǒng)中所有的資源設(shè)置標(biāo)志位、排序,規(guī)定所有的進程申請資源必須以一定的順序(升序或降序)做操作來避免死鎖。
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)進入到了某個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),重量級鎖(悲觀鎖))進行了大量的優(yōu)化
17.在Java中Lock接口與synchronized塊的區(qū)別是什么?
- 用法不一樣。synchronized既可以加在方法上,也可以加載特定的代碼塊上,括號中表示需要鎖的對象。而Lock需要顯示地指定起始位置和終止位置。synchronzied是托管給jvm執(zhí)行的,Lock鎖定是通過代碼實現(xiàn)的。
- 在性能上來說,如果競爭資源不激烈,兩者的性能是差不多的,而當(dāng)競爭資源非常激烈時(即有大量線程同時競爭),此時Lock的性能要遠遠優(yōu)于synchronized。所以說,在具體使用時要根據(jù)適當(dāng)情況選擇。
- 鎖的機制不一樣。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)鍵字,它提供了一種獨占的加鎖方式。
- synchronized的獲取和釋放鎖由JVM實現(xiàn),用戶不需要顯示的釋放鎖,非常方便。
- 不足:
- 當(dāng)線程嘗試獲取鎖的時候,如果獲取不到鎖會一直阻塞。
- 如果獲取鎖的線程進入休眠或者阻塞,除非當(dāng)前線程異常,否則其他線程嘗試獲取鎖必須一直等待。
19.關(guān)于成員變量和局部變量
- 如果一個變量是成員變量,那么多個線程對同一個對象的成員變量進行操作的時候,他們對該成員變量是彼此影響的,也就是說一個線程對成員變量的改變會影響到另外一個線程;如果一個變量是局部變量,那么每個線程都會有一個該局部變量的拷貝,一個線程對該局部變量的改變不會影響到其它的線程。
20. 如果你提交任務(wù)時,線程池隊列已滿。會時發(fā)會生什么?
- 如果一個任務(wù)不能被調(diào)度執(zhí)行那么ThreadPoolExecutor’s submit()方法將會拋出一個RejectedExecutionException異常。
21.volatile關(guān)鍵字的作用是?
- 保證變量的可見性。
- 在java內(nèi)存結(jié)構(gòu)中,每個線程都是有自己獨立的內(nèi)存空間(此處指的線程棧)。當(dāng)需要對一個共享變量操作時,線程會將這個數(shù)據(jù)從主存空間復(fù)制到自己的獨立空間內(nèi)進行操作,然后在某個時刻將修改后的值刷新到主存空間。這個中間時間就會發(fā)生許多奇奇怪怪的線程安全問題了,volatile就出來了,它保證讀取數(shù)據(jù)時只從主存空間讀取,修改數(shù)據(jù)直接修改到主存空間中去,這樣就保證了這個變量對多個操作線程的可見性了。換句話說,被volatile修飾的變量,能保證該變量的 單次讀或者單次寫 操作是原子的。
- 但是線程安全是兩方面需要的 原子性(指的是多條操作)和可見性。volatile只能保證可見性,synchronized是兩個均保證的。
- volatile輕量級,只能修飾變量;synchronized重量級,還可修飾方法。
- volatile不會造成線程的阻塞,而synchronized可能會造成線程的阻塞。
22.守護線程和非守護線程有什么區(qū)別?
- 程序運行完畢,JVM 會等待非守護線程完成后關(guān)閉,但是 JVM 不會等待守護線程
23.線程的生命周期?
線程的生命周期包含5個階段,包括:新建、就緒、運行、阻塞、銷毀。
-
新建:就是剛使用new方法,new出來的線程;
-
就緒:就是調(diào)用的線程的start()方法后,這時候線程處于等待CPU分配資源階段,誰先搶的CPU資源,誰開始執(zhí)行;
-
運行:當(dāng)就緒的線程被調(diào)度并獲得CPU資源時,便進入運行狀態(tài),run方法定義了線程的操作和功能;
-
阻塞:在運行狀態(tài)的時候,可能因為某些原因?qū)е逻\行狀態(tài)的線程變成了阻塞狀態(tài),比如sleep()、wait()之后線程就處于了阻塞狀態(tài),這個時候需要其他機制將處于阻塞狀態(tài)的線程喚醒,比如調(diào)用notify或者notifyAll()方法。喚醒的線程不會立刻執(zhí)行run方法,它們要再次等待CPU分配資源進入運行狀態(tài);
-
銷毀:如果線程正常執(zhí)行完畢后或線程被提前強制性的終止或出現(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,此時可以進行修改,將V改成新值
- 當(dāng)預(yù)期值E!=主內(nèi)存中的值V時,將主內(nèi)存中的已經(jīng)改變的值更新到自己的工作內(nèi)存中,再次嘗試比較,直到預(yù)期值E等于主內(nèi)存中的值V,才可以修改。這個過程稱為自旋
30.synchronized和CAS的區(qū)別?
- 相同點:
- 在多線程情況下,都可以保證共享數(shù)據(jù)的安全性。
- 不同點:
- 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特點?
- Hashtable:
- ConcurrentHashMap:
反射類加載器
1.Java反射機制的作用?
- 在運行時判斷任意一個對象所屬的類。
- 在運行時判斷任意一個類所具有的成員變量和方法。
- 在運行時任意調(diào)用一個對象的方法
- 在運行時構(gòu)造任意一個類的對象
2.什么是反射機制?
- 簡單說,反射機制值得是程序在運行時能夠獲取自身的信息。在java中,只要給定類的名字,那么就可以通過反射機制來獲得類的所有信息。
3.哪里用到反射機制?
- Spring 框架的 IoC 基于反射創(chuàng)建對象和設(shè)置依賴屬性。
- Spring MVC 的請求調(diào)用對應(yīng)方法,也是通過反射。
- JDBC 的 Class#forName(String className) 方法,也是使用反射。
4.反射機制的優(yōu)缺點?
- 靜態(tài)編譯:
- 動態(tài)編譯:
- 運行時確定類型,綁定對象。動態(tài)編譯最大限度的發(fā)揮了java的靈活性,體現(xiàn)了多態(tài)的應(yīng)用,有利于降低類之間的耦合性。一句話,反射機制的優(yōu)點就是可以實現(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)功能的更新,而采用反射機制的話,它就可以不用卸載,只需要在運行時才動態(tài)的創(chuàng)建和編譯,就可以實現(xiàn)該功能。它的缺點是對性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它滿足我們的要求。這類操作總是慢于只直接執(zhí)行相同的操作
5.反射中,Class.forName 和 ClassLoader 區(qū)別
- java中class.forName()和classLoader都可用來對類進行加載。
- class.forName()前者除了將類的.class文件加載到j(luò)vm中之外,還會對類進行解釋,執(zhí)行類中的static塊。
- 而classLoader只干一件事情,就是將.class文件加載到j(luò)vm中,不會執(zhí)行static中的內(nèi)容,只有在newInstance才會去執(zhí)行static塊。
6.什么是雙親委派模型?
- 如果一個類加載器收到了類加載請求,它并不會自己先去加載,而是把這個請求委托給父類的加載器去執(zhí)行,如果父類加載器還存在其父類加載器,則進一步向上委托,依次遞歸,請求最終將到達頂層的啟動類加載器,如果父類加載器可以完成類加載任務(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表達式內(nèi)置對象:
pageContext對象是二者唯一相同的對象,其他都是各自獨立的對象
2.說一下 jsp 的 4 種作用域?
JSP中的四種作用域包括page、request、session和application,具體來說:
-
page代表與一個頁面相關(guān)的對象和屬性。
-
request代表與Web客戶機發(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ù)器運行環(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 表達式內(nèi)置對象和,JSP 內(nèi)置對象不是一回事,el表達式中想要使用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超時時間,達到超時時間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方法表達。
- Web容器加載Servlet,Servlet被服務(wù)器實例化后,生命周期開始。通過調(diào)用servlet的init()方法進行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īng)的 Servlet 實例的 service() 方法,service() 方法再派遣運行與請求相對應(yīng)的 doXX(doGet,doPost) 方法來處理用戶請求。
- 銷毀 當(dāng) Servlet 容器決定將一個 Servlet 從服務(wù)器中移除時 ( 如 Servlet 文件被更新 ),便調(diào)用該 Servlet 實例的 destroy() 方法,在銷毀該 Servlet 實例之前, 來做一些其他的工作。
加載實例化,初始化,銷毀,在整個生命周期中只會執(zhí)行一次
補充:
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請求頭或請求體進行一些格式化的處理
- 將響應(yīng)數(shù)據(jù)進行壓縮再返回給瀏覽器。
- 解決亂碼問題。
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 的順序進行調(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é)點中必須配置一個整數(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ā):
補充:
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)用戶打開多個同屬于一個進程的瀏覽器窗口,在這些窗口的訪問屬于同一個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ù)寫的方法進行復(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都會有自己獨有的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的異同點以及聯(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),可以幫助我們快速的進行數(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)常作為條件進行查詢的字段比較適合.如果需要建立聯(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)中,除了使用主鍵進行的查詢,其他的我都會在測試庫上測試其耗時,慢查詢的統(tǒng)計主要由運維在做,會定期將業(yè)務(wù)中的慢查詢反饋給我們.
慢查詢的優(yōu)化首先要搞明白慢的原因是什么? 是查詢條件沒有命中索引?是load了不需要的數(shù)據(jù)列?還是數(shù)據(jù)量太大?
所以優(yōu)化也是針對這三個方向來的,
-
首先分析語句,看看是否load了額外的數(shù)據(jù),可能是查詢了多余的行并且拋棄掉了,可能是加載了許多結(jié)果中并不需要的列,對語句進行分析以及重寫.
-
分析語句的執(zhí)行計劃,然后獲得其使用索引的情況,之后修改語句或者修改索引,使得語句可以盡可能的命中索引.
-
如果對語句的優(yōu)化已經(jīng)無法進行,可以考慮表中的數(shù)據(jù)量是否太大,如果是的話可以進行橫向或者縱向的分表.
5.區(qū)別B樹,B-,B+,B*?
- B樹:二叉樹,每個結(jié)點只存儲一個關(guān)鍵字,等于則命中,小于走左結(jié)點,大于走右結(jié)點;
- B-樹:多路搜索樹,每個結(jié)點存儲M/2到M個關(guān)鍵字,非葉子結(jié)點存儲指向關(guān)鍵字范圍的子結(jié)點; 所有關(guān)鍵字在整顆樹中出現(xiàn),且只出現(xiàn)一次,非葉子結(jié)點可以命中;
- B+樹:在B-樹基礎(chǔ)上,為葉子結(jié)點增加鏈表指針,所有關(guān)鍵字都在葉子結(jié)點中出現(xiàn),非葉子結(jié)點作為葉子結(jié)點的索引;B+樹總是到葉子結(jié)點才命中;
- B*樹:在B+樹基礎(chǔ)上,為非葉子結(jié)點也增加鏈表指針,將結(jié)點的最低利用率從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很像存儲過程,是一種運行在后臺的SQL語句集合,我們可以從使用 prepared statements 獲得很多好處,無論是性能問題還是安全問題。Prepared Statements 可以檢查一些你綁定好的變量,這樣可以保護你的程序不會受到“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是什么?可以詳細說一下嗎?
- A=Atomicity
- 原子性,就是上面說的,要么全部成功,要么全部失敗.不可能只執(zhí)行一部分操作.
- C=Consistency
- 系統(tǒng)(數(shù)據(jù)庫)總是從一個一致性的狀態(tài)轉(zhuǎn)移到另一個一致性的狀態(tài),不會存在中間狀態(tài).
- I=Isolation
- 隔離性: 通常來說:一個事務(wù)在完全提交之前,對其他事務(wù)是不可見的.注意前面的通常來說加了紅色,意味著有例外情況.
- D=Durability
- 持久性,一旦事務(wù)提交,那么就永遠是這樣子了,哪怕系統(tǒng)崩潰也不會影響到這個事務(wù)的結(jié)果.
2.同時有多個事務(wù)在進行會怎么樣呢?
多事務(wù)的并發(fā)進行一般會造成以下幾個問題:
-
臟讀: A事務(wù)讀取到了B事務(wù)未提交的內(nèi)容,而B事務(wù)后面進行了回滾.
-
不可重復(fù)讀: 當(dāng)設(shè)置A事務(wù)只能讀取B事務(wù)已經(jīng)提交的部分,會造成在A事務(wù)內(nèi)的兩次查詢,結(jié)果竟然不一樣,因為在此期間B事務(wù)進行了提交操作.
-
幻讀: 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ù)的不一致,這時候需要一些機制來保證訪問的次序,鎖機制就是這樣的一個機制.
6.MySQL都有哪些鎖呢?像上面那樣子進行鎖定豈不是有點阻礙并發(fā)效率了?
從鎖的類別上來講,有共享鎖和排他鎖.
-
共享鎖: 又叫做讀鎖. 當(dāng)用戶要進行數(shù)據(jù)的讀取時,對數(shù)據(jù)加上共享鎖.共享鎖可以同時加上多個.
-
排他鎖: 又叫做寫鎖. 當(dāng)用戶要進行數(shù)據(jù)的寫入時,對數(shù)據(jù)加上排他鎖.排他鎖只可以加一個,他和其他的排他鎖,共享鎖都相斥.
用上面的例子來說就是用戶的行為有兩種,一種是來看房,多個用戶一起看房是可以接受的. 一種是真正的入住一晚,在這期間,無論是想入住的還是想看房的都不可以.
鎖的粒度取決于具體的存儲引擎,InnoDB實現(xiàn)了行級鎖,頁級鎖,表級鎖.
他們的加鎖開銷從大到小,并發(fā)能力也是從大到小.
7.行級鎖定的優(yōu)點缺點?
缺點:
-
-
比頁級或表級鎖定占用更多的內(nèi)存。
-
當(dāng)在表的大部分中使用時,比頁級或表級鎖定速度慢,因為你必須獲取更多的鎖。
-
如果你在大部分?jǐn)?shù)據(jù)上經(jīng)常進行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é)點上存儲了主鍵索引以及全部的數(shù)據(jù)(按照順序),如果主鍵索引是自增ID,那么只需要不斷向后排列即可,如果是UUID,由于到來的ID與原來的大小不確定,會造成非常多的數(shù)據(jù)插入,數(shù)據(jù)移動,然后導(dǎo)致產(chǎn)生很多的內(nèi)存碎片,進而造成插入性能的下降.
補充:
- 關(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ù)字段,獨立表進行存儲,以便提高性能(例如:簡介字段);
-
使用varchar類型代替char,因為varchar會動態(tài)分配長度,char指定長度是固定的;
-
給表創(chuàng)建主鍵,對于沒有主鍵的表,在查詢和索引定義上有一定的影響;
-
避免表字段運行為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)缺點?
存儲過程是一些預(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è)計.
|