Java 常見(jiàn)概念

1.HashMap和HashTable的區(qū)別

  • [x] HashMap去掉了contains方法
  • [x] HashTable是同步的(線程安全)
  • [x] HashMap允許空鍵值
  • [x] HashMap執(zhí)行快速失敗機(jī)制
  • [ ] Fast-fail機(jī)制:在使用迭代器的過(guò)程中有其它線程修改了集合對(duì)象結(jié)構(gòu)或元素?cái)?shù)量,都將拋出ConcurrentModifiedException
  • HashMap幾乎可以等價(jià)于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受為null的鍵值(key)和值(value),而Hashtable則不行)。
  • Hashtable和HashMap有幾個(gè)主要的不同:線程安全以及速度。僅在你需要完全的線程安全的時(shí)候使用Hashtable,而如果你使用Java 5或以上的話,請(qǐng)使用ConcurrentHashMap吧。

2.java的線程安全類

Vector、Stack、HashTable、ConcurrentHashMap、Properties

3.java集合框架

  • Collection - List
    • 有順序以線性方式存儲(chǔ),可以存放重復(fù)對(duì)象
  • Collection - List - ArrayList
    • 數(shù)組方式存儲(chǔ)數(shù)據(jù)  索引數(shù)據(jù)快插入數(shù)據(jù)慢  線程不安全
  • Collection - List - LinkedList
    • 雙向鏈表實(shí)現(xiàn)存儲(chǔ)  索引數(shù)據(jù)慢插入數(shù)度較快  線程不安全(比安全性能好)
  • Collection - List - Vector
    • 數(shù)組方式存儲(chǔ)數(shù)據(jù)  索引數(shù)據(jù)快插入數(shù)據(jù)慢  線程安全
  • Collection - List - Vector - Stack
    • 繼承自Vector,實(shí)現(xiàn)一個(gè)后進(jìn)先出的堆棧
  • Collection - Set
    • 無(wú)順序,不包含重復(fù)的元素
  • Collection - Set - HashSet
    • 為快速查找設(shè)計(jì)的Set。存入HashSet的對(duì)象必須定義hashCode()。
  • Collection - Set - TreeSet
    • 保存次序的Set, 底層為樹(shù)結(jié)構(gòu)。使用它可以從Set中提取有序的序列。
  • Collection - Set - LinkedHashSet
    • 具有HashSet的查詢速度,且內(nèi)部使用鏈表維護(hù)元素的順序(插入的次序)。于是在使用迭代器遍歷Set時(shí),結(jié)果會(huì)按元素插入的次序顯示。
  • Map
    • 鍵必須是唯一
  • Map - HashMap
    • HashMap:基于散列表的實(shí)現(xiàn)  允許空鍵空值  線程不安全  (與Hashtable基本一致)
  • Map - TreeMap
    • TreeMap: 基于紅黑樹(shù)數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)  不允許空鍵空值  線程不安全
  • Map - HashTable
    • Hashtable:基于散列表的實(shí)現(xiàn)  允許空鍵空值  線程安全
  • Map - WeakHashMap
    • 改進(jìn)的HashMap,它對(duì)key實(shí)行“弱引用”,如果一個(gè)key不再被外部所引用,那么該key可以被GC回收。
  • Map - LinkedHashMap
    • 具有HashMap的所有特性。
    • 內(nèi)部對(duì)數(shù)據(jù)的存儲(chǔ)也是數(shù)組加鏈表的形式。
    • 多了一個(gè)雙向鏈表來(lái)維護(hù)內(nèi)部數(shù)據(jù)的順序關(guān)系。
  • SparseArray
    • 采用了二分法方式存儲(chǔ)數(shù)據(jù)(安卓的一個(gè)集合類)
    • key必須為int類型,這中情況下的HashMap可以用SparseArray代替
    • 避免了HashMap自動(dòng)裝箱得到內(nèi)存消耗
  • ArrayMap
    • ArrayMap 實(shí)現(xiàn)了implements Map<K, V>接口,所以它也是一個(gè)關(guān)聯(lián)數(shù)組、哈希表
    • 存儲(chǔ)以key->value 結(jié)構(gòu)形式的數(shù)據(jù)。
    • 它也是線程不安全的,允許key為null,value為null
    • 內(nèi)部實(shí)現(xiàn)是基于兩個(gè)數(shù)組
      • 一個(gè)int[]數(shù)組,用于保存每個(gè)item的hashCode.
      • 一個(gè)Object[]數(shù)組,保存key/value鍵值對(duì)。容量是上一個(gè)數(shù)組的兩倍
    • 使用二分查找法得到相應(yīng)的index

在除需要排序時(shí)使用TreeSet,TreeMap外,都應(yīng)使用HashSet,HashMap,因?yàn)樗麄兊男矢摺?/p>

3.1 ArrayList的構(gòu)造函數(shù)有三個(gè)

  1. 無(wú)參構(gòu)造 容量為10
  2. ArrayList(Collections<?extends E> c)構(gòu)造包含指定collection的元素的列表
  3. ArrayList(int initialCapacity) 指定初始容量

3.2 Iterator(迭代器)支持從源集合安全地刪除對(duì)象,防止并發(fā)修改異常(ConcurrentModifiedException)

4.Java垃圾回收機(jī)制

4.1 調(diào)用system.gc() Runtime.getRuntime.gc()

4.2 垃圾回收:釋放那些不再持有任何引用的對(duì)象的內(nèi)存

4.3 怎樣判斷是否需要收集:

  1. 引用計(jì)數(shù)法:對(duì)象沒(méi)有任何引用與之關(guān)聯(lián)(無(wú)法解決循環(huán)引用)
  2. 對(duì)象引用遍歷法:對(duì)象引用遍歷從一組對(duì)象開(kāi)始,沿著對(duì)象圖的每條鏈接,遞歸確定可以到達(dá)的對(duì)象,如果某對(duì)象不能從這些根對(duì)象的一個(gè)(至少一個(gè))到達(dá),則將它作為垃圾收集。

4.4 垃圾回收方法

  1. 標(biāo)記清除法(Mark-Sweeping):易產(chǎn)生內(nèi)存碎片
  2. 復(fù)制回收法(Copying):為了解決Mark-Sweep法而提出,內(nèi)存空間減至一半
  3. 標(biāo)記壓縮法(Mark-Compact):為了解決Copying法的缺陷,標(biāo)記后移動(dòng)到一端再清楚
  4. 分代回收法(GenerationalCollection):新生代對(duì)象存活周期短,需要大量回收對(duì)象,需要復(fù)制的少,執(zhí)行copying算法;老年代對(duì)象存活周期相對(duì)長(zhǎng),回收少量對(duì)象,執(zhí)行mark-compact算法.
    新生代劃分:較大的eden區(qū) 和 2個(gè)survivor區(qū)

