午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

java最常見(jiàn)200+面試題及解析

 頭號(hào)碼甲 2021-04-28

題目整理

Java基礎(chǔ)進(jìn)階階段

基礎(chǔ)概念類

1.JDK1.8新特性?

2.面向?qū)ο蠛兔嫦蜻^(guò)程的區(qū)別?

3.什么是值傳遞和引用傳遞?

4.什么是不可變對(duì)象?

5.講講類的實(shí)例化順序?

6.java 創(chuàng)建對(duì)象的幾種方式

7.Java訪問(wèn)修飾符的作用域

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)境中訪問(wè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)問(wèn)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.有沒(méi)有可能兩個(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.如何使用泛型類?

樹(shù)

1.什么是二叉樹(shù)?

2.什么是二叉查找樹(shù)?

3.什么是平衡二叉樹(shù)?

序列化

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)者問(wèn)題?

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)線程安全問(wè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.說(shuō)一下 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)站訪問(wèn)量。那么會(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過(guò)濾器的作用?

5.servlet監(jiān)聽(tīng)器的作用?

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)心過(guò)業(yè)務(wù)系統(tǒng)里面的sql耗時(shí)嗎?統(tǒng)計(jì)過(guò)慢查詢嗎?對(duì)慢查詢都怎么優(yōu)化過(guò)?

5.區(qū)別B樹(shù),B-,B+,B*?

6.MySQL優(yōu)化策略?

7.key和index的區(qū)別?

8.怎么驗(yàn)證 mysql 的索引是否滿足需求?

事務(wù)相關(guān)

1.ACID是什么?可以詳細(xì)說(shuō)一下嗎?

2.同時(shí)有多個(gè)事務(wù)在進(jìn)行會(huì)怎么樣呢?

3.怎么解決這些問(wèn)題呢?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.說(shuō)一下 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ǔ)過(guò)程?有哪些優(yōu)缺點(diǎn)?

4.說(shuō)一說(shuō)三個(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開(kāi)始,12月是11,而java.time.LocalDate月份和星期都改成了 enum, 就不可能出錯(cuò)了;
2.面向?qū)ο蠛兔嫦蜻^(guò)程的區(qū)別?

面向過(guò)程

  • 優(yōu)點(diǎn):性能比面向?qū)ο蟾撸驗(yàn)轭愓{(diào)用時(shí)需要實(shí)例化,開(kāi)銷比較大,比較消耗資源。比如,單片機(jī)、嵌入式開(kāi)發(fā)、Linux/Unix 等一般采用面向過(guò)程開(kāi)發(fā),性能是最重要的因素。
  • 缺點(diǎn):沒(méi)有面向?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):性能比面向過(guò)程低。
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
  • 通過(guò)反射
  • 采用clone
  • 通過(guò)序列化機(jī)制

前2者都需要顯式地調(diào)用構(gòu)造方法。造成耦合性最高的恰好是第一種,因此你發(fā)現(xiàn)無(wú)論什么框架,只要涉及到解耦必先減少new的使用

7.Java訪問(wèn)修飾符的作用域

作用域 當(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之后開(kāi)始支持String
9.switch中能否作用在byte,long上?
  • 可以用在byte上,不能用在long上
10.什么是自動(dòng)拆裝箱?
  • 自動(dòng)裝箱和拆箱,就是基本類型和引用類型之間的轉(zhuǎn)換。
  • 把基本數(shù)據(jù)類型轉(zhuǎn)換成包裝類的過(guò)程就是打包裝,為裝箱。
  • 把包裝類轉(zhuǎn)換成基本數(shù)據(jù)類型的過(guò)程就是拆包裝,為拆箱
11.如何正確的退出多層嵌套循環(huán)?

使用標(biāo)號(hào)和break;

繼承

  • Java支持多繼承么?
    • Java類中不支持多繼承,但是可以多實(shí)現(xiàn),所以接口的擴(kuò)展性比較好,實(shí)際開(kāi)發(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)造方法

    • 抽象類中可以有普通成員變量,接口中沒(méi)有普通成員變量;

    • 抽象類中可以有非抽象的方法,接口中的方法都必須是抽象的;

    • 抽象類中的方法可以是public,protected類型,接口中的方法只能是public類型的,切 默認(rèn)為public abstract類型;

    • 抽象類中可以有靜態(tài)方法,接口中不能有靜態(tài)方法;

    • 抽象類中的靜態(tài)變量訪問(wèn)類型可以是任意的,但接口中的靜態(tài)變量只能是public static final 類型。

    • .一個(gè)類可以實(shí)現(xiàn)多個(gè)接口,但一個(gè)類只能繼承一個(gè)抽象類;

  • 應(yīng)用區(qū)別:

    • 接口更多是在系統(tǒng)架構(gòu)方面發(fā)揮作用,主要用于定義模塊之間的通信契約;而抽象類在代碼方法 發(fā)揮作用,可以使用代碼塊的重用;

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ù)、返回值相同。
  • 子類方法不能縮小父類方法的訪問(wèn)權(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)
    • 更加靈活
  • 弊端:
    • 不能使用子類的特有內(nèi)容
2.代碼中如何實(shí)現(xiàn)多態(tài)

實(shí)現(xiàn)多態(tài)主要有以下三種方式:

  • 接口實(shí)現(xiàn)

  • 繼承父類重寫方法

  • 同一類中進(jìn)行方法重載

3.Java 中實(shí)現(xiàn)多態(tài)的機(jī)制是什么?
  • 父類對(duì)象指向子類引用

