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

5.什么是活化與鈍化?
服務(wù)器自動(dòng)完成(注意使用本地Tomcat才行)
6.EL內(nèi)置對(duì)象有哪些?
- 作用: 只能在EL 中使用,讓EL 更加簡(jiǎn)單

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