4.5 內(nèi)存分配

  • 新生代 |Eden Space|From Space|To Space|
  • 對(duì)象主要分配在新生代的EdenSpace和FromSpace
  • 如果EdenSapce和FromSpace空間不足,則發(fā)起一次GC
  • 若進(jìn)行GC后,EdenSpace和FromSpace能夠容納該對(duì)象,就放在Eden和FromSpace。在GC過(guò)程中會(huì)將EdenSpace和FromSpace存活的對(duì)象移動(dòng)到ToSpace,然后清理Eden和From。若在清理過(guò)程中,ToSpace無(wú)法足夠容納該對(duì)象,則將該對(duì)象移入老年代中。在進(jìn)行GC后,Eden和From為空,MinorGC完成。From和To標(biāo)記互換。To區(qū)(邏輯上)始終為空。
  • 新生代的回收成為MinorGC,對(duì)老年代的回收成為MajorGC又名FullGC

其他

  • 優(yōu)先在Eden上分配
  • 大對(duì)象直接進(jìn)入老年代
  • 長(zhǎng)期存活的對(duì)象進(jìn)入老年代
  • 動(dòng)態(tài)對(duì)象年齡判定 suvivor區(qū)同年齡對(duì)象總和大于suvivor區(qū)空間的一半,MinorGC時(shí)復(fù)制至老年代
  • 空間分配擔(dān)保 新生代放不下借用老年代,虛擬機(jī)檢測(cè)GC租借的老年代內(nèi)存是否大于剩余的老年代內(nèi)存。若大于,MinorGC變?yōu)橐淮蜦ullGC。若小于,查看虛擬機(jī)是否允許擔(dān)保失敗,若允許則執(zhí)行一次MinorGC,否則也要變?yōu)橐淮蜦ullGC

5.一些重要的關(guān)鍵字

  • volatile
    Java 語(yǔ)言提供了一種稍弱的同步機(jī)制,即volatile變量.用來(lái)確保將變量的更新操作通知到其他線程,保證了新值能立即同步到主內(nèi)存,以及每次使用前立即從主內(nèi)存刷新。 當(dāng)把變量聲明為volatile類型后,編譯器與運(yùn)行時(shí)都會(huì)注意到這個(gè)變量是共享的。volatile修飾變量,每次被線程訪問(wèn)時(shí)強(qiáng)迫其從主內(nèi)存重讀該值,修改后再寫回共享內(nèi)存。保證讀取的可見(jiàn)性,對(duì)其他線程立即可見(jiàn)。由于不保證原子性,也就不能保證線程安全。由于及時(shí)更新,很可能導(dǎo)致另一線程訪問(wèn)最新變量值,無(wú)法跳出循環(huán)的情況。同時(shí),volatile屏蔽了VM中必要的代碼優(yōu)化,效率上較低。另一個(gè)優(yōu)點(diǎn):禁止指令重排序

  • final
    final修飾的變量是常量,必須進(jìn)行初始化,可以顯示初始化,也可以通過(guò)構(gòu)造進(jìn)行初始化,如果不初始化編譯會(huì)報(bào)錯(cuò)。

6.多線程 & 并發(fā) & 同步 & 鎖

6.1 線程的run方法和start方法

  • start方法
    用start方法來(lái)啟動(dòng)線程,是真正實(shí)現(xiàn)了多線程。調(diào)用thread類的start方法來(lái)啟動(dòng)一個(gè)線程,此時(shí)線程處于就緒狀態(tài),一旦得到cpu時(shí)間片,就開(kāi)始執(zhí)行run方法。注:此時(shí)無(wú)需等待run方法執(zhí)行完畢,即可執(zhí)行下面的代碼,所以run方法并沒(méi)有實(shí)現(xiàn)多線程。
  • run方法
    只是thread類的一個(gè)普通方法,若直接調(diào)用程序中依然只有主線程這一個(gè)線程,還要順序執(zhí)行,依然要等待run方法體執(zhí)行完畢才可執(zhí)行下面的代碼。

6.2 ReadWriteLock(讀寫鎖)

寫寫互斥 讀寫互斥 讀讀并發(fā)
在讀多寫少的情況下可以提高效率

6.3 resume(繼續(xù)掛起的線程)和suspend(掛起線程)一起用

6.4 wait與notify、notifyall一起用

6.5 sleep與wait的異同點(diǎn)

  1. sleep是Thread類的靜態(tài)方法,wait來(lái)自object類
  2. sleep不釋放鎖,wait釋放鎖
  3. wait,notify,notifyall必須在同步代碼塊中使用,sleep可以在任何地方使用
  4. 都可以拋出InterruptedException

6.6 讓一個(gè)線程停止執(zhí)行

異常 - 停止執(zhí)行
休眠 - 停止執(zhí)行
阻塞 - 停止執(zhí)行

6.7 ThreadLocal相關(guān)

  • ThreadLocal解決了變量并發(fā)訪問(wèn)的沖突問(wèn)題

    • 當(dāng)使用ThreadLocal維護(hù)變量時(shí),ThreadLocal為每個(gè)使用該變量的線程提供獨(dú)立的變量副本,每個(gè)線程都可以獨(dú)立地改變自己的副本,而不會(huì)影響其它線程所對(duì)應(yīng)的副本,是線程隔離的。線程隔離的秘密在于ThreadLocalMap類(ThreadLocal的靜態(tài)內(nèi)部類)
    • 原理
      • 這個(gè)類之所以能夠存儲(chǔ)每個(gè)thread的信息,是因?yàn)樗膬?nèi)部有一個(gè)Values內(nèi)部類,而Values中有一個(gè)Object組。
      • Objec數(shù)組是以一種近似于map的形式來(lái)存儲(chǔ)數(shù)據(jù)的,其中偶數(shù)位存ThreadLocal的弱引用,它的下一位存值。
      • 在尋址的時(shí)候,Values采用一種很神奇的方式——斐波拉契散列尋址Values里面的getAfterMiss()方式讓人覺(jué)得很奇怪
  • 與synchronized同步機(jī)制的比較

    • 首先,它們都是為了解決多線程中相同變量訪問(wèn)沖突問(wèn)題。不過(guò),在同步機(jī)制中,要通過(guò)對(duì)象的鎖機(jī)制保證同一時(shí)間只有一個(gè)線程訪問(wèn)該變量。該變量是線程共享的,使用同步機(jī)制要求程序縝密地分析什么時(shí)候?qū)υ撟兞孔x寫,什么時(shí)候需要鎖定某個(gè)對(duì)象,什么時(shí)候釋放對(duì)象鎖等復(fù)雜的問(wèn)題,程序設(shè)計(jì)編寫難度較大,是一種“以時(shí)間換空間”的方式。
      而ThreadLocal采用了以“以空間換時(shí)間”的方式。