內(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)部類提供了更好的封裝,除了該外圍類,其他類都不能訪問(wèn)。
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)境中訪問(wèn)非static變量?
  • static變量在Java中是屬于類的,它在所有的實(shí)例中的值是一樣的。當(dāng)類被Java虛擬機(jī)載入的時(shí)候,會(huì)對(duì)static變量進(jìn)行初始化。如果你的代碼嘗試不用實(shí)例來(lái)訪問(wèn)非static的變量,編譯器會(huì)報(bào)錯(cuò),因?yàn)檫@些變量還沒(méi)有被創(chuàng)建出來(lái),還沒(mé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)問(wèn)s5==s2返回什么?
  • 返回false。在編譯過(guò)程中,編譯器會(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)值

    • byte、short、int、long的默認(rèn)值為0

    • float、double默認(rèn)值為0.0

    • char默認(rèn)值為空

    • boolean默認(rèn)值為false

  • 所占字節(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è)類,以及常用的方法?
  • .java.lang.string

  • substring(),indexOf(),concat(),endswith(),length(),replace()

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ò)誤或者硬件問(wèn)題,不能指望程序來(lái)處理這樣的問(wèn)題,除了退出運(yùn)行外別無(wú)選擇,它是Java虛擬機(jī)拋出的。
  • exception 表示程序需要捕捉、需要處理的異常,是由與程序設(shè)計(jì)的不完善而出現(xiàn)的問(wèn)題,程序必須處理的問(wè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)沒(méi)有去處理過(guò)NullPointerException,而且這個(gè)異常還是最常見(jiàn)的異常之一。
  • 出現(xiàn)運(yùn)行時(shí)異常的時(shí)候,程序會(huì)將異常一直向上拋,一直拋到遇到處理代碼,如果沒(méi)有catch塊進(jìn)行處理,到了最上層,如果是多線程就有Thread.run()拋出,如果不是多線程那么就由main.run()拋出。拋出之后,如果是線程,那么該線程也就終止了,如果是主程序,那么該程序也就終止了。
  • 其實(shí)運(yùn)行時(shí)異常的也是繼承自Exception,也可以用catch塊對(duì)其處理,只是我們一般不處理罷了,也就是說(shuō),如果不對(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通過(guò)面向?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的異常處理是通過(guò)5個(gè)關(guān)鍵詞來(lái)實(shí)現(xiàn)的:try catch throw throws finally。

一般情況下是用try來(lái)執(zhí)行一段程序,如果出現(xiàn)異常,系統(tǒng)會(huì)拋出(throws),我們可以通過(guò)它的類型來(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)行記錄,通過(guò)調(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í)行。就算是沒(méi)有catch語(yǔ)句同時(shí)又拋出異常的情況下,finally代碼塊仍然會(huì)被執(zhí)行。最后要說(shuō)的是,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中沒(méi)有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)集合中沒(méi)有某個(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底層通過(guò)數(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方法底層如 果增加的元素超過(guò)了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ù)該過(guò)程;
  • LinkedList底層通過(guò)雙向鏈表實(shí)現(xiàn),取元素時(shí)需要進(jìn)行前項(xiàng)或后項(xiàng)的遍歷,插入元素時(shí)只需要記錄本項(xiàng)的前后 項(xiàng)即可,所以插入快查詢慢;
  • ArrayList和LinkedList底層方法都沒(méi)有加synchronized關(guān)鍵詞,多線程訪問(wè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沒(méi)有實(shí)現(xiàn)synchronized線程非安全,HashTable實(shí)現(xiàn)了synchronized線程安全;
    • HashMap允許key和value為null,而HashTable不允許
  • 底層原理:數(shù)組+鏈表實(shí)現(xiàn)
  • ConcurrentHashMap鎖分段技術(shù):HashTable效率低下的原因,是因?yàn)樗L問(wèn)HashTable的線程都必須競(jìng)爭(zhēng)同一把鎖,那假如容器中有多把鎖,每一把鎖用于鎖住容器中的一部分?jǐn)?shù)據(jù),那么當(dāng)多線程訪問(wèn)容器中不同的數(shù)據(jù)時(shí),線程間就不會(huì)存在鎖競(jìng)爭(zhēng),從而提高并發(fā)訪問(wèn)率;ConcurrentHashMap使用的就是鎖分段技術(shù),首先將數(shù)據(jù)分成一段一段的存儲(chǔ),然后給每一段數(shù)據(jù)配一把鎖,當(dāng)一個(gè)線程占用鎖訪問(wèn)其中一個(gè)數(shù)據(jù)時(shí),其他段的數(shù)據(jù)也能被其他線程訪問(wèn);
  • 實(shí)現(xiàn)TreeMap
4.什么是迭代器(Iterator)?
  • Iterator接口提供了很多對(duì)集合元素進(jìn)行迭代的方法。每一個(gè)集合類都包含了可以返回迭代器實(shí)例的迭代方法。迭代器可以在迭代的過(guò)程中刪除底層集合的元素,但是不可以直接調(diào)用集合的remove(Object Obj)刪除,可以通過(guò)迭代器的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),地址是任意的,所以在開(kāi)辟內(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ì)此訪問(wèn)的情況下選用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)榫€程安全的問(wèn)題,HashMap效率比HashTable的要高。
  • Hashtable是同步的,而HashMap不是。因此,HashMap更適合于單線程環(huán)境,而Hashtable適合于多線程環(huán)境。

一般現(xiàn)在不建議用HashTable

  • 是HashTable是遺留類,內(nèi)部實(shí)現(xiàn)很多沒(méi)優(yōu)化和冗余
  • 即使在多線程環(huán)境下,現(xiàn)在也有同步的ConcurrentHashMap替代,沒(méi)有必要因?yàn)槭嵌嗑€程而用HashTable。
11.List 和 Set 區(qū)別?

List,Set都是繼承自Collection接口

  • List特點(diǎn):
    • 元素有放入順序
    • 元素可重復(fù)
  • Set特點(diǎn):
    • 元素?zé)o放入順序
    • 元素不可重復(fù)
    • 重復(fù)元素會(huì)覆蓋掉

(注意:元素雖然無(wú)放入順序,但是元素在set中的位置是有該元素的HashCode決定的,其位置其實(shí)是固定的,加入Set 的Object必須定義equals()方法 ,另外list支持for循環(huán),也就是通過(guò)下標(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.有沒(méi)有可能兩個(gè)不相等的對(duì)象有相同的hashcode?
  • 有可能,(通話,重地)兩個(gè)不相等的對(duì)象可能會(huì)有相同的 hashcode 值,這就是為什么在 hashmap 中會(huì)有沖突。如果兩個(gè)對(duì)象相等,必須有相同的hashcode 值,反之不成立。
16.HashMap、LinkedHashMap、TreeMap的區(qū)別?
  • HashMap是根據(jù)鍵的hashcode值存儲(chǔ)數(shù)據(jù),根據(jù)鍵可以直接獲取它的值,具有很快的訪問(wèn)速度,取得的數(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í)候得到的是排序過(guò)的記錄。
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ǔ)位置,如果該位置上沒(méi)有元素,就會(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一致,同樣沒(méi)有鎖保護(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)景不同

  • 自然排序能滿足大部分情況

  • 存儲(chǔ)沒(méi)有修改權(quán)限的類時(shí)可以使用

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í)期的問(wèn)題提前到了編譯期間
  • 避免了強(qiáng)制類型轉(zhuǎn)換
2.泛型用在什么地方?
  • 類,方法,接口
3.如何使用泛型類?
  • 創(chuàng)建泛型類對(duì)象時(shí),必須要給這個(gè)泛型確定具體的數(shù)據(jù)類型

樹(shù)

1.什么是二叉樹(shù)?
  • 任意節(jié)點(diǎn)的子節(jié)點(diǎn)不超過(guò)2
2.什么是二叉查找樹(shù)?
  • 每個(gè)節(jié)點(diǎn)最多有兩個(gè)子節(jié)點(diǎn),左邊比當(dāng)前節(jié)點(diǎn)小,右邊比當(dāng)前節(jié)點(diǎn)大
3.什么是平衡二叉樹(shù)?
  • 二叉樹(shù)左右子樹(shù)的樹(shù)高差不超過(guò)1,任意節(jié)點(diǎn)的左右子樹(shù)都是平衡二叉樹(shù)
  • 通過(guò)左旋右旋保持樹(shù)的平衡

序列化

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ā)的問(wèn)題。
  • 反序列化的過(guò)程,則是和序列化相反的過(guò)程。
  • 另外,我們不能將序列化局限在 Java 對(duì)象轉(zhuǎn)換成二進(jìn)制數(shù)組,例如說(shuō),我們將一個(gè) Java 對(duì)象,轉(zhuǎn)換成 JSON 字符串,或者 XML 字符串,這也可以理解為是序列化。
2.如何實(shí)現(xiàn) Java 序列化?

將需要被序列化的類,實(shí)現(xiàn) Serializable 接口,該接口沒(méi)有需要實(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))。

反序列化

  • 要恢復(fù)的話則用輸入流。
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é)流?
  • 字節(jié)流
5.如何在讀寫文件時(shí)指定字符集?

jdk11之前:

  • 使用轉(zhuǎn)換流InputStreamReader(輸入轉(zhuǎn)換流)字節(jié)轉(zhuǎn)換字符橋梁/OutputStreamWriter(輸出轉(zhuǎn)換流)字符轉(zhuǎn)字節(jié)橋梁

jdk11之后

  • 直接使用FileReader指定
6.字符緩沖流特有方法?
  • readLine():讀取一整行,到達(dá)尾處為null
  • newLine():跨平臺(tái)換行
7.為什么使用對(duì)象流?
  • 在開(kāi)發(fā)中,經(jīng)常需要將對(duì)象的信息保存到磁盤中,如果使用前面所學(xué)的知識(shí)來(lái)實(shí)現(xiàn),會(huì)非常的繁瑣。使用對(duì)象流就非常的方便
  • 對(duì)象操作流可以將對(duì)象以字節(jié)的形式寫到本地文件中,直接打開(kāi)是看不懂的,需要時(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:
    • 可以直接調(diào)用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)用,沒(méi)有新的線程啟動(dòng),start()方法才會(huì)啟動(dòng)新線程。

6.Java中Runnable和Callable有什么不同?
  • Runnable和Callable都代表那些要在不同的線程中執(zhí)行的任務(wù)。Runnable從JDK1.0開(kāi)始就有了,Callable是在JDK1.5增加的。它們的主要區(qū)別是Callable的 call() 方法可以返回值和拋出異常,而Runnable的run()方法沒(méi)有這些功能。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)能被其它線程可見(jiàn)提供了保證,它們之間是先行發(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ù)有限。為了避免這些問(wèn)題,在程序啟動(dòng)的時(shí)候就創(chuàng)建若干線程來(lái)響應(yīng)處理,它們被稱為線程池,里面的線程叫工作線程。從JDK1.5開(kāi)始,Java API提供了Executor框架讓你可以創(chuàng)建不同的線程池。比如單線程池,每次處理一個(gè)任務(wù);數(shù)目固定的線程池或者是緩存線程池(一個(gè)適合很多生存期短的任務(wù)的程序的可擴(kuò)展線程池)
13.如何寫代碼來(lái)解決生產(chǎn)者消費(fèi)者問(wèn)題?
  • 在現(xiàn)實(shí)中你解決的許多線程問(wèn)題都屬于生產(chǎn)者消費(fèi)者模型,就是一個(gè)線程生產(chǎn)任務(wù)供其它線程進(jìn)行消費(fèi),你必須知道怎么進(jìn)行線程間通信來(lái)解決這個(gè)問(wèn)題。比較低級(jí)的辦法是用wait和notify來(lái)解決這個(gè)問(wèn)題,比較贊的辦法是用Semaphore 或者 BlockingQueue來(lái)實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模型