7.接口與抽象類

  1. 一個(gè)子類只能繼承一個(gè)抽象類,但能實(shí)現(xiàn)多個(gè)接口
  2. 抽象類可以有構(gòu)造方法,接口沒(méi)有構(gòu)造方法
  3. 抽象類可以有普通成員變量,接口沒(méi)有普通成員變量
  4. 抽象類和接口都可有靜態(tài)成員變量,抽象類中靜態(tài)成員變量訪問(wèn)類型任意,接口只能public static final(默認(rèn))
  5. 抽象類可以沒(méi)有抽象方法,抽象類可以有普通方法,接口中都是抽象方法
  6. 抽象類可以有靜態(tài)方法,接口不能有靜態(tài)方法
  7. 抽象類中的方法可以是public、protected和默認(rèn);接口方法只有public

8.Statement接口

8.1

  • Statement是最基本的用法,不傳參,采用字符串拼接,存在注入漏洞
  • PreparedStatement傳入?yún)?shù)化的sql語(yǔ)句,同時(shí)檢查合法性,效率高,可以重用,防止sql注入
  • CallableStatement接口擴(kuò)展PreparedStatement,用來(lái)調(diào)用存儲(chǔ)過(guò)程
  • public interface CallableStatement extends PreparedStatement
  • public interface PreparedStatement extends Statement
  • BatchedStatement用于批量操作數(shù)據(jù)庫(kù),BatchedStatement不是標(biāo)準(zhǔn)的Statement類

8.2 Statement與PrepareStatement的區(qū)別

  • 創(chuàng)建時(shí)的區(qū)別
Statement statement = conn.createStatement();
PreparedStatement preStatement = conn.prepareStatement(sql);
  • 執(zhí)行的時(shí)候
ResultSet rSet = statement.executeQuery(sql);
ResultSet pSet = preStatement.executeQuery();

由上可以看出,PreparedStatement有預(yù)編譯的過(guò)程,已經(jīng)綁定sql,之后無(wú)論執(zhí)行多少遍,都不會(huì)再去進(jìn)行編譯,
而 statement 不同,如果執(zhí)行多遍,則相應(yīng)的就要編譯多少遍sql,所以從這點(diǎn)看,preStatement 的效率會(huì)比 Statement要高一些

  • 安全性

preStatement是預(yù)編譯的,所以可以有效的防止SQL注入等問(wèn)題

  • 代碼的可讀性和可維護(hù)性

PreparedStatement更勝一籌

9.抽象類和最終類

抽象類可以沒(méi)有抽象方法,最終類可以,沒(méi)有最終方法

最終類不能被繼承,最終方法不能被重寫(可以重載)

10.異常

10.1 throw、throws、try...catch、finally

  1. throws用在方法上,方法內(nèi)部通過(guò)throw拋出異常
  2. try用于檢測(cè)包住的語(yǔ)句塊,若有異常,拋出并執(zhí)行catch子句
  3. catch捕獲try塊中拋出的異常并處理

10.2 關(guān)于finally

  1. finally不管有沒(méi)有異常都要處理
  2. finally{}比return先執(zhí)行,多個(gè)return執(zhí)行一個(gè)后就不在執(zhí)行
  3. 不管有木有異常拋出,finally在return返回前執(zhí)行

10.3 受檢查異常和運(yùn)行時(shí)異常


image
  1. 粉紅色的是受檢查的異常(checked exceptions),其必須被try...catch語(yǔ)句塊所捕獲,或者在方法簽名里通過(guò)throws子句聲明。受檢查的異常必須在編譯時(shí)被捕捉處理,命名為Checked Exception是因?yàn)镴ava編譯器要進(jìn)行檢查,Java虛擬機(jī)也要進(jìn)行檢查,以確保這個(gè)規(guī)則得到遵守。

  2. 綠色的異常是運(yùn)行時(shí)異常(runtime exceptions),需要程序員自己分析代碼決定是否捕獲和處理,比如空指針,被0除...

  3. 而聲明為Error的,則屬于嚴(yán)重錯(cuò)誤,如系統(tǒng)崩潰、虛擬機(jī)錯(cuò)誤、動(dòng)態(tài)鏈接失敗等,這些錯(cuò)誤無(wú)法恢復(fù)或者不可能捕捉,將導(dǎo)致應(yīng)用程序中斷,Error不需要捕捉。

11.this & super

11.1 super出現(xiàn)在父類的子類中。有三種存在方式

  1. super.xxx(xxx為變量名或?qū)ο竺?意思是獲取父類中xxx的變量或引用
  2. super.xxx(); (xxx為方法名)意思是直接訪問(wèn)并調(diào)用父類中的方法
  3. super() 調(diào)用父類構(gòu)造
  • super只能指代其直接父類

11.2 this() & super()在構(gòu)造方法中的區(qū)別

  1. 調(diào)用super()必須寫在子類構(gòu)造方法的第一行,否則編譯不通過(guò)
  2. super從子類調(diào)用父類構(gòu)造,this在同一類中調(diào)用其他構(gòu)造
  3. 均需要放在第一行
  4. 盡管可以用this調(diào)用一個(gè)構(gòu)造器,卻不能調(diào)用2個(gè)
  5. this和super不能出現(xiàn)在同一個(gè)構(gòu)造器中,否則編譯不通過(guò)
  6. this()、super()都指的對(duì)象,不可以在static環(huán)境中使用
  7. 本質(zhì)this指向本對(duì)象的指針。super是一個(gè)關(guān)鍵字

12.修飾符一覽

修飾符             類內(nèi)部     同一個(gè)包        子類      任何地方
private         yes
default         yes         yes
protected       yes         yes             yes
public          yes         yes             yes         yes

13.構(gòu)造內(nèi)部類對(duì)象

public class Enclosingone {
    public class Insideone {}
    public static class Insideone{}
}

public class Test {
    public static void main(String[] args) {
    Enclosingone.Insideone obj1 = new Enclosingone().new Insideone();
    Enclosingone.Insideone obj2 = new Enclosingone.Insideone();
    }
}

14.序列化

聲明為static和transient類型的數(shù)據(jù)不能被序列化,序列化的筆記參見(jiàn)[Java-note-序列化.md][5]