14.Java多線程中的死鎖

死鎖是指兩個(gè)或兩個(gè)以上的進(jìn)程在執(zhí)行過(guò)程中,因爭(zhēng)奪資源而造成的一種互相等待的現(xiàn)象,若無(wú)外力作用,它們都將無(wú)法推進(jìn)下去。這是一個(gè)嚴(yán)重的問(wè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)說(shuō),它是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)訪問(wèn)某個(gè)對(duì)象的synchronized方法的時(shí)候,表示將對(duì)象上鎖,此時(shí)其它任何線程都無(wú)法再去訪問(wèn)synchronized方法了,直到之前的那個(gè)線程執(zhí)行方法完畢后(或者是拋出了異常),那么將該對(duì)象的鎖釋放掉,其他線程才有可能再去訪問(wèn)該synchronized方法。

  • 注意1:
    • 如果一個(gè)對(duì)象有多個(gè)synchronized方法,某一個(gè)時(shí)刻某個(gè)線程已經(jīng)進(jìn)入到了某個(gè)synchronized方法,那么在該方法沒(méi)有執(zhí)行完畢前,其它線程是無(wú)法訪問(wèn)該對(duì)象的任何synchronzed方法的。
  • 注意2:
    • 如果某個(gè)Synchronized方法是static的,那么當(dāng)線程訪問(wèn)該方法時(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)線程分別訪問(wèn)同一個(gè)類的兩個(gè)對(duì)象的兩個(gè)static Synchronized方法的時(shí)候,他們執(zhí)行的順序也是順序的,也就是說(shuō)一個(gè)線程先去執(zhí)行方法,執(zhí)行完畢后另一個(gè)線程才開(kāi)始執(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鎖定是通過(guò)代碼實(shí)現(xiàn)的。
  • 在性能上來(lái)說(shuō),如果競(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。所以說(shuō),在具體使用時(shí)要根據(jù)適當(dāng)情況選擇。
  • 鎖的機(jī)制不一樣。synchronized獲得鎖和釋放的方式都是在塊結(jié)構(gòu)中,而且是自動(dòng)釋放鎖。而Lock則需要開(kāi)發(fā)人員手動(dòng)去釋放,并且必須在finally塊中釋放,否則會(huì)引起死鎖問(wèn)題的發(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í),如果沒(méi)有主動(dòng)通過(guò)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ì)該成員變量是彼此影響的,也就是說(shuō)一個(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)鍵字的作用是?
  • 保證變量的可見(jià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ā)生許多奇奇怪怪的線程安全問(wèn)題了,volatile就出來(lái)了,它保證讀取數(shù)據(jù)時(shí)只從主存空間讀取,修改數(shù)據(jù)直接修改到主存空間中去,這樣就保證了這個(gè)變量對(duì)多個(gè)操作線程的可見(jiàn)性了。換句話說(shuō),被volatile修飾的變量,能保證該變量的 單次讀或者單次寫 操作是原子的。
  • 但是線程安全是兩方面需要的 原子性(指的是多條操作)和可見(jiàn)性。volatile只能保證可見(jiàn)性,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í)開(kāi)始執(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)線程安全問(wè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è)過(guò)程稱為自旋
30.synchronized和CAS的區(qū)別?
  • 相同點(diǎn):
    • 在多線程情況下,都可以保證共享數(shù)據(jù)的安全性。
  • 不同點(diǎn):
    • synchronized總是從最壞的角度出發(fā),認(rèn)為每次獲取數(shù)據(jù)的時(shí)候,別人都有可能修改。所以在每 次操作共享數(shù)據(jù)之前,都會(huì)上鎖。(悲觀鎖)
    • CAS是從樂(lè)觀的角度出發(fā),假設(shè)每次獲取數(shù)據(jù)別人都不會(huì)修改,所以不會(huì)上鎖。只不過(guò)在修改共享數(shù)據(jù)的時(shí)候,會(huì)檢查一下,別人有沒(méi)有修改過(guò)這個(gè)數(shù)據(jù)。如果別人修改過(guò),那么我再次獲取現(xiàn)在最新的值。如果別人沒(méi)有修改過(guò),那么我現(xiàn)在直接修改共享數(shù)據(jù)的值.(樂(lè)觀鎖)
31.并發(fā)容器Hashtable和ConcurrentHashMap特點(diǎn)?
  • Hashtable:
    • Hashtable采取悲觀鎖synchronized的形式保證數(shù)據(jù)的安全性

    • 只要有線程訪問(wèn),會(huì)將整張表全部鎖起來(lái),所以Hashtable效率低下

  • ConcurrentHashMap:
    • 采用sychronized+cas

    • 線程安全,效率比Hashtable高,比HashMap低 

反射類加載器

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)單說(shuō),反射機(jī)制值得是程序在運(yùn)行時(shí)能夠獲取自身的信息。在java中,只要給定類的名字,那么就可以通過(guò)反射機(jī)制來(lái)獲得類的所有信息。
3.哪里用到反射機(jī)制?
  • Spring 框架的 IoC 基于反射創(chuàng)建對(duì)象和設(shè)置依賴屬性。
  • Spring MVC 的請(qǐng)求調(diào)用對(duì)應(yīng)方法,也是通過(guò)反射。
  • JDBC 的 Class#forName(String className) 方法,也是使用反射。