15.Java的方法區(qū)

與堆一樣,是線程共享的區(qū)域。方法區(qū)中存儲(chǔ):被虛擬機(jī)加載的類信息,常量,靜態(tài)變量,編譯器編譯后的代碼等數(shù)據(jù)。這個(gè)區(qū)域的內(nèi)存回收目標(biāo)主要是針對(duì)常量池的對(duì)象的回收和對(duì)類型的卸載。

16.正則表達(dá)式

次數(shù)符號(hào)

* 0或多次
+ 1或多次
?0或1次
{n} 恰n次
{n,m} 從n到m次

其他符號(hào)

符號(hào) 等價(jià)形式

\d      [0-9]
\D      [^0-9]  
\w      [a-zA-Z_0-9]
\W      [^a-zA-Z_0-9]
\s      [\t\n\r\f]
\S      [^\t\n\r\f]
.       任何字符

邊界匹配器

行開(kāi)頭 ^
行結(jié)尾 $
單詞邊界 \b

貪婪模式:最大長(zhǎng)度匹配 非貪婪模式:匹配到結(jié)果就好,最短匹配

環(huán)視

字符              描述                  匹配對(duì)象
.                   單個(gè)任意字符          
[...]               字符組                     列出的任意字符
[^...]                                      未列出的任意字符
^                   caret                   行的起始位置
$                   dollar                  行的結(jié)束位置
\<                                          單詞的起始位置
\>                                          單詞的結(jié)束位置
\b                  單詞邊界
\B                  非單詞邊界
(?=Expression)      順序肯定環(huán)視          成功,如果右邊能夠匹配
(?!Expression)      順序否定環(huán)視          成功,如果右邊不能夠匹配
(?<=Expression)     逆序肯定環(huán)視          成功,如果左邊能夠匹配
(?<!Expression)     逆序否定環(huán)視          成功,如果左邊不能夠匹配

舉例:北京市(海定區(qū))(朝陽(yáng)區(qū))(西城區(qū))

Regex: .*(?=\()

模式和匹配器的典型調(diào)用次序

  1. 把正則表達(dá)式編譯到模式中
    Pattern p = Pattern.compile("a*b");
  2. 創(chuàng)建給定輸入與此模式的匹配器
    Matcher m = p.matcher("aaab");
  3. 嘗試將整個(gè)區(qū)域與此模式匹配
    boolean b = m.matches();

17.Servlet & JSP & Tomcat

17.1 Servlet繼承實(shí)現(xiàn)結(jié)構(gòu)

Servlet (接口)            -->      init|service|destroy方法
GenericServlet(抽象類)  -->      與協(xié)議無(wú)關(guān)的Servlet
HttpServlet(抽象類)        -->      實(shí)現(xiàn)了http協(xié)議
自定義Servlet          -->      重寫doGet/doPost

17.2 編寫Servlet的步驟

  1. 繼承HttpServlet
  2. 重寫doGet/doPost方法
  3. 在web.xml中注冊(cè)servlet

17.3 Servlet生命周期

  1. init:僅執(zhí)行一次,負(fù)責(zé)裝載servlet時(shí)初始化servlet對(duì)象
  2. service:核心方法,一般get/post兩種方式
  3. destroy:停止并卸載servlet,釋放資源

17.4 過(guò)程

  1. 客戶端request請(qǐng)求 -> 服務(wù)器檢查Servlet實(shí)例是否存在 -> 若存在調(diào)用相應(yīng)service方法
  2. 客戶端request請(qǐng)求 -> 服務(wù)器檢查Servlet實(shí)例是否存在 -> 若不存在裝載Servlet類并創(chuàng)建實(shí)例 -> 調(diào)用init初始化 -> 調(diào)用service
  3. 加載和實(shí)例化、初始化、處理請(qǐng)求、服務(wù)結(jié)束

17.5 doPost方法要拋出的異常:ServletExcception、IOException

17.6 Servlet容器裝載Servlet

  1. web.xml中配置load-on-startup啟動(dòng)時(shí)裝載
  2. 客戶首次向Servlet發(fā)送請(qǐng)求
  3. Servlet類文件被更新后,重新裝載Servlet

17.7 HttpServlet容器響應(yīng)web客戶請(qǐng)求流程

  1. Web客戶向servlet容器發(fā)出http請(qǐng)求
  2. servlet容器解析Web客戶的http請(qǐng)求
  3. servlet容器創(chuàng)建一個(gè)HttpRequest對(duì)象,封裝http請(qǐng)求信息
  4. servlet容器創(chuàng)建一個(gè)HttpResponse對(duì)象
  5. servlet容器調(diào)用HttpServlet的service方法,把HttpRequest和HttpResponse對(duì)象作為service方法的參數(shù)傳給HttpServlet對(duì)象
  6. HttpServlet調(diào)用httprequest的有關(guān)方法,獲取http請(qǐng)求信息
  7. httpservlet調(diào)用httpresponse的有關(guān)方法,生成響應(yīng)數(shù)據(jù)
  8. Servlet容器把HttpServlet的響應(yīng)結(jié)果傳給web客戶

17.8 HttpServletRequest完成的功能

  1. request.getCookie()
  2. request.getHeader(String s)
  3. request.getContextPath()

17.9 HttpServletResponse完成的功能

  1. 設(shè)http頭
  2. 設(shè)置Cookie
  3. 輸出返回?cái)?shù)據(jù)

17.10 session

HttpSession session = request.getSession(boolean create)
返回當(dāng)前請(qǐng)求的會(huì)話

17.11 JSP的前身就是Servlet

17.12 Tomcat容器的等級(jí)

Tomcat - Container - Engine - Host - Servlet - 多個(gè)Context(一個(gè)Context對(duì)應(yīng)一個(gè)web工程)-Wrapper

17.13 Servlet與JSP九大內(nèi)置對(duì)象的關(guān)系

JSP對(duì)象 怎樣獲得

1. out              ->      response.getWriter
2. request      ->      Service方法中的req參數(shù)
3. response         ->      Service方法中的resp參數(shù)
4. session      ->      request.getSession
5. application  ->      getServletContext
6. exception        ->      Throwable
7. page             ->      this
8. pageContext      ->      PageContext
9. Config           ->      getServletConfig

exception是JSP九大內(nèi)置對(duì)象之一,其實(shí)例代表其他頁(yè)面的異常和錯(cuò)誤。只有當(dāng)頁(yè)面是錯(cuò)誤處理頁(yè)面時(shí),即isErroePage為 true時(shí),該對(duì)象才可以使用。