4.反射機(jī)制的優(yōu)缺點(diǎn)?
  • 靜態(tài)編譯:
    • 在編譯時(shí)確定類型,綁定對(duì)象,即通過(guò)
  • 動(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的開(kāi)發(fā)中它的靈活性就表現(xiàn)的十分明顯。比如,一個(gè)大型的軟件,不可能一次就把把它設(shè)計(jì)的很完美,當(dāng)這個(gè)程序編譯后,發(fā)布了,當(dāng)發(fā)現(xiàn)需要更新某些功能時(shí),我們不可能要用戶把以前的卸載,再重新安裝新的版本,假如這樣的話,這個(gè)軟件肯定是沒(méi)有多少人用的。采用靜態(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í)是通過(guò)三次握手協(xié)議,保證跟服務(wù)器之間的連接

  • 針對(duì)客戶端來(lái)講,是往外寫的,所以是輸出流 針對(duì)服務(wù)器來(lái)講,是往里讀的,所以是輸入流

  • read方法也是阻塞的

  • 客戶端在關(guān)流的時(shí)候,還多了一個(gè)往服務(wù)器寫結(jié)束標(biāo)記的動(dòng)作

  • 最后一步斷開(kāi)連接,通過(guò)四次揮手協(xié)議保證連接終止

 

web階段

jsp相關(guān)

1.jsp內(nèi)置對(duì)象和EL內(nèi)置對(duì)象的區(qū)別與聯(lián)系

jsp內(nèi)置對(duì)象:

  • jsp內(nèi)可以在<%%>中直接使用的對(duì)象9個(gè)

EL表達(dá)式內(nèi)置對(duì)象:

  • jsp呢可以在${}中直接使用的對(duì)象11個(gè)

pageContext對(duì)象是二者唯一相同的對(duì)象,其他都是各自獨(dú)立的對(duì)象

2.說(shuō)一下 jsp 的 4 種作用域?

JSP中的四種作用域包括page、request、session和application,具體來(lái)說(shuō):

  • 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ì)象。大家只要打開(kāi)jsp編譯過(guò)后生成的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)的過(guò)程。 例如: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:通過(guò)該對(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ū)別?

 

  • post:
    • 數(shù)據(jù)不會(huì)顯示在地址欄

 

    • 安全

    • 大小無(wú)限制

    • 可以提交二進(jìn)制文件

  • get:

    • 數(shù)據(jù)顯示在地址欄

    • 不安全

    • get方式提交有大小限制(約4kb)

2.相對(duì)路徑和絕對(duì)路徑?
  • 相對(duì)路徑

    概念:

    • 不以"/"開(kāi)頭,而是根據(jù)資源的相對(duì)位置關(guān)系的道德路徑

    寫法:

    • 從路徑不一樣的位置開(kāi)始寫 例如:bbb/bbb ..bbb/b.html (../表示退一級(jí))

  • 絕對(duì)路徑

    概念:

    • 以"/"為開(kāi)頭的路徑就是絕對(duì)路徑.該路徑不會(huì)隨著位置變化而變化

    寫法:

3.Cookie和session的區(qū)別?

session是基于cookie

多次請(qǐng)求之間共享數(shù)據(jù)

  • cookie:
    • 數(shù)據(jù)存儲(chǔ)于客戶端--不安全

    • 只能存字符串

    • 大小有限制

  • session:
    • 數(shù)據(jù)存儲(chǔ)于服務(wù)器端--安全

    • 類型無(wú)限制

    • 大小無(wú)限制

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才行)

  • 鈍化:
    • 概念:序列化。把長(zhǎng)時(shí)間不用,但還不到過(guò)期時(shí)間的 HttpSession 進(jìn)行序列化,寫到磁盤上

    • 時(shí)機(jī):當(dāng)訪問(wèn)量很大時(shí),服務(wù)器會(huì)根據(jù) getLastAccessTime 來(lái)進(jìn)行排序,對(duì)長(zhǎng)時(shí)間不用,但是還沒(méi)到過(guò)期時(shí)間的 HttpSession 進(jìn)行序列化。
  • 活化:
    • 概念:相反的狀態(tài),從磁盤讀取到內(nèi)存

    • 時(shí)機(jī):tomcat重新啟動(dòng)時(shí)會(huì)將會(huì)話加載到內(nèi)存

 

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)站訪問(wèn)量。那么會(huì)產(chǎn)生很多的session,該怎么解決?

session默認(rèn)保存在內(nèi)存中,內(nèi)存資源寶貴,session數(shù)據(jù)量大導(dǎo)致內(nèi)存利用率高,以下方案解決session內(nèi)存存儲(chǔ)問(wèn)題:

  • 可以設(shè)置session超時(shí)時(shí)間,達(dá)到超時(shí)時(shí)間session自動(dòng)清空

    <session-config>

    <session-timeout>20</session-timeout>

    </session-config>

  • 將session中的數(shù)據(jù)序列化到硬盤中
  • 不使用session,使用cookie(此方法存在安全性問(wèn)題)
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èn)的網(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èn)網(wǎng)站創(chuàng)建,用戶離開(kāi)該網(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í)例化后,生命周期開(kāi)始。通過(guò)調(diào)用servlet的init()方法進(jìn)行servlet的初始化。通過(guò)調(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過(guò)濾器的作用?
  • 打印一些請(qǐng)求參數(shù)到日志中
  • 授權(quán)請(qǐng)求訪問(wèn)資源
  • 在將請(qǐng)求提交給servlet之前,對(duì)request請(qǐng)求頭或請(qǐng)求體進(jìn)行一些格式化的處理
  • 將響應(yīng)數(shù)據(jù)進(jìn)行壓縮再返回給瀏覽器。
  • 解決亂碼問(wèn)題。
5.servlet監(jiān)聽(tīng)器的作用?
  • 監(jiān)聽(tīng)客戶端的請(qǐng)求,服務(wù)器端的操作等 。通過(guò)監(jiān)聽(tīng)器,可以自動(dòng)激發(fā)一些操作,比如監(jiān)聽(tīng)在線的用戶數(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了,注意,有讀者可能說(shuō)ServletConext的setAttribute不是可以設(shè)置對(duì)象嗎?但是這是在servlet創(chuàng)建之后才能調(diào)用的方法,如果希望web應(yīng)用一啟動(dòng)就產(chǎn)生初始參數(shù)必須使用監(jiān)聽(tīng)器)。
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ù)的值越小,說(shuō)明越先被加載。
8.HttpServlet為什么聲明為抽象類?
  • httpServlet類雖然是抽象類但卻沒(méi)有抽象方法,之所以這樣設(shè)計(jì),是因?yàn)閐oget,dopost等方法并沒(méi)有業(yè)務(wù)邏輯,開(kāi)發(fā)者至少應(yīng)該重寫一個(gè)service中的方法,這就是我們不能實(shí)例化HttpServlet的原因。