18.struts

  1. struts可進(jìn)行文件上傳
  2. struts基于MVC模式
  3. struts讓流程結(jié)構(gòu)更清晰
  4. struts有許多action類,會(huì)增加類文件數(shù)目

19.Hibernate的7大鼓勵(lì)措施

  1. 盡量使用many-to-one,避免使用單項(xiàng)one-to-many
  2. 靈活使用單項(xiàng)one-to-many
  3. 不用一對(duì)一,使用多對(duì)一代替一對(duì)一
  4. 配置對(duì)象緩存,不使用集合對(duì)象
  5. 一對(duì)多使用bag,多對(duì)一使用set
  6. 繼承使用顯示多態(tài)
  7. 消除大表,使用二級(jí)緩存

20.JVM

20.1 JVM內(nèi)存配置參數(shù)

  1. -Xmx:最大堆大小
  2. -Xms:初始堆大小(最小內(nèi)存值)
  3. -Xmn:年輕代大小
  4. -XXSurvivorRatio:3 意思是Eden:Survivor=3:2
  5. -Xss棧容量
  6. -XX:+PrintGC 輸出GC日志
  7. -XX:+PrintGCDetails 輸出GC的詳細(xì)日志

20.2 JVM內(nèi)存結(jié)構(gòu)

  1. 堆:Eden、Survivor、old 線程共享
  2. 方法區(qū)(非堆):持久代,代碼緩存,線程共享
  3. JVM棧:中間結(jié)果,局部變量,線程隔離
  4. 本地棧:本地方法(非Java代碼)
  5. 程序計(jì)數(shù)器 :線程私有,每個(gè)線程都有自己獨(dú)立的程序計(jì)數(shù)器,用來(lái)指示下一條指令的地址
  6. 注:持久代Java8消失,取代的稱為元空間(本地堆內(nèi)存的一部分)

21.面向?qū)ο蟮奈宕蠡驹瓌t(solid)

  1. S單一職責(zé)SRP:Single-Responsibility Principle
    一個(gè)類,最好只做一件事,只有一個(gè)引起它的變化。單一職責(zé)原則可以看做是低耦合,高內(nèi)聚在面向?qū)ο笤瓌t的引申,將職責(zé)定義為引起變化的原因,以提高內(nèi)聚性減少引起變化的原因。

  2. O開(kāi)放封閉原則OCP:Open-Closed Principle
    軟件實(shí)體應(yīng)該是可擴(kuò)展的,而不是可修改的。對(duì)擴(kuò)展開(kāi)放,對(duì)修改封閉

  3. L里氏替換原則LSP:Liskov-Substitution Principle
    子類必須能夠替換其基類。這一思想表現(xiàn)為對(duì)繼承機(jī)制的約束規(guī)范,只有子類能夠替換其基類時(shí),才能夠保證系統(tǒng)在運(yùn)行期內(nèi)識(shí)別子類,這是保證繼承復(fù)用的基礎(chǔ)。

  4. I接口隔離原則ISP:Interface-Segregation Principle
    使用多個(gè)小的接口,而不是一個(gè)大的總接口

  5. D依賴倒置原則DIP:Dependency-Inversion Principle
    依賴于抽象。具體而言就是高層模塊不依賴于底層模塊,二者共同依賴于抽象。抽象不依賴于具體,具體依賴于抽象。

面向?qū)ο笤O(shè)計(jì)原則
  1. 封裝變化
  2. 少用繼承 多用組合
  3. 針對(duì)接口編程 不針對(duì)實(shí)現(xiàn)編程
  4. 為交互對(duì)象之間的松耦合設(shè)計(jì)而努力
  5. 類應(yīng)該對(duì)擴(kuò)展開(kāi)發(fā) 對(duì)修改封閉(開(kāi)閉OCP原則)
  6. 依賴抽象,不要依賴于具體類(依賴倒置DIP原則)
  7. 密友原則:只和朋友交談(最少知識(shí)原則)

說(shuō)明:將方法調(diào)用保持在界限內(nèi),只調(diào)用屬于以下范圍的方法:
該對(duì)象本身(本地方法)對(duì)象的組件 被當(dāng)作方法參數(shù)傳進(jìn)來(lái)的對(duì)象 此方法創(chuàng)建或?qū)嵗娜魏螌?duì)象

  1. 別找我(調(diào)用我) 我會(huì)找你(調(diào)用你)(好萊塢原則)
  2. 一個(gè)類只有一個(gè)引起它變化的原因(單一職責(zé)SRP原則)

22.null可以被強(qiáng)制轉(zhuǎn)型為任意類型的對(duì)象。

23.代碼執(zhí)行次序

  1. 多個(gè)靜態(tài)成員變量,靜態(tài)代碼塊按順序執(zhí)行
  2. 單個(gè)類中: 靜態(tài)代碼 -> main方法 -> 構(gòu)造塊 -> 構(gòu)造方法
  3. 構(gòu)造塊在每一次創(chuàng)建對(duì)象時(shí)執(zhí)行
  4. 涉及父類和子類的初始化過(guò)程
    a.初始化父類中的靜態(tài)成員變量和靜態(tài)代碼塊
    b.初始化子類中的靜態(tài)成員變量和靜態(tài)代碼塊
    c.初始化父類的普通成員變量和構(gòu)造代碼塊(按次序),再執(zhí)行父類的構(gòu)造方法(注意父類構(gòu)造方法中的子類方法覆蓋)
    d.初始化子類的普通成員變量和構(gòu)造代碼塊(按次序),再執(zhí)行子類的構(gòu)造方法

24.紅黑樹(shù)

二叉搜索樹(shù):(Binary Search Tree又名:二叉查找樹(shù),二叉排序樹(shù))它或者是一棵空樹(shù),或者是具有下列性質(zhì)的二叉樹(shù): 若它的左子樹(shù)不空,則左子樹(shù)上所有結(jié)點(diǎn)的值均小于它的根結(jié)點(diǎn)的值;若它的右子樹(shù)不空,則右子樹(shù)上所有結(jié)點(diǎn)的值均大于它的根結(jié)點(diǎn)的值;它的左、右子樹(shù)也分別為二叉搜索樹(shù)。

紅黑樹(shù)的定義:滿足以下五個(gè)性質(zhì)的二叉搜索樹(shù)

  1. 每個(gè)結(jié)點(diǎn)或是紅色的或是黑色的
  2. 根結(jié)點(diǎn)是黑色的
  3. 每個(gè)葉結(jié)點(diǎn)是黑色的
  4. 如果一個(gè)結(jié)點(diǎn)是紅色的,則它的兩個(gè)子結(jié)點(diǎn)是黑色的
  5. 對(duì)于每個(gè)結(jié)點(diǎn),從該結(jié)點(diǎn)到其后代葉結(jié)點(diǎn)的簡(jiǎn)單路徑上,均包含相同數(shù)目的黑色結(jié)點(diǎn)