9.redirect(重定向)和forward(請(qǐng)求轉(zhuǎn)發(fā))區(qū)別?

重定向:

  • 兩次請(qǐng)求

  • 地址欄發(fā)生變化

  • 不可以使用request域的共享數(shù)據(jù)

  • 不可以訪問(wèn)/WEB_INF下的資源

轉(zhuǎn)發(fā):

  • 一次請(qǐng)求

  • 地址欄不發(fā)生變化

  • 可以使用request域的共享數(shù)據(jù)

  • 可以訪問(wèn)/WEB_INF下的資源

補(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之間的通信,我們可以通過(guò)set/get方法為web應(yīng)用設(shè)置或取出屬性值。servlet提供3個(gè)域(和jsp區(qū)分開(kāi)來(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等方法是存在線程安全問(wèn)題的,因?yàn)閟ervlet容器為每一個(gè)客戶端請(qǐng)求都創(chuàng)建一個(gè)線程,這些線程在同一時(shí)刻可能訪問(wèn)同一個(gè)servlet的service方法,所以我們?cè)谑褂眠@些方法時(shí)務(wù)必小心。
12.如何創(chuàng)建線程安全的servlet?(SingleThreadModel方法不算)
  1. 盡量使用局部變量,減少全局變量的使用。
  2. 對(duì)于共享變量,加上關(guān)鍵字synchronized。

注:servlet中常見(jiàn)線程安全與不安全的對(duì)象

  • 線程安全:ServletRequest,ServletResponse
  • 線程不安全:ServletContext,HttpSession。

對(duì)于 ServletContext,我們應(yīng)盡量減少該對(duì)象中屬性的修改。

而HttpSession對(duì)象在用戶會(huì)話期間存在,只能在處理屬于同一個(gè)Session的請(qǐng)求的線程中被訪問(wèn),因此Session對(duì)象的屬性訪問(wèn)理論上是線程安全的。但是當(dāng)用戶打開(kāi)多個(gè)同屬于一個(gè)進(jìn)程的瀏覽器窗口,在這些窗口的訪問(wèn)屬于同一個(gè)Session,會(huì)出現(xiàn)多次請(qǐng)求,需要多個(gè)工作線程來(lái)處理請(qǐng)求,可能造成同時(shí)多線程讀寫屬性

13.是否有必要重寫service方法?
  • 一般情況下是沒(méi)有必要的,因?yàn)閟ervice方法會(huì)根據(jù)請(qǐng)求的類型(get、post等)將請(qǐng)求分發(fā)給doxxx方法去執(zhí)行。即使我們需要在處理請(qǐng)求之前需要做一些額外的事,我們也可以通過(guò)過(guò)濾器或監(jiān)聽(tīng)器完成。
14.servlet包裝類有什么用?
  • servletAPI提供了兩個(gè)包裝類:HttpServletRequestWrapper類和HttpServletResponseWrapper類,這些包裝類幫助開(kāi)發(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ū)別?
  1. 每個(gè)servlet都會(huì)有自己獨(dú)有的servletConfig對(duì)象而servletContext對(duì)象是整個(gè)web應(yīng)用共享的。
  2. servletConfig提供servlet的初始化參數(shù)(init-param),僅該servlet可以訪問(wèn)。而servletContext提供的初始化參數(shù)整個(gè)web應(yīng)用的所有servlet都可以訪問(wèn)。
  3. servletContext對(duì)象提供了setAttribute方法設(shè)置共享參數(shù),而servletConfig并沒(méi)有對(duì)應(yīng)的set方法。
18.PrintWriter和ServletOutPutStream類有什么區(qū)別?
  • PrintWriter是字符流,ServletOutputStream是字節(jié)流。可以通過(guò) PrintWriter向?yàn)g覽器輸出字符數(shù)組或者是字符串。也可以通過(guò)ServletOutPutStream向?yàn)g覽器端輸出字節(jié)數(shù)組。
  • PrintWriter對(duì)象在servlet中可以通過(guò)response.getWriter()方法獲取
  • ServletOutputStream對(duì)象通過(guò)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中沒(méi)有內(nèi)置對(duì)象,jsp中的內(nèi)置對(duì)象都是必須通過(guò)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+樹(shù)索引等,而我們經(jīng)常使用的InnoDB存儲(chǔ)引擎的默認(rèn)索引實(shí)現(xiàn)為:B+樹(shù)索引.
3.在建立索引的時(shí)候,都有哪些需要考慮的因素呢?
  • 建立索引的時(shí)候一般要考慮到字段的使用頻率,經(jīng)常作為條件進(jìn)行查詢的字段比較適合.如果需要建立聯(lián)合索引的話,還需要考慮聯(lián)合索引中的順序.此外也要考慮其他方面,比如防止過(guò)多的所有對(duì)表造成太大的壓力.這些都和實(shí)際的表結(jié)構(gòu)以及查詢方式有關(guān).
4.關(guān)心過(guò)業(yè)務(wù)系統(tǒng)里面的sql耗時(shí)嗎?統(tǒng)計(jì)過(guò)慢查詢嗎?對(duì)慢查詢都怎么優(yōu)化過(guò)?