黑高

從某個(gè)結(jié)點(diǎn)x出發(fā)(不含x)到達(dá)一個(gè)葉結(jié)點(diǎn)的任意一條簡(jiǎn)單路徑上的黑色結(jié)點(diǎn)個(gè)數(shù)稱為該結(jié)點(diǎn)的黑高。
紅黑樹(shù)的黑高為其根結(jié)點(diǎn)的黑高。

其他

  • 一個(gè)具有n個(gè)內(nèi)部結(jié)點(diǎn)的紅黑樹(shù)的高度h<=2lg(n+1)
  • 結(jié)點(diǎn)的屬性(五元組):color key left right p
  • 動(dòng)態(tài)集合操作最壞時(shí)間復(fù)雜度為O(lgn)

25.排序

  • 穩(wěn)定排序:插入排序、冒泡排序、歸并排序、基數(shù)排序

  • 插入排序[穩(wěn)定]
    適用于小數(shù)組,數(shù)組已排好序或接近于排好序速度將會(huì)非常快
    復(fù)雜度:O(n^2) - O(n) - O(n^2) - O(1)[平均 - 最好 - 最壞 - 空間復(fù)雜度]

  • 歸并排序[穩(wěn)定]
    采用分治法
    復(fù)雜度:O(nlogn) - O(nlgn) - O(nlgn) - O(n)[平均 - 最好 - 最壞 - 空間復(fù)雜度]

  • 冒泡排序[穩(wěn)定]
    復(fù)雜度:O(n^2) - O(n) - O(n^2) - O(1)[平均 - 最好 - 最壞 - 空間復(fù)雜度]

  • 基數(shù)排序 分配+收集[穩(wěn)定]
    復(fù)雜度: O(d(n+r)) r為基數(shù)d為位數(shù) 空間復(fù)雜度O(n+r)

  • 樹(shù)排序
    應(yīng)用:TreeSet的add方法、TreeMap的put方法
    不支持相同元素,沒(méi)有穩(wěn)定性問(wèn)題
    復(fù)雜度:平均最差O(nlogn)

  • 堆排序(就地排序)
    復(fù)雜度:O(nlogn) - O(nlgn) - O(nlgn) - O(1)[平均 - 最好 - 最壞 - 空間復(fù)雜度]

  • 快速排序
    復(fù)雜度:O(nlgn) - O(nlgn) - O(n^2) - O(1)[平均 - 最好 - 最壞 - 空間復(fù)雜度]
    棧空間0(lgn) - O(n)

  • 選擇排序
    復(fù)雜度:O(n^2) - O(n^2) - O(n^2) - O(1)[平均 - 最好 - 最壞 - 空間復(fù)雜度]

  • 希爾排序
    復(fù)雜度 小于O(n^2) 平均 O(nlgn) 最差O(n^s)[1<s<2] 空間O(1)

26.查找與散列

26.1 散列函數(shù)設(shè)計(jì)

  • 直接定址法:f(key) = a*key+b

簡(jiǎn)單、均勻,不易產(chǎn)生沖突。但需事先知道關(guān)鍵字的分布情況,適合查找表較小且連續(xù)的情況,故現(xiàn)實(shí)中并不常用

  • 除留余數(shù)法:f(key) = key mod p (p<=m) p取小于表長(zhǎng)的最大質(zhì)數(shù) m為表長(zhǎng)

  • DJBX33A算法(time33哈希算法hash = hash*33+(unsigned int)str[i];

平方取中法 折疊法 更多....

26.2 沖突處理

閉散列(開(kāi)放地址方法):要求裝填因子a較小,閉散列方法把所有記錄直接存儲(chǔ)在散列表中

  • 線性探測(cè):易產(chǎn)生堆積現(xiàn)象(基地址不同堆積在一起)
  • 二次探測(cè):f(key) = (f(key)+di) % m di=12,-12,22,-22...可以消除基本聚集
  • 隨機(jī)探測(cè):f(key) = (f(key)+di),di采用隨機(jī)函數(shù)得到,可以消除基本聚集
  • 雙散列:避免二次聚集

開(kāi)散列(鏈地址法):原地處理

  • 同義詞記錄存儲(chǔ)在一個(gè)單鏈表中,散列表中子存儲(chǔ)單鏈表的頭指針。
  • 優(yōu)點(diǎn):無(wú)堆積 事先無(wú)需確定表長(zhǎng) 刪除結(jié)點(diǎn)易于實(shí)現(xiàn) 裝載因子a>=1,缺點(diǎn):需要額外空間

27.枚舉類

JDK1.5出現(xiàn) 每個(gè)枚舉值都需要調(diào)用一次構(gòu)造函數(shù)

28.數(shù)組復(fù)制方法

  1. for逐一復(fù)制
  2. System.arraycopy() -> 效率最高native方法
  3. Arrays.arrayOf() -> 本質(zhì)調(diào)用arraycopy
  4. clone方法 -> 返回Object[],需要強(qiáng)制類型轉(zhuǎn)換

29.多態(tài)

  1. Java通過(guò)方法重寫和方法重載實(shí)現(xiàn)多態(tài)
  2. 方法重寫是指子類重寫了父類的同名方法
  3. 方法重載是指在同一個(gè)類中,方法的名字相同,但是參數(shù)列表不同

30.Java文件

.java文件可以包含多個(gè)類,唯一的限制就是:一個(gè)文件中只能有一個(gè)public類, 并且此public類必須與
文件名相同。而且這些類和寫在多個(gè)文件中沒(méi)有區(qū)別。

31.Java移位運(yùn)算符

java中有三種移位運(yùn)算符

  1. << :左移運(yùn)算符,x << 1,相當(dāng)于x乘以2(不溢出的情況下),低位補(bǔ)0
  2. :帶符號(hào)右移,x >> 1,相當(dāng)于x除以2,正數(shù)高位補(bǔ)0,負(fù)數(shù)高位補(bǔ)1

  3. :無(wú)符號(hào)右移,忽略符號(hào)位,空位都以0補(bǔ)齊

32.形參&實(shí)參

  1. 形式參數(shù)可被視為local variable.形參和局部變量一樣都不能離開(kāi)方法。只有在方法中使用,不會(huì)在方法外可見(jiàn)。
  2. 形式參數(shù)只能用final修飾符,其它任何修飾符都會(huì)引起編譯器錯(cuò)誤。但是用這個(gè)修飾符也有一定的限制,就是在方法中不能對(duì)參數(shù)做任何修改。不過(guò)一般情況下,一個(gè)方法的形參不用final修飾。只有在特殊情況下,那就是:方法內(nèi)部類。一個(gè)方法內(nèi)的內(nèi)部類如果使用了這個(gè)方法的參數(shù)或者局部變量的話,這個(gè)參數(shù)或局部變量應(yīng)該是final。
  3. 形參的值在調(diào)用時(shí)根據(jù)調(diào)用者更改,實(shí)參則用自身的值更改形參的值(指針、引用皆在此列),也就是說(shuō)真正被傳遞的是實(shí)參。

33.IO

image

34.局部變量為什么要初始化

局部變量是指類方法中的變量,必須初始化。局部變量運(yùn)行時(shí)被分配在棧中,量大,生命周期短,如果虛擬機(jī)給每個(gè)局部變量都初始化一下,是一筆很大的開(kāi)銷,但變量不初始化為默認(rèn)值就使用是不安全的。出于速度和安全性兩個(gè)方面的綜合考慮,解決方案就是虛擬機(jī)不初始化,但要求編寫者一定要在使用前給變量賦值。

35.JDK提供的用于并發(fā)編程的同步器

  1. Semaphore Java并發(fā)庫(kù)的Semaphore可以很輕松完成信號(hào)量控制,Semaphore可以控制某個(gè)資源可被同時(shí)訪問(wèn)的個(gè)數(shù),通過(guò) acquire() 獲取一個(gè)許可,如果沒(méi)有就等待,而 release() 釋放一個(gè)許可。
  2. CyclicBarrier 主要的方法就是一個(gè):await()。await()方法每被調(diào)用一次,計(jì)數(shù)便會(huì)減少1,并阻塞住當(dāng)前線程。當(dāng)計(jì)數(shù)減至0時(shí),阻塞解除,所有在此CyclicBarrier上面阻塞的線程開(kāi)始運(yùn)行。
  3. 直譯過(guò)來(lái)就是倒計(jì)數(shù)(CountDown)門閂(Latch)。倒計(jì)數(shù)不用說(shuō),門閂的意思顧名思義就是阻止前進(jìn)。在這里就是指 CountDownLatch.await() 方法在倒計(jì)數(shù)為0之前會(huì)阻塞當(dāng)前線程。

36.Java類加載器

一個(gè)jvm中默認(rèn)的classloader有Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader,分別各司其職:

  1. Bootstrap ClassLoader(引導(dǎo)類加載器) 負(fù)責(zé)加載java基礎(chǔ)類,主要是 %JRE_HOME/lib/目錄下的rt.jar、resources.jar、charsets.jar等
  2. Extension ClassLoader(擴(kuò)展類加載器) 負(fù)責(zé)加載java擴(kuò)展類,主要是 %JRE_HOME/lib/ext目錄下的jar等
  3. App ClassLoader(系統(tǒng)類加載器) 負(fù)責(zé)加載當(dāng)前java應(yīng)用的classpath中的所有類。
    classloader 加載類用的是全盤負(fù)責(zé)委托機(jī)制。 所謂全盤負(fù)責(zé),即是當(dāng)一個(gè)classloader加載一個(gè)Class的時(shí)候,這個(gè)Class所依賴的和引用的所有 Class也由這個(gè)classloader負(fù)責(zé)載入,除非是顯式的使用另外一個(gè)classloader載入。
    所以,當(dāng)我們自定義的classloader加載成功了com.company.MyClass以后,MyClass里所有依賴的class都由這個(gè)classLoader來(lái)加載完成。

37.Java語(yǔ)言的魯棒性

Java在編譯和運(yùn)行程序時(shí),都要對(duì)可能出現(xiàn)的問(wèn)題進(jìn)行檢查,以消除錯(cuò)誤的產(chǎn)生。它提供自動(dòng)垃圾收集來(lái)進(jìn)行內(nèi)存管理,防止程序員在管理內(nèi)存時(shí)容易產(chǎn)生的錯(cuò)誤。通過(guò)集成的面向?qū)ο蟮睦馓幚頇C(jī)制,在編譯時(shí),Java揭示出可能出現(xiàn)但未被處理的例外,幫助程序員正確地進(jìn)行選擇以防止系統(tǒng)的崩潰。另外,Java在編譯時(shí)還可捕獲類型聲明中的許多常見(jiàn)錯(cuò)誤,防止動(dòng)態(tài)運(yùn)行時(shí)不匹配問(wèn)題的出現(xiàn)。

38.Java語(yǔ)言特性

  1. Java致力于檢查程序在編譯和運(yùn)行時(shí)的錯(cuò)誤
  2. Java虛擬機(jī)實(shí)現(xiàn)了跨平臺(tái)接口
  3. 類型檢查幫助檢查出許多開(kāi)發(fā)早期出現(xiàn)的錯(cuò)誤
  4. Java自己操縱內(nèi)存減少了內(nèi)存出錯(cuò)的可能性
  5. Java還實(shí)現(xiàn)了真數(shù)組,避免了覆蓋數(shù)據(jù)的可能

39.Hibernate延遲加載

  1. Hibernate2延遲加載實(shí)現(xiàn):a)實(shí)體對(duì)象 b)集合(Collection)
  2. Hibernate3 提供了屬性的延遲加載功能
    當(dāng)Hibernate在查詢數(shù)據(jù)的時(shí)候,數(shù)據(jù)并沒(méi)有存在與內(nèi)存中,當(dāng)程序真正對(duì)數(shù)據(jù)的操作時(shí),對(duì)象才存在與內(nèi)存中,就實(shí)現(xiàn)了延遲加載,他節(jié)省了服務(wù)器的內(nèi)存開(kāi)銷,從而提高了服務(wù)器的性能。
  3. hibernate使用Java反射機(jī)制,而不是字節(jié)碼增強(qiáng)程序來(lái)實(shí)現(xiàn)透明性。
  4. hibernate的性能非常好,因?yàn)樗莻€(gè)輕量級(jí)框架。映射的靈活性很出色。它支持各種關(guān)系數(shù)據(jù)庫(kù),從一對(duì)一到多對(duì)多的各種復(fù)雜關(guān)系。

40.包裝類的equals()方法不處理數(shù)據(jù)轉(zhuǎn)型,必須類型和值都一樣才相等。

41.子類可以繼承父類的靜態(tài)方法!但是不能覆蓋。因?yàn)殪o態(tài)方法是在編譯時(shí)確定了,不能多態(tài),也就是不能運(yùn)行時(shí)綁定。