在業(yè)務(wù)系統(tǒng)中,除了使用主鍵進(jìn)行的查詢,其他的我都會(huì)在測(cè)試庫(kù)上測(cè)試其耗時(shí),慢查詢的統(tǒng)計(jì)主要由運(yùn)維在做,會(huì)定期將業(yè)務(wù)中的慢查詢反饋給我們.

慢查詢的優(yōu)化首先要搞明白慢的原因是什么? 是查詢條件沒(méi)有命中索引?是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樹(shù),B-,B+,B*?
  • B樹(shù):二叉樹(shù),每個(gè)結(jié)點(diǎn)只存儲(chǔ)一個(gè)關(guān)鍵字,等于則命中,小于走左結(jié)點(diǎn),大于走右結(jié)點(diǎn);
  • B-樹(shù):多路搜索樹(shù),每個(gè)結(jié)點(diǎn)存儲(chǔ)M/2到M個(gè)關(guān)鍵字,非葉子結(jié)點(diǎn)存儲(chǔ)指向關(guān)鍵字范圍的子結(jié)點(diǎn); 所有關(guān)鍵字在整顆樹(shù)中出現(xiàn),且只出現(xiàn)一次,非葉子結(jié)點(diǎn)可以命中;
  • B+樹(shù):在B-樹(shù)基礎(chǔ)上,為葉子結(jié)點(diǎn)增加鏈表指針,所有關(guān)鍵字都在葉子結(jié)點(diǎn)中出現(xiàn),非葉子結(jié)點(diǎn)作為葉子結(jié)點(diǎn)的索引;B+樹(shù)總是到葉子結(jié)點(diǎn)才命中;
  • B*樹(shù):在B+樹(shù)基礎(chǔ)上,為非葉子結(jié)點(diǎn)也增加鏈表指針,將結(jié)點(diǎn)的最低利用率從1/2提高到2/3;
6.MySQL優(yōu)化策略?
  • 開(kāi)啟查詢緩存,優(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ǔ)過(guò)程,是一種運(yùn)行在后臺(tái)的SQL語(yǔ)句集合,我們可以從使用 prepared statements 獲得很多好處,無(wú)論是性能問(wèn)題還是安全問(wèn)題。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ì)說(shuō)一下嗎?
  • A=Atomicity
    • 原子性,就是上面說(shuō)的,要么全部成功,要么全部失敗.不可能只執(zhí)行一部分操作.
  • C=Consistency
    • 系統(tǒng)(數(shù)據(jù)庫(kù))總是從一個(gè)一致性的狀態(tài)轉(zhuǎn)移到另一個(gè)一致性的狀態(tài),不會(huì)存在中間狀態(tài).
  • I=Isolation
    • 隔離性: 通常來(lái)說(shuō):一個(gè)事務(wù)在完全提交之前,對(duì)其他事務(wù)是不可見(jiàn)的.注意前面的通常來(lái)說(shuō)加了紅色,意味著有例外情況.
  • D=Durability
    • 持久性,一旦事務(wù)提交,那么就永遠(yuǎn)是這樣子了,哪怕系統(tǒng)崩潰也不會(huì)影響到這個(gè)事務(wù)的結(jié)果.
2.同時(shí)有多個(gè)事務(wù)在進(jìn)行會(huì)怎么樣呢?

多事務(wù)的并發(fā)進(jìn)行一般會(huì)造成以下幾個(gè)問(wèn)題:

  • 臟讀: A事務(wù)讀取到了B事務(wù)未提交的內(nèi)容,而B(niǎo)事務(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ù).造成"幻覺(jué)".

3.怎么解決這些問(wèn)題呢?MySQL的事務(wù)隔離級(jí)別了解嗎?

MySQL的四種隔離級(jí)別如下:

 

  • READ UNCOMMITTED(未提交讀)

 

    • 這就是上面所說(shuō)的例外情況了,這個(gè)隔離級(jí)別下,其他事務(wù)可以看到本事務(wù)沒(méi)有提交的部分修改.因此會(huì)造成臟讀的問(wèn)題(讀取到了其他事務(wù)未提交的部分,而之后該事務(wù)進(jìn)行了回滾).
    • 這個(gè)級(jí)別的性能沒(méi)有足夠大的優(yōu)勢(shì),但是又有很多的問(wèn)題,因此很少使用.
  • READ COMMITTED(已提交讀)

    • 其他事務(wù)只能讀取到本事務(wù)已經(jīng)提交的部分.這個(gè)隔離級(jí)別有 不可重復(fù)讀的問(wèn)題,在同一個(gè)事務(wù)內(nèi)的兩次讀取,拿到的結(jié)果竟然不一樣,因?yàn)榱硗庖粋€(gè)事務(wù)對(duì)數(shù)據(jù)進(jìn)行了修改.
  • REPEATABLE READ(可重復(fù)讀)

    • 可重復(fù)讀隔離級(jí)別解決了上面不可重復(fù)讀的問(wèn)題(看名字也知道),但是仍然有一個(gè)新問(wèn)題,就是 幻讀,當(dāng)你讀取id> 10 的數(shù)據(jù)行時(shí),對(duì)涉及到的所有行加上了讀鎖,此時(shí)例外一個(gè)事務(wù)新插入了一條id=11的數(shù)據(jù),因?yàn)槭切虏迦氲?所以不會(huì)觸發(fā)上面的鎖的排斥,那么進(jìn)行本事務(wù)進(jìn)行下一次的查詢時(shí)會(huì)發(fā)現(xiàn)有一條id=11的數(shù)據(jù),而上次的查詢操作并沒(méi)有獲取到,再進(jìn)行插入就會(huì)有主鍵沖突的問(wèn)題.
  • SERIALIZABLE(可串行化)

    • 這是最高的隔離級(jí)別,可以解決上面提到的所有問(wèn)題,因?yàn)樗麖?qiáng)制將所以的操作串行執(zhí)行,這會(huì)導(dǎo)致并發(fā)性能極速下降,因此也不是很常用.
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)保證訪問(wèn)的次序,鎖機(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)說(shuō)就是用戶的行為有兩種,一種是來(lái)看房,多個(gè)用戶一起看房是可以接受的. 一種是真正的入住一晚,在這期間,無(wú)論是想入住的還是想看房的都不可以.