42.Java語(yǔ)法糖

  1. Java7的switch用字符串 - hashcode方法 switch用于enum枚舉
  2. 偽泛型 - List< E>原始類型
  3. 自動(dòng)裝箱拆箱 - Integer.valueOf和Integer.intValue
  4. foreach遍歷 - Iterator迭代器實(shí)現(xiàn)
  5. 條件編譯
  6. enum枚舉類、內(nèi)部類
  7. 可變參數(shù) - 數(shù)組
  8. 斷言語(yǔ)言
  9. try語(yǔ)句中定義和關(guān)閉資源

43.JVM工具

命令行

  1. jps(jvm processor status)虛擬機(jī)進(jìn)程狀況工具
  2. jstat(jvm statistics monitoring)統(tǒng)計(jì)信息監(jiān)視
  3. jinfo(configuration info for java)配置信息工具
  4. jmap(memory map for java)Java內(nèi)存映射工具
  5. jhat(JVM Heap Analysis Tool)虛擬機(jī)堆轉(zhuǎn)儲(chǔ)快照分析工具
  6. jstack(Stack Trace for Java)Java堆棧跟蹤工具
  7. HSDIS:JIT生成代碼反匯編

可視化

  1. JConsole(Java Monitoring and Management Console):Java監(jiān)視與管理控制臺(tái)
  2. VisualVM(All-in-one Java Troubleshooting Tool):多合一故障處理工具

44.內(nèi)部類為什么可以訪問(wèn)外部類的私有屬性

在內(nèi)部類構(gòu)造的時(shí)候,會(huì)將外部類的引用傳遞進(jìn)來(lái),并且作為內(nèi)部類的一個(gè)屬性,所以內(nèi)部類會(huì)持有一個(gè)其外部類的引用。

當(dāng)內(nèi)部類調(diào)用外部類的私有屬性時(shí),其真正的執(zhí)行是調(diào)用了編譯器生成的屬性的靜態(tài)方法(即acess0,access1等)來(lái)獲取這些屬性值。這一切都是編譯器的特殊處理。

外部類可以通過(guò)內(nèi)部類的實(shí)例獲取私有屬性x的操作.

45.如何讓內(nèi)部類私有成員不被外部訪問(wèn)

使用匿名內(nèi)部類

public class PrivateToOuter {
  Runnable mRunnable = new Runnable(){
      private int x=10;
      @Override
      public void run() {
          System.out.println(x);
      }
  };

  public static void main(String[] args){
      PrivateToOuter p = new PrivateToOuter();
      //System.out.println("anonymous class private filed= "+ p.mRunnable.x); //not allowed
      p.mRunnable.run(); // allowed
  }
}

由于mRunnable對(duì)象的類型為Runnable,而不是匿名內(nèi)部類的類型(我們無(wú)法正常拿到),而Runanble中沒(méi)有x這個(gè)屬性,所以mRunnable.x是不被允許的。

46. Java匿名內(nèi)部類訪問(wèn)外部變量,為何需被標(biāo)志為final?

  • 這要從閉包說(shuō)起,匿名內(nèi)部類和外部方法形成了一個(gè)閉包,因此,匿名內(nèi)部類能夠訪問(wèn)外部方法的變量,看起來(lái)是一種“天經(jīng)地義”的事情,Java語(yǔ)言當(dāng)然也需要實(shí)現(xiàn)這種特性,但是這里遇到了一個(gè)問(wèn)題。
  • 匿名內(nèi)部類的生命周期可能比外部的類要長(zhǎng),因此訪問(wèn)外部局部變量有可能是訪問(wèn)不到的。
  • 那怎么辦呢?Java語(yǔ)言為了實(shí)現(xiàn)這種特性, 只好將外部的局部變量偷偷的賦值了一份給匿名內(nèi)部類。那這樣匿名內(nèi)部類就可以肆無(wú)忌憚的訪問(wèn)外部局部變量了。
  • 問(wèn)題又來(lái)了,這種通過(guò)賦值的形式有一個(gè)缺陷,匿名內(nèi)部類不可以修改“原來(lái)的局部變量”,因?yàn)槭且环荨皬?fù)制品”,修改復(fù)制品對(duì)原變量沒(méi)什么影響啊。
  • 那怎么辦? Java語(yǔ)言干脆強(qiáng)制要求被匿名內(nèi)部類訪問(wèn)的外部局部變量必須是final的,什么意思呢?就是“一刀切”,不讓修改了。

47. 非靜態(tài)內(nèi)部類為什么不能有靜態(tài)成員

  • static類型的屬性和方法,在類加載的時(shí)候就會(huì)存在于內(nèi)存中。
  • 要想使用某個(gè)類的static屬性和方法,那么這個(gè)類必須要加載到虛擬機(jī)- 中。
  • 非靜態(tài)內(nèi)部類并不隨外部類一起加載,只有在實(shí)例化外部類之后才會(huì)加載。

在外部類并沒(méi)有實(shí)例化,內(nèi)部類還沒(méi)有加載,這時(shí)候如果調(diào)用內(nèi)部類的靜態(tài)成員或方法,內(nèi)部類還沒(méi)有加載,卻試圖在內(nèi)存中創(chuàng)建該內(nèi)部類的靜態(tài)成員,這明顯是矛盾的。

所以非靜態(tài)內(nèi)部類不能有靜態(tài)成員變量或靜態(tài)方法。

48. 手寫實(shí)現(xiàn)二分查找

    /**
 * 使用遞歸的二分查找
 **title:recursionBinarySearch
 **@param arr 有序數(shù)組
 **@param key 待查找關(guān)鍵字
 **@return 找到的位置
 */
public static int recursionBinarySearch( int[] arr, int key, int low, int high )
{
    if ( key < arr[low] || key > arr[high] || low > high )
    {
        return(-1);
    }

    int middle = (low + high) / 2; /* 初始中間位置 */
    if ( arr[middle] > key )
    {
        /* 比關(guān)鍵字大則關(guān)鍵字在左區(qū)域 */
        return(recursionBinarySearch( arr, key, low, middle - 1 ) );
    }else if ( arr[middle] < key )
    {
        /* 比關(guān)鍵字小則關(guān)鍵字在右區(qū)域 */
        return(recursionBinarySearch( arr, key, middle + 1, high ) );
    }else {
        return(middle);
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,208評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 175,746評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 62,666評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,477評(píng)論 6 407
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 54,960評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 42,200評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,726評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,617評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,807評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,049評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 34,425評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 35,674評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,432評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,769評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容