鎖的粒度取決于具體的存儲(chǔ)引擎,InnoDB實(shí)現(xiàn)了行級(jí)鎖,頁(yè)級(jí)鎖,表級(jí)鎖.

他們的加鎖開(kāi)銷從大到小,并發(fā)能力也是從大到小.

7.行級(jí)鎖定的優(yōu)點(diǎn)缺點(diǎn)?
  • 優(yōu)點(diǎn):
    • 當(dāng)在許多線程中訪問(wèn)不同的行時(shí)只存在少量鎖定沖突。

    • 回滾時(shí)只有少量的更改

    • 可以長(zhǎng)時(shí)間鎖定單一的行。

  缺點(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í)別鎖定,通過(guò)支持不同的類型鎖定,你也可以很容易地調(diào)節(jié)應(yīng)用程序,因?yàn)槠滏i成本小于行級(jí)鎖定。

8.說(shuō)一下 mysql 的行鎖和表鎖?
  • MyISAM 只支持表鎖,InnoDB 支持表鎖和行鎖,默認(rèn)為行鎖。
    • 表級(jí)鎖:開(kāi)銷小,加鎖快,不會(huì)出現(xiàn)死鎖。鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)量最低。

    • 行級(jí)鎖:開(kāi)銷大,加鎖慢,會(huì)出現(xiàn)死鎖。鎖力度小,發(fā)生鎖沖突的概率小,并發(fā)度最高。

表設(shè)計(jì)相關(guān)

1. 為什么要盡量設(shè)定一個(gè)主鍵?
  • 主鍵是數(shù)據(jù)庫(kù)確保數(shù)據(jù)行在整張表唯一性的保障,即使業(yè)務(wù)上本張表沒(méi)有主鍵,也建議添加一個(gè)自增長(zhǎng)的ID列作為主鍵.設(shè)定了主鍵之后,在后續(xù)的刪改查的時(shí)候可能更加快速以及確保操作數(shù)據(jù)范圍安全.
2.主鍵使用自增ID還是UUID?
  • 推薦使用自增ID,不要使用UUID.
    • 因?yàn)樵贗nnoDB存儲(chǔ)引擎中,主鍵索引是作為聚簇索引存在的,也就是說(shuō),主鍵索引的B+樹(shù)葉子節(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)于主鍵是聚簇索引,如果沒(méi)有主鍵,InnoDB會(huì)選擇一個(gè)唯一鍵來(lái)作為聚簇索引,如果沒(mé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填充.也就是說(shuō),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ì)于沒(méi)有主鍵的表,在查詢和索引定義上有一定的影響;

  • 避免表字段運(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ū)別?
  • InnoDB支持事物,而MyISAM不支持事物

  • InnoDB支持行級(jí)鎖,而MyISAM支持表級(jí)鎖

  • InnoDB支持MVCC, 而MyISAM不支持

  • InnoDB支持外鍵,而MyISAM不支持

  • InnoDB不支持全文索引,而MyISAM支持。

3.什么是存儲(chǔ)過(guò)程?有哪些優(yōu)缺點(diǎn)?

存儲(chǔ)過(guò)程是一些預(yù)編譯的SQL語(yǔ)句。1、更加直白的理解:存儲(chǔ)過(guò)程可以說(shuō)是一個(gè)記錄集,它是由一些T-SQL語(yǔ)句組成的代碼塊,這些T-SQL語(yǔ)句代碼像一個(gè)方法一樣實(shí)現(xiàn)一些功能(對(duì)單表或多表的增刪改查),然后再給這個(gè)代碼塊取一個(gè)名字,在用到這個(gè)功能的時(shí)候調(diào)用他就行了。2、存儲(chǔ)過(guò)程是一個(gè)預(yù)編譯的代碼塊,執(zhí)行效率比較高,一個(gè)存儲(chǔ)過(guò)程替代大量T_SQL語(yǔ)句 ,可以降低網(wǎng)絡(luò)通信量,提高通信速率,可以一定程度上確保數(shù)據(jù)安全

但是,在互聯(lián)網(wǎng)項(xiàng)目中,其實(shí)是不太推薦存儲(chǔ)過(guò)程的,比較出名的就是阿里的《Java開(kāi)發(fā)手冊(cè)》中禁止使用存儲(chǔ)過(guò)程,我個(gè)人的理解是,在互聯(lián)網(wǎng)項(xiàng)目中,迭代太快,項(xiàng)目的生命周期也比較短,人員流動(dòng)相比于傳統(tǒng)的項(xiàng)目也更加頻繁,在這樣的情況下,存儲(chǔ)過(guò)程的管理確實(shí)是沒(méi)有那么方便,同時(shí),復(fù)用性也沒(méi)有寫在服務(wù)層那么好.

4.說(shuō)一說(shuō)三個(gè)范式?
  • 第一范式: 每個(gè)列都不可以再拆分.
  • 第二范式: 非主鍵列完全依賴于主鍵,而不能是依賴于主鍵的一部分.
  • 第三范式: 非主鍵列只依賴于主鍵,不依賴于其他非主鍵.

在設(shè)計(jì)數(shù)據(jù)庫(kù)結(jié)構(gòu)的時(shí)候,要盡量遵守三范式,如果不遵守,必須有足夠的理由.比如性能. 事實(shí)上我們經(jīng)常會(huì)為了性能而妥協(xié)數(shù)據(jù)庫(kù)的設(shè)計(jì).

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多