七種原始數據類型(boolean,char,byte,short,float,double.long)
第二章 JavaSE基礎
一、Java 面向對象
- 面向對象都有哪些特性以及你對這些特性的理解 ?
- 繼承:從已有的類得到繼承信息創建新類的過程 – 繼承自父類、基類、超類 – 產生子類、派生類
- 封裝:把數據和操作方法幫頂起來,對數據的訪問只能通過已定義的接口;封裝就是隱藏一切可以隱藏的東西,只向外界提供最簡單的編程接口
- 多態:允許不同子類型的對象對同一個消息做出不同的反應
- 編譯時的多態 重載overlord 前綁定 – 不換新
- 運行時的多態 重寫override 後綁定 – 換新 – 精髓 :
- ① 方法重寫
- ② 對象造型
- 抽象:將一類對象的共同特徵總結出來構造類的過程 – 數據抽象和行爲抽象
-
面向對象三大特性:封裝、繼承、多態
- 訪問權限修飾符public、private、protected, 以及不寫(默認)時的區別?
- 當前類、同包、子類、其他包 四個方面考慮
- 如何理解clone對象 ?
- 爲什麼要用clone?
在堆區中,新建一個與原來的對象所有變量有所有相同的值的對象
- ①對任何的對象x,都有x.clone() !=x //克隆對象與原對象不是同一個對象
- ②對任何的對象x,都有x.clone().getClass() = = x.getClass() //克隆對象與原對象的類型一樣
- ③如果對象x的equals()方法定義恰當,那麼x.clone().equals(x)應該成立
- new 一個對象的過程和 clone 一個對象的過程區別 ?
new是初始化新建,clone是初始化拷貝新建 - clone 對象的使用
clone()是淺拷貝,如果想要深拷貝一個對象,這個對象必須要實現Cloneable接口,實現clone方法,並且在clone方法內部,把該對象引用的其他對象也要clone一份,這就要求這個被引用的對象必須也要實現Cloneable接口並且實現clone方法.
二 、JavaSE 語法
- & 和 && 的區別?
- &兩種用法 – 按位與 and 邏輯與
- && 短路與運算符
- 在 Java 中,如何跳出當前的多重嵌套循環?
- 在最外層循環前加一個標記如 A,然後用 break A;可以跳出多重循環。
ok: for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { System.out.println("i=" + i + ",j=" + j); if (j == 5) break ok; } }
- 兩個對象值相同,卻有不同的hashcode,這句話對不對?
- 不對
- 值相同,hashcode一定相同
- hashcode相同,值不一定相同
- 是否可以繼承String類
- String類是final類,不可以被繼承
- 當一個對象被當作參數傳遞到一個方法後,此方法可改變這個對象的屬性,並可返回變化後的結果,這裏到底是值傳遞還是引用傳遞?
- 是值傳遞
- Java 語言的方法調用只支持參數的值傳遞
- 當一個對象實例作爲一個參數被傳遞到方法中時,參數的值就是對該對象的引用。對象的屬性可以在被調用過程中被改變,但對對象引用的改變是不會影響到調用者的。
- 重載(overload)和重寫(override)的區別?重載的方法能否根據返回類型進行區分?
- 重載是在一個類裏,同名的方法有不同的參數列表(參數類型不同、參數個數不同或者二者都不同),重載對返回類型沒有特殊的要求。
- 編譯時多態 – 前綁定
- 重寫是子類繼承父類後對父類方法的重新實現, 要求子類被重寫方法與父類被重寫方法有相同的返回類型,比父類被重寫方法更好訪問,不能比父類被重寫方法聲明更多的異常
- 運行時多態 – 後綁定
- 構造方法不能被重寫/聲明爲final的方法不能被重寫/聲明爲static的方法不能被重寫,但能被再次聲明
- 重寫的方法能夠拋出任何非強制異常(UncheckedException,也叫非運行時異常),無論被重寫的方法是否拋出異常。
- 但是,重寫的方法不能拋出新的強制性異常,或者比被重寫方法聲明的更廣泛的強制性異常,反之則可以。
- 運行時多態 – 後綁定
- 爲什麼函數不能根據返回類型來區分重載?
- 因爲調用時不能指定類型信息,編譯器不知道你要調用哪個函數。僅返回值類型不同的重載是不應該允許的。
- 函數的返回值值是作爲函數運行之後的一個“狀態”,它是保持方法的調用者與被調用者進行通信的關鍵,並不能作爲某個方法的標識。
- 抽象類(abstract class)和接口(interface)有什麼異同?
- 不同:
(1)抽象類: (2)接口- ①在抽象類中可以定義構造器 ①接口中不能定義構造器
- ②可以有抽象方法和具體方法 ②方法全部都是抽象方法
- ③抽象類中可以定義成員變量 ③接口中定義的成員變量實際上都是常量
- ④抽象類中可以包含靜態方法 ④接口中不能有靜態方法
- ⑤一個類只能繼承一個抽象類 ⑤一個類可實現多個接口
- ⑥抽象類中的成員可以是四種 ⑤接口中的全部成員都是public
- ⑦有抽象方法的類必須被定義爲抽象類,而抽象類未必要有抽象方法
- 相同:
①不能被實例化
②可以將抽象類和接口類型作爲引用類
③一個類如果繼承了某個抽象類或者實現了某個接口,都需要對其中的抽象方法全部進行實現,否則該類仍然需要被聲明爲抽象類
- 抽象的(abstract)方法是否可同時是靜態的(static)?是否可同時是本地方法(native)?是否可同時被 synchronized?
- 都不能
- 抽象方法需要子類重寫,而靜態方法是無法被重寫的
- 本地方法是由本地代碼實現的方法,而抽象方法是沒有實現的
- synchronize和方法的實現細節有關,抽象方法不涉及實現細節,因此互相矛盾
- 闡述靜態變量和實例變量的區別?
- 靜態變量:是被static修飾的變量,也稱爲類變量,屬於類而不屬於任何一個對象,
一個類不管創建多少個對象,靜態變量值內存中有且只有一個拷貝。可以讓對個對象共享內存。 - 實例變量:必須依存於某一實例,需要先創建對象,然後通過對象才能訪問到它
- ==和 equals 的區別?
- 最大的區別: == 是運算符 / equals 是方法
- == :如果比較的對象是基本數據類型,則比較的數值是否相等;如果是引用數據類型,則比較的是對象的地址值是否相等
- equals:用來比較方法兩個對象的內容是否相等,不能用於基本數據類型的變量,如果沒有對equals方法進行重寫,那麼比較的是引用類型的變量所指向的對象的地址
- String類 和 StringBuffer類
- String類是不可變類,它所有的對象都是不可變對象。
- 如果經常對字符串進行修改,那麼內存開銷是很大的。因爲 String 對象不可改變,所以對於內容相同的字符串,只要一個 String 對象來表示就可以了
- 對於字符串常量,如果內容相同,Java 認爲它們代表同一個 String對象
- 不可變類優點:因爲它的對象只讀,所以多線程併發訪問不會有任何問題。
- 不可變類缺點:每個不同的狀態都要一個對象來代表,可能會造成性能的問題。
- StringBuffer 類,允許被修改,而不是每個不同的字符串都要生成一個新的對象。
三、Java中的多態
- Java 中實現多態的機制是什麼?
- 重寫:
靠的是父類或接口定義的引用變量可以指向子類或具體實現類的實例對象。而程序調用的方法是運行期才動態綁定,就是引用變量所指的具體實例對象的方法,也就是內存里正在運行的那個對象的方法,而不是引用變量的類型中定義的方法。
四、Java 的異常處理
- error 和 exception 的區別?
- Error 類和 Exception 類的父類都是 Throwable 類,區別如下:
- Error無法恢復和預防
- Exception可以捕獲且可能恢復 – 分爲編譯時異常和運行時異常
- Java 中異常分爲哪些種類
- 編譯時異常CheckedException(普通異常)對Checked 異常處理方法有兩種:
- 當前方法知道如何處理該異常,則用 try…catch 塊來處理該異常。
- 當前方法不知道如何處理,則在定義該方法是聲明拋出該異常 – throws語句。
- 運行時異常RuntimeException(系統異常)
- 寫出最常見的 5 個 RuntimeException?
- 數組下標越界 / 空指針 / 指定的類找不到 / 字符串轉換爲數字異常 / 方法傳遞參數錯誤 / 數據類型轉換異常 / 未找到類定義錯誤 / SQL 語句錯誤 / 實例化異常 / 方法不存在異常
- throw 和 throws 的區別
- throw
- throw用在方法體內,表示拋出異常,由方法體內的語句處理
- throw拋出的異常一定是一個異常實例,執行throw一定是拋出了某種異常
- throws
- throws用在方法聲明後面,表示如果拋出異常,由該方法的調用者進行異常的處理
- throws主要是聲明這個方法會拋出某種類型的異常,讓它的使用者知道需要捕獲的異常的類型
- throws表示出現異常的一種可能性,並不一定會發生這種異常
- final、finally、finalize 的區別?
- final–用於聲明屬性、方法、類,表示屬性不可變、方法不可覆蓋、類不可被繼承
- finally–異常處理語句結構的一部分,表示總是執行,它一定會被執行
- finalize–Object類的一個方法,在垃圾回收器執行的時候會調用被回收對象的此方法,可以覆蓋此方法提供垃圾收集時的其他資源回收,該方法更像是一個對象生命週期的臨終方法,當該方法被調用則代表該對象的即將死亡,這是一種被動的方法(回調方法)
五、JavaSE 常用 API
- Math.round(11.5) = 12; Math.round(-11.5) = -11
- 四捨五入是參數+0.5後取整
- switch 是否能作用在 byte 上?是否能作用在 long 上?是否能作用在 String上?
- 可以的有:byte、short、char、int、enum、String
- 不可以的有:long
- 數組有沒有 length() 方法? String 有沒有 length() 方法?
- 數組沒有length()方法,但是有length屬性;
- String有length()方法
- String 、StringBuilder 、StringBuffer的區別?
- String:字符串常量,在修改時不會改變自身;若修改,等於重新生成新的字符串對象。對象定義後不可變,線程安全。
- StringBuffer:表示的字符串對象可以直接進行修改是線程安全的(對調用方法加入同步鎖), 執行效率較慢,適用於多線程下操作字符串緩衝區大量數據。
- StringBuilder:非線程安全,適用於單線程下操作字符串緩衝區大量數據。
- ①StringBuffer和StringBuilder的方法完全相同
- ②StringBuilder是在單線程環境下使用的,因爲他的所有方法都沒有被synchronized修飾,因此他的理論效率也比StringBuffer要高,多數情況下建議使用。
- 什麼情況下用“+”運算符進行字符串連接比調用 StringBuffer/StringBuilder對象的 append()方法連接字符串性能更好?
- 在 Java 中 String 類已經重載了"+"。也就是說,字符串可以直接使用"+“進行連接;在 Java 中無論使用何種方式進行字符串連接,實際上都使用的是 StringBuilder;
字符串的+操作其本質是創建了 StringBuilder 對象進行 append 操作;然後將拼接後的 StringBuilder 對象用 toString 方法處理成 String對象;在使用 StringBuilder時,儘量不要”+"和 StringBuilder混着用,否則會創建更多的 StringBuilder對象
- Java 中的日期和時間
- Calendar / LocalDateTime
- 格式化日期
- Java.text.DataFormat 的子類(如 SimpleDateFormat 類)中的 format(Date)方法可將日期格式化
- Java 8 中可以用 java.time.format.DateTimeFormatter 來格式化時間日期
- LocalDate, LocalTime, LocalDateTime, Instant, Period, Duration 等等,所有這些類都是不可變的和線程安全的。
- LocalDate 是一個不可變的類,它表示默認格式(yyyy-MM-dd)的日期,該類爲 now()方法提供了重載方法。
- LocalTime 是一個不可變的類。
- LocalDateTime 是一個不可變的日期-時間對象,它表示一組日期-時間。
- Instant 類是用在機器可讀的時間格式上的,它以 Unix 時間戳的形式存儲日期時間
-
日期 API 工具TemporalAdjuster
-
解析和格式化
- 將一個日期格式轉換爲不同的格式,之後再解析一個字符串,得到日期時間對象
六、Java 的數據類型
- Java 的基本數據類型都有哪些各佔幾個字節
- 字符型:char 2
- 布爾型:boolean 1
- 整 型:byte 1 / short 2 / int 4 / long 8 /
- 浮點型:float 4 / double 8
- int 和 Integer有什麼區別?
-
Java 爲每一個基本數據類型都引入了對應的包裝類型(wrapper class)
int的包裝類型就是Integer。Java的自動裝箱/拆箱機制,使得二者可以相互轉換。 -
Java 爲每個原始類型提供了包裝類型:
原始 | 包裝 |
---|---|
boolean | $Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
- 數據類型之間的轉換
- 字符串如何轉基本數據類型?
- 調用基本數據類型對應的包裝類中的方法 parseXXX(String)或 valueOf(String)即可返回相應基本類型。
- 基本數據類型如何轉字符串?
- 一種方法是將基本數據類型與空字符串(“”)連接(+)即可獲得其所對應的字符串;
- 另一種方法是調用 String類中的 valueOf()方法返回相應字符串
七、Java 的 IO
- Java中有幾種流?
- 按照流的方向:輸入流(inputStream)和輸出流(outputStream)
- 按照實現功能分:節點流和處理流
- 按處理數據的單位:字節流和字符流
- 如何將一個 java 對象序列化到文件裏
- 在 java 中能夠被序列化的類必須先實現 Serializable 接口,該接口沒有任何抽象方法只是起到一個標記作用。
-
- 字節流和字符流的區別
- 字節流讀取的時候,讀到一個字節就返回一個字節 / 字符流使用了字節流讀到一個或多個字節時,先去查指定的編碼表,將查到的字符返回
- 字節流可以處理所有類型數據 / 而字符流只能處理字符數據
- 只要是處理純文本數據,就要優先考慮使用字符流,除此之外都用字節流
- 字節流主要是操作 byte 類型數據,以 byte 數組爲準,主要操作類就是 OutputStream、InputStream
- 如果是音頻文件、圖片、歌曲,就用字節流好點,如果是關係到中文(文本)的,用字符流好點。
- 在程序中一個字符等於兩個字節
- java 提供了 Reader、Writer 兩個專門操作字符流的類
- 如何實現對象克隆?
- 有兩種方式。
- 實現 Cloneable 接口並重寫 Object 類中的 clone()方法
- 實現 Serializable 接口,通過對象的序列化和反序列化實現克隆,可以實現真正的深度克隆;這種是方案明顯優於使用 Object 類的 clone方法克隆對象。
- 什麼是 java 序列化,如何實現 java 序列化?
- 序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內容進行流化;序列化是爲了解決在對對象流進行讀寫操作時所引發的問題;
- 序列化的實現:將需要被序列化的類實現Serializable接口,該接口沒有需要實現 的方法,implements Serializable只是爲了標註該對象是可被序列化的,然後使用一個輸出流(如:FileOutputStream)來構造一個 ObjectOutputStream(對象流)對象,
接着,使用 ObjectOutputStream 對象的 writeObject(Object obj)方法,就可以將參數爲 obj 的對象寫出(即保存其狀態),要恢復的話則用輸入流。
八、Java 的集合
- HashMap 排序題,上機題
- HashMap – LinkedHashMap – HashMap
- 集合的安全性問題
- 在集合中 Vector 和 HashTable 是線程安全的
- ArrayList、HashSet、HashMap 是非線程安全的
- ArrayList 內部用什麼實現的?
- ArrayList 內部是用 Object[]實現的。
- 併發集合和普通集合如何區別?
- ConcurrentHashMap 是線程安全的, 用HashMap 的實現
- List 的三個子類的特點
- ArrayList 底層結構是數組,底層查詢快,增刪慢
- voctor 底層結構是數組 線程安全的,增刪慢,查詢慢
- LinkedList 底層結構是鏈表型的,增刪快,查詢慢
- List 和 Map、Set 的區別
- 結構特點
- List和Set是存儲單列數據的集合,Map是存儲鍵和值這樣的雙列數據的集合;
- List中存儲的數據是有順序,並且允許重複;
- Map中存儲的數據是沒有順序的,其鍵是不能重複的、值是可以有重複的,
- Set中存儲的數據是無序的,且不允許重複,但元素在集合中的位置由元素的 hashcode 決定,位置是固定的,即set集合根據 hashcode來存儲數據
- 實現類
- List 接口有三個實現類:LinkedList / ArrayList / vector
- Map 接口有三個實現類:HashMap / LinkedHashMap / HashTable
- Set 接口有兩個實現類: HashSet / LinkedHashSet
- 區別
- List 集合中對象按照索引位置排序,可以有重複對象,允許按照對象在集合中的索引位置檢索對象
- Set 集合中的對象不按照特定的方式排序,並且沒有重複對象,但它的實現類能對集合中的對象按照特定的方式排序
- Map 中的每一個元素包含一個鍵和一個值,成對出現,鍵對象不可以重複,值對象可以重複
- HashMap 和 HashTable 有什麼區別?
- HashMap
- 是 Map 的一個子接口,是將鍵映射到值的對象;
- 不允許鍵值重複,允許空鍵和空值;
- 是線程不安全的, 效率要比 HashTable 的效率高一些.
- HashTable
- 是線程安全的一個集合;
- 不允許 null 值作爲一個 key 值或者 Value 值;
- HashTable在被多個線程訪問時不需要自己爲它的方法實現同步,而 HashMap 在被多個線程訪問的時候需要自己爲它的方法實現同步
九、Java 的多線程和併發庫
(一)多線程基礎知識–傳統線程機制的回顧
1.傳統使用類 Thread 和接口 Runnable 實現
(1) 在 Thread 子類覆蓋的 run 方法中編寫運行代碼
(2) 在傳遞給 Thread 對象的 Runnable 對象的 run 方法中編寫代碼
2.定實現時器 Timer 和 TimerTask
3.線程互斥與同步
4.線程局部變量 ThreadLocal
(1)ThreadLocal 的作用和目的:用於實現線程內的數據共享,即對於相同的程序代碼,
多個模塊在同一個線程中運行時要共享一份數據,而在另外線程中運行時又共享另外一份數據
5.多線程共享數據
(1)多個線程行爲一致,共同操作一個數據源。可以使用同一個 Runnable 對象
(2)多個線程行爲不一致,共同操作一個數據源.這時候需要用不同的Runnable對象
(二)多線程基礎知識–線程併發庫
Executors 線程池工廠類
線程池作用就是限制系統中執行線程的數量
爲什麼要用線程池:
減少了創建和銷燬線程的次數,每個工作線程都可以被重複利用,可執行多個任務
可以根據系統的承受能力,調整線程池中工作線線程的數目,防止因爲因爲消耗過多的內存
在 java 的多線程中,一但線程關閉,就會成爲死線程。關閉後死線程就沒有辦法在啓動了。再次啓動就會出現異常信息
併發隊列-阻塞隊列
常用的併發隊列有阻塞隊列和非阻塞隊列,前者使用鎖實現,後者則使用 CAS 非阻塞算法實現
1.BlockingQueue 阻塞隊列通常用於一個線程生產對象,而另外一個線程消費這些對象的場景
2.SychronousQueue 同步隊列 ,但它的特別之處在於它內部沒有容器
3.DeplayQueue 延時無界阻塞隊列只有在延遲期滿時才能從中提取元素
併發隊列-非阻塞隊列
非阻塞算法 CAS
CAS 包含 3 個操作數:
需要讀寫的內存位置 V
進行比較的值 A
擬寫入的新值 B
“使用 CAS 控制併發”與“使用樂觀鎖”並不等價。CAS 只是一種手段,既可以實現樂觀鎖,也可以實現悲觀鎖。樂觀、悲觀只是一種併發控制的策略。
(三)多線程面試題
1. 多線程的創建方式
(1)繼承 Thread 類
(2)實現 Runnable 接口的方式實現多線程,並且實例化 Thread
(3)使用 ExecutorService、Callable、Future 實現有返回結果的多線程
執行 Callable 任務後,可以獲取一個 Future 的對象,
在該對象上調用 get 就可以獲取到 Callable 任務返回的 Object 了,再結合線程池接口
ExecutorService 就可以實現有返回結果的多線程了
PS:可返回值的任務必須實現 Callable 接口,類似的,無返回值的任務必須 Runnable 接口
2. 在 java 中 wait 和 sleep 方法的不同?
A: 在等待時 wait 會釋放鎖,而 sleep 一直持有鎖。wait 通常被用於線程間交互,sleep 通常被用於暫停執行。
3. 什麼是線程池,如何使用?
A: 線程池就是事先將多個線程對象放到一個容器中,當使用的時候就不用 new 線程而是直接去池中拿線程即可,
節省了開闢子線程的時間,提高的代碼執行效率
4. 常用的線程池有哪些?
A: newSingleThreadExecutor:
創建一個單線程的線程池,此線程池保證所有任務的執行順序按照任務的提交順序執行。
newFixedThreadPool:
創建固定大小的線程池,每次提交一個任務就創建一個線程,直到線程達到線程池的最大大小。
newCachedThreadPool:
創建一個可緩存的線程池,此線程池不會對線程池大小做限制,線程池大小完全依賴於操作系統(或者說 JVM)能夠創建的最大線程大小。
newScheduledThreadPool:
創建一個大小無限的線程池,此線程池支持定時以及週期性執行任務的需求。
5. 請敘述一下您對線程池的理解?
A: 線程池如何用、線程池的好處、線程池的啓動策略
(1)合理利用線程池能夠帶來三個好處:
第一:降低資源消耗。通過重複利用已創建的線程降低線程創建和銷燬造成的消耗。
第二:提高響應速度。當任務到達時,任務可以不需要等到線程創建就能立即執行。
第三:提高線程的可管理性。線程是稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,
使用線程池可以進行統一的分配,調優和監控。
6. Java 中多線程間的通信怎麼實現?
A: 共享變量 && wait/notify 機制
7. 請說出同步線程及線程調度相關的方法?
A: wait():使一個線程處於等待(阻塞)狀態,並且釋放所持有的對象的鎖;
sleep():使一個正在運行的線程處於睡眠狀態,是一個靜態方法,調用此方法要處理 InterruptedException 異常;
notify():喚醒一個處於等待狀態的線程,當然在調用此方法的時候,並不能確切的喚醒某一個等待狀態的線程,而是由 JVM 確定喚醒哪個線程,而且與優先級無關;
notityAll():喚醒所有處於等待狀態的線程,該方法並不是將對象的鎖給所有線程,而是讓它們競爭,只有獲得鎖的線程才能進入就緒狀態;
十、Java 內部類
- 靜態嵌套類 (Static Nested Class) 和內部類(Inner Class)的不同?
- 靜態嵌套類:Static Nested Class 是被聲明爲靜態(static)的內部類,它可以不依賴於外部類實例被實例化。
- 內部類:需要在外部類實例化後才能實例化。
第三章 JavaSE 高級
一、Java 中的反射
- 說說你對 Java 中反射的理解
- Java中的反射首先是能夠獲取到Java中要反射類的字節碼,獲取字節碼有三種方法
- Class.forName(className)
- 類名.class
- this.getClass()。
- 然後將字節碼中的方法、變量、構造函數等映射成相應的 Method、Filed、Constructor 等類,這些類提供了豐富的方法可以被我們所使用。
二、Java 中的動態代理
- 動靜態代理的區別,什麼場景使用?
- 靜態代理通常只代理一個類,動態代理是代理一個接口下的多個實現類
- 靜態代理事先知道要代理的是什麼,而動態代理不知道要代理什麼東西,只有在運行時才知道。
- AOP 編程就是基於動態代理實現的,比如著名的 Spring 框架、Hibernate 框架等等都是動態代理的使用例子。
三、Java 中的設計模式&回收機制
- 你所知道的設計模式有哪些
- 總體來說設計模式分爲三大類:
- 創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
- 結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式
- 行爲型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
- JVM 垃圾回收機制和常見算法
- GC(Garbage Collector)在回收對象前首先必須發現那些無用的對象,如何去發現定位這些無用的對象?
- 常用的搜索算法是根搜索算法:
通過一些“GC Roots”對象作爲起點,從這些節點開始往下搜索,搜索通過的路徑成爲引用鏈(Reference Chain),當一個對象沒有被 GC Roots 的引用鏈連接的時候,說明這個對象是不可用的,通過上面的算法搜索到無用對象之後,就是回收過程 - 標記—清除算法(Mark-Sweep)(DVM 使用的算法)
效率不高,而且清除後回產生大量的不連續空間,這樣當程序需要分配大內存對象時,可能無法找到足夠的連續空間。 - 複製算法(Copying)
複製算法是把內存分成大小相等的兩塊,每次使用其中一塊,當垃圾回收的時候,把存活的對象複製到另一塊上,然後把這塊內存整個清理掉。
複製算法實現簡單,運行效率高,但是由於每次只能使用其中的一半,造成內存的利用率不高。現在8:1的分配 - 標記—整理算法(Mark-Compact)
把存活對象往內存的一端移動,然後直接回收邊界以外的內存。
標記—整理算法提高了內存的利用率,並且它適合在收集對象存活時間較長的老年代。
(4)分代收集(Generational Collection)
分代收集是根據對象的存活時間把內存分爲新生代和老年代,
根據各個代對象的存活特點,每個代採用不同的垃圾回收算法。
新生代採用複製算法,老年代採用標記—整理算法
- 常用的搜索算法是根搜索算法:
- 談談 JVM 的內存結構和內存分配
- Java 內存模型
- Java 虛擬機將其管轄的內存大致分三個邏輯部分:方法區(Method Area)、Java 棧和 Java 堆。
- 1、方法區是靜態分配的,編譯器將變量綁定在某個存儲位置上,而且這些綁定不會在運行時改變。
- 2、Java Stack 是一個邏輯概念,特點是後進先出。一個棧的空間可能是連續的,也可能是不連續的。
- 3、Java 堆分配(heap allocation)意味着以隨意的順序,在運行時進行存儲空間分配和收回的內存管理模型。
Java 對象的內存總是在 heap 中分配。
- Java 虛擬機將其管轄的內存大致分三個邏輯部分:方法區(Method Area)、Java 棧和 Java 堆。
- Java 內存分配
- 基礎數據類型直接在棧空間分配;
- 方法的形式參數,直接在棧空間分配,當方法調用完成後從棧空間回收;
- 引用數據類型,需要用 new 來創建,既在棧空間分配一個地址空間,又在堆空間分配對象的類變量;
- 方法的引用參數,在棧空間分配一個地址空間,並指向堆空間的對象區,當方法調用完後從棧空間回收;
- 局部變量 new 出來時,在棧空間和堆空間中分配空間,當局部變量生命週期結束後,棧空間立刻被回收,堆空間區域等待 GC 回收;
- 方法調用時傳入的實際參數,先在棧空間分配,在方法調用完成後從棧空間釋放;
- 字符串常量在 DATA 區域分配 ,this 在堆空間分配;
- 數組既在棧空間分配數組名稱, 又在堆空間分配數組實際的大小!
- Java 中引用類型都有哪些?(重要)
- Java 中對象的引用分爲四種級別,這四種級別由高到低依次爲:強引用、軟引用、弱引用和虛引用。
- 解釋內存中的棧 (stack) 、堆 (heap) 和方法區 (method area) 的用法
- 通常我們定義一個基本數據類型的變量,一個對象的引用,還有就是函數調用的現場保存都使用 JVM 中的棧空間;
- 而通過 new 關鍵字和構造器創建的對象則放在堆空間,堆是垃圾收集器管理的主要區域,由於現在的垃圾收集器都採用分代收集算法,所以堆空間還可以細分爲新生代和老生代,再具體一點可以分爲 Eden、Survivor(又可分爲From Survivor 和 To Survivor)、Tenured;
- 方法區和堆都是各個線程共享的內存區域,用於存儲已經被 JVM 加載的類信息、常量、靜態變量、JIT 編譯器編譯後的代碼等數據;
- 程序中的字面量(literal)如直接書寫的 100、"hello"和常量都是放在常量池中,常量池是方法區的一部分。
- 棧空間操作起來最快但是棧很小,通常大量的對象都是放在堆空間,
- 棧和堆的大小都可以通過 JVM 的啓動參數來進行調整,
- 棧空間用光了會引發 StackOverflowError,而堆和常量池空間不足則會引發 OutOfMemoryError。
舉例:String str = new String(“hello”);這個語句中變量 str 放在棧上,用 new 創建出來的字符串對象放在堆上,而"hello"這個字面量是放在方法區的。
- heap 和 stack 有什麼區別
- 申請方式
- stack:由系統自動分配。
- heap:需要程序員自己申請,並指明大小,通過new Object()的形式開闢
- 申請後系統的響應
- stack:只要棧的剩餘空間大於所申請空間,系統將爲程序提供內存,否則將報異常提示棧溢出。
- heap:遍歷記錄空閒內存地址的鏈表,尋找第一個空間大於或等於所申請空間的堆結點,分配空間給程序
- 申請大小的限制
- stack:棧是向低地址擴展的數據結構,是一塊連續的內存的區域 – 溢出OverFlow
- heap:堆是向高地址擴展的數據結構,是不連續的內存區域 – 溢出OutOfMemoryError。
- 系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。
- 堆的大小受限於計算機系統中有效的虛擬內存,堆的空間比較靈活,也比較大。
- 申請效率的比較:
- stack:由系統自動分配,速度較快。
- heap:由 new 分配的內存,一般速度較慢,容易產生內存碎片,但用起來方便。
- heap 和 stack 中的存儲內容
- Java 中堆棧的應用
- 棧(stack)與堆(heap)都是 Java 用來在 Ram 中存放數據的地方
- 棧的優勢是,存取速度比堆要快,棧數據可以共享,存在棧中的數據大小與生存期必須是確定的,缺乏靈活性
- 堆的
- 優點是可以動態地分配內存大小,生存期也不必事先告訴編譯器,Java 的垃圾回收器會自動收走這些不再使用的數據
- 缺點是要在運行時動態分配內存,存取速度較慢。
- 種基本類型存在於棧中,8中對應的包裝類數據存在於堆中
第七章 框架
一、SpringMVC
- SpringMVC 的工作原理
Spring的MVC框架是圍繞DispatcherServlet來設計的,它用來處理所有的HTTP請求和響應。
- (1)用戶發送請求至前端控制器DispatcherServlet;
- (2) DispatcherServlet收到請求後,調用HandlerMapping處理器映射器,請求獲取Handle;
- (3)處理器映射器根據請求url找到具體的處理器,生成處理器對象及處理器攔截器(如果有則生成)一併返回給DispatcherServlet;
- (4)DispatcherServlet 調用 HandlerAdapter處理器適配器;
- (5)HandlerAdapter 經過適配調用 具體處理器(Handler,也叫後端控制器);
- (6)Handler執行完成返回ModelAndView;
- (7)HandlerAdapter將Handler執行結果ModelAndView返回給DispatcherServlet;
- (8)DispatcherServlet將ModelAndView傳給ViewResolver視圖解析器進行解析;
- (9)ViewResolver解析後返回具體View;
- (10)DispatcherServlet對View進行渲染視圖(即將模型數據填充至視圖中)
- (11)DispatcherServlet響應用戶。
- SpringMVC 常用註解都有哪些?
- @requestMapping 用於請求url映射
- @RequestBody 註解實現接受http請求的json數據,將json數據轉化爲Java對象
- @ResopnseBody 註釋實現將controller方法返回對象轉化爲json響應給客戶
- 如歌開啓註解處理器和適配器
- 在項目的springmvc.xml中通過開啓< mvc:annotation-driven >來實現。
- 如何解決get和post亂碼問題?
- 解決post請求亂碼:可以在web.xml裏配置一個CharacterEncodingFilter過濾器,設置爲utf-8;
- 解決get請求亂碼:兩種方法
- ①修改tomvat配置文件添加編碼與工程編碼一致
- ② 對參數進行重新編碼,String userName = New String(Request.getParameter(“userName”).getBytes(“ISO8859-1”), “utf-8”);
二、Spring
- 談談你對Spring的理解
- Spring是一個開源框架,爲簡化企業級應用開發而生,Spring可以是使簡單的JavaBean實現以前只有EJB才能實現的功能。
- Spring是一個IOC和AOP容器框架。
- Spring容器的主要核心是:
控制反轉IOC(舉例子:“不用打電話過來,我們會打給你”),傳統的Java開發模式中,當需要一個對象時,我們會自己使用new或者getInstance等直接或間接調用構造方法創建一個對象,而在Spring開發模式中,Spring容器使用了工廠模式爲我們創建了所需要的對象,不需要我們自己創建了,直接調用Spring提供的對象就可以了,這就是控制反轉的思想。 - Spring中IOC的實現: 依賴注入(DI)。spring 使用 javaBean 對象的 set 方法或者 帶參數的構造方法 爲我們在創建所需對象時將其屬性自動設置所需要的值的過程,就是依賴注入的思想。
- 面向切面編程(AOP),在面向切面編程中,我們將一個個的對象某些類似的方面橫向抽成一個切面,對這個切面進行一些如權限控制、事物管理,記錄日誌等公用操作處理的過程就是面向切面編程的思想。AOP 底層是動態代理,如果是接口採用 JDK 動態代理,如果是類採用CGLIB 方式實現動態代理。
- Spring 中的設計模式(2017-11-13-lyq)
- 單例模式ApplicationContext——spring 中兩種代理方式
- 若目標對象實現了若干接口,spring 使用 jdk 的 java.lang.reflect.Proxy類代理;
- 若目標兌現沒有實現任何接口,spring 使用 CGLIB 庫生成目標類的子類;
在 spring 的配置文件中設置 bean 默認爲單例模式;
- 模板方式模式JdbcTemplate——用來解決代碼重複的問題;
- 委派模式——spring 提供了前端控制器 DispatherServlet 來對請求進行分發;
- 視圖幫助(view helper)——spring 提供了一系列的 JSP 標籤、高效宏來幫助將分散的代碼整合在試圖中。
- 依賴注入——貫穿於 BeanFactory/ApplacationContext 接口的核心理念。
- 工廠模式BeanFactory——在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,並且是通過使用同一個接口來指向新創建的對象。Spring 中使用 beanFactory 來創建對象的實例。
- Spring 的常用註解
- Spring 在 2.5 版本以後開始支持註解的方式來配置依賴注入。可以用註解的方式來代替 xml 中 bean 的描述。註解注入將會被容器在 XML 注入之前被處理,所以後者會覆蓋掉前者對於同一個屬性的處理結果。
- 註解裝配在 spring 中默認是關閉的。所以需要在 spring 的核心配置文件中配置一下才能使用基於註解的裝配模
式。配置方式如下:
< context:annotation-config /> - 常用的註解:
- @Required: 該註解應用於設值方法
- @Autowired:該註解應用於有值設值方法、非設值方法、構造方法和變量。
- @Qualifier:該註解和@Autowired 搭配使用,用於消除特定 bean 自動裝配的歧義。
- 簡單介紹一下 Spring bean 的生命週期
- bean定義
- bean初始化 - 兩種方式
- 在配置文件中通過制定init-menthod來完成
- 實現org.springframeork.beans.factory.InitializingBean接口
- bean調用
- 三種方式可以得到bean實例,並進行調用
- bean銷燬
- 使用配置文件制定的destory-menthod屬性
- 實現org.springframework.bean.factory.DisposeableBean接口
- Spring 結構圖
- 核心容器:包括Core、Beans、Context、EL模塊
- Core模塊:封裝了框架依賴的的最底層部分,包括資源控制、類型轉換、常用的工具類
- Beans模塊:提供了框架的基礎部分,包括IOC和DI;工廠設計模式的實現、面向接口編程
- Context模塊:以Core和Beans爲基礎,集成Beans模塊功能並添加資源綁定、JavaEE指出等;核心接口是ApplicationContext
- EL模塊:提供強大的表達式語言支持
- AoP、Aspects模塊
- AOP 模塊:提供了符合 AOP Alliance 規範的面向切面編程實現;能動態的把功能添加到需要的代碼中;降低業務邏輯和通用功能的耦合
- 提供了對 AspectJ 的集成
實現
- 數據訪問/集成模塊 : 包括JDBC、ORM、OXM、JMS 和 事務管理
- JDBC 模塊:提供了一個JBDC的樣例模板,能消除傳統冗長的JDBC編碼及必須的事務控制,而且能享受到 Spring 管理事務的好處
- ORM模塊: 提供與流行的“對象-關係”映射框架的無縫集成,可以使用 Spring 事務管理,無需額外控制事務
- OXM 模塊:提供了一個對 Object/XML 映射實現, java對象 < — >XML數據
- JMS 模塊:提供一套 “消息生產者、消息消費者”模板用於更加簡單的使用 JMS,JMS 用於用於在兩個應用程序之間,或分佈式系統中發送消息,進行異步通信
- 事務模塊:該模塊用於 Spring 管理事務,只要是 Spring 管理對象都能得到 Spring 管理事務的好處,無需在代碼中進行事務控制,而且支持編程和聲明性的事務管理
- Web/Remoting 模塊:包含Web、Web-Servlet、Web-Struts、Web-Porlet 模塊
- Web 模塊:提供了基礎的 web 功能以及 Web Service 支持,並提供一個 RestTemplate 類來提供方便的 Restful services 訪問
- Web-Servlet 模塊:提供了一個 Spring MVC Web 框架實現
- Web-Struts 模塊:提供了與 Struts 無縫集成
- Test 模塊:Spring支持Junit和TestNG 測試框架,且額外提供了基於Spring的測試功能
- Spring 能幫我們做什麼?
- 根據配置文件創建及組裝對象之間的依賴關係,只需要改配置文件即可
- 面向切面編程能幫助我們無耦合的實現日誌記錄,性能統計,安全控制,不需要在現有代
碼中添加任何額外代碼,現有代碼專注業務邏輯 - 能非常簡單的管理數據庫事務,只需獲取連接,執行SQL,其他事物相關的都交給Spring管理
- 能與第三方數據庫訪問框架(如 Hibernate、JPA)無縫集成
- 能與第三方 Web(如 Struts、JSF)框架無縫集成
- Spring 能方便的與JavaEE(如Java Mail、任務調度)整合,與更多技術整合(如緩存框架)
- 請描述一下 Spring 的事務
- 聲明式事務管理:用在 Spring 配置文件中聲明式的處理事務來代替代碼式的處理事務
- 編程式事物管理:在代碼中顯式挪用beginTransaction()、commit()、rollback()等事務治理相關的方法
- 編程式事務與聲明式事務的區別:
1)編程式事務是自己寫事務處理的類,然後調用
2)聲明式事務是在配置文件中配置,一般搭配在框架裏面使用!
- BeanFactory 常用的實現類有哪些?
- BeanFactory是工廠模式的一個實現,提供IOC功能,把應用的配置和依賴從正真的應用代碼中分離,常用的 BeanFactory 實現有 :
- DefaultListableBeanFactory
- XmlBeanFactory
- ApplicationContext 等
- 解釋 Spring JDBC、Spring DAO 和 Spring ORM?
- Spring-DAO 並非 Spring 的一個模塊,它實際上是指示你寫 DAO 操作、寫好 DAO 操作的一些規範。因此,對於訪問你的數據它既沒有提供接口也沒有提供實現更沒有提供模板。在寫一個 DAO 的時候,你應該使用 @Repository 對其進行註解,這樣底層技術(JDBC,Hibernate,JPA,等等)的相關異常才能一致性地翻譯爲相應的 DataAccessException 子類。
- Spring-JDBC 提供了 Jdbc 模板類,它移除了連接代碼以幫你專注於 SQL 查詢和相關參數。Spring-JDBC 還提供了一個 JdbcDaoSupport,這樣你可以對你的 DAO 進行擴展開發。它主要定義了兩個屬性:一個 DataSource和一個 JdbcTemplate,它們都可以用來實現 DAO 方法。JdbcDaoSupport 還提供了一個將 SQL 異常轉換爲Spring DataAccessExceptions 的異常翻譯器。
- Spring-ORM 是一個囊括了很多持久層技術(JPA,JDO,Hibernate,iBatis)的總括模塊。對於這些技術中的每一個,Spring 都提供了集成類,這樣每一種技術都能夠在遵循 Spring 的配置原則下進行使用,並平穩地和 Spring 事務管理進行集成。
- 對 於 每 一 種 技 術 , 配 置 主 要 在 於 將 一 個 DataSource bean 注 入 到 某 種 SessionFactory 或者 EntityManagerFactory 等 bean 中。純 JDBC 不需要這樣的一個集成類(JdbcTemplate 除外),因爲 JDBC 僅依賴於一個 DataSource。
- 如果你計劃使用一種 ORM 技術,比如 JPA 或者 Hibernate,那麼你就不需要 Spring-JDBC 模塊了,你需要的是這個 Spring-ORM 模塊。
- 簡單介紹一下 Spring WEB 模塊?
- Spring 的 WEB 模塊是構建在 application context 模塊基礎之上,提供一個適合 web 應用的上下文。這個模塊也包括支持多種面向 web 的任務,如透明地處理多個文件上傳請求和程序級請求參數的綁定到你的業務對象。
- Spring 配置文件有什麼作用?
- Spring 配置文件是個 XML 文件,這個文件包含了類信息,描述瞭如何配置它們,以及如何相互調用。
- 什麼是 Spring IOC 容器?
- IOC 控制反轉:Spring IOC 負責創建對象,管理對象。通過依賴注入(DI),裝配對象,配置對象,並且管理這些對象的整個生命週期。
- IOC 的優點是什麼?
- IOC 或 依賴注入把應用的代碼量降到最低;
- 它使應用容易測試,單元測試不再需要單例和 JNDI 查找機制;
- 最小的代價和最小的侵入性使鬆散耦合得以實現;
- IOC 容器支持加載服務時的餓漢式初始化和懶加載。
- ApplicationContext 的實現類有哪些?
- FileSystemXmlApplicationContext :此容器從一個 XML 文件中加載 beans 的定義,XML Bean 配置文件的全路徑名必須提供給它的構造函數;
- ClassPathXmlApplicationContext:此容器也從一個 XML 文件中加載 beans 的定義,這裏,你需要正確設置classpath 因爲這個容器將在 classpath 裏找 bean 配置;
- WebXmlApplicationContext:此容器加載一個 XML 文件,此文件定義了一個 WEB 應用的所有 bean。
- BeanFactory 與 AppliacationContext 有什麼區別?
- BeanFactory:
基礎類型的 IOC 容器,提供完成的 IOC 服務支持。如果沒有特殊指定,默認採用延遲初始化策略。相對來說,容
器啓動初期速度較快,所需資源有限。 - ApplicationContext“
ApplicationContext 是在 BeanFactory 的基礎上構建,是相對比較高級的容器實現,除了 BeanFactory 的所有
支持外,ApplicationContext 還提供了事件發佈、國際化支持等功能。ApplicationContext 管理的對象,在容器啓動
後默認全部初始化並且綁定完成。
- 什麼是 Spring 的依賴注入?
- java 開發中,程序員在某個類中需要依賴其它類的方法,則通常是 new 一個依賴類再調用類實例的方法,這種開發存在的問題是 new 的類實例不好統一管理。
- spring 提出了依賴注入的思想,即依賴類不由程序員實例化,而是通過 spring 容器幫我們 new 指定實例並且將實例注入到需要該對象的類中。
- 依賴注入的另一種說法是“控制反轉”,通俗的理解是:平常我們 new 一個實例,這個實例的控制權是我們程序員,而控制反轉是指 new 實例工作不由我們程序員來做而是交給 spring 容器來做。
- 有哪些不同類型的 IOC(依賴注入)方式?
- Set 注入
- 構造器注入
- 靜態工廠的方法注入
- 實例工廠的方法注入
- 什麼是 Spring beans?
- Spring beans 是那些形成 Spring 應用的主幹的 java 對象。
- 它們被 Spring IOC 容器初始化,裝配,和管理。
- 這些 beans 通過容器中配置的元數據創建。比如,以 XML 文件中 的形式定義。
- Spring 框架定義的 beans 都是單例 beans。
- 一個 Spring Beans 的定義需要包含什麼?
- 一個 Spring Bean 的定義包含容器必知的所有配置元數據,包括如何創建一個 bean,它的生命週期詳情及它的依賴。
- 怎樣定義類的作用域?
- 當定義一個 在 Spring 裏,我們還能給這個 bean 聲明一個作用域。它可以通過 bean 定義中的 scope 屬性來定義。
- 如,當 Spring 要在需要的時候每次生產一個新的 bean 實例,bean 的 scope 屬性被指定爲prototype。另一方面,一個 bean 每次使用的時候必須返回同一個實例,這個 bean 的 scope 屬性必須設爲singleton。
- Spring 支持的幾種 bean 的作用域?
- Spring 框架支持以下五種 bean 的作用域:
- singleton : bean在每個Spring ioc容器中只有一個實例,缺省的Spring bean的作用域是Singleton。
- prototype :一個bean的定義可以有多個實例。
- request :每次http請求都會創建一個bean,該作用域僅在基於web的Spring ApplicationContext情形下有效。
- session : 在一個HTTP Session中,一個bean定義對應一個實例。該作用域僅在基於web的Spring ApplicationContext 情形下有效。
- global-session:在一個全局的 HTTP Session 中,一個 bean 定義對應一個實例。該作用域僅在基於 web 的Spring ApplicationContext 情形下有效。
- Spring 框架中的單例 bean 是線程安全的嗎?
- 不是線程安全的。
- 什麼是 Spring 的內部 bean?
- 當一個 bean 僅被用作另一個 bean 的屬性時,它能被聲明爲一個內部 bean,爲了定義 inner bean,在Spring的基於XML的配置元數據中,可以在 < property/ >或 < constructor-arg/ >元素內使用< bean/ > 元素。
- 內部 bean 通常是匿名的,它們的 Scope 一般是 prototype。
- 在 Spring 中如何注入一個 java 集合?
- Spring 提供以下幾種集合的配置元素:
- < list >類型用於注入一列值,允許有相同的值。
- < set > 類型用於注入一組值,不允許有相同的值。
- < map > 類型用於注入一組鍵值對,鍵和值都可以爲任意類型。
- < props >類型用於注入一組鍵值對,鍵和值都只能爲 String 類型。
- 什麼是 bean 的自動裝配?
- 無須在 Spring 配置文件中描述 javaBean 之間的依賴關係;
- IOC 容器會自動建立 javabean 之間的關聯關係。
- 解釋不同方式的自動裝配?
- 有五種自動裝配的方式,可以用來指導Spring容器用自動裝配方式來進行依賴注入。
- no:默認的方式是不進行自動裝配,通過顯式設置 ref 屬性來進行裝配。
- byName:通過參數名自動裝配,Spring 容器在配置文件中發現 bean 的 autowire 屬性被設置成 byname,之後容器試圖匹配、裝配和該 bean 的屬性具有相同名字的 bean。
- byType:通過參數類型自動裝配,Spring 容器在配置文件中發現 bean 的 autowire 屬性被設置成 byType,之後容器試圖匹配、裝配和該 bean 的屬性具有相同類型的 bean。如果有多個 bean 符合條件,則拋出錯誤。
- constructor:這個方式類似於 byType, 但是要提供給構造器參數,如果沒有確定的帶參數的構造器參數類型,將會拋出異常。
- autodetect:首先嚐試使用 constructor 來自動裝配,如果無法工作,則使用 byType 方式。
- 什麼是基於 Java 的Spring 註解配置? 給一些註解的例子?
- 基於 Java 的配置,允許在少量的 Java 註解的幫助下,進行大部分 Spring 配置而非通過 XML 文件。
- 以@Configuration 註解爲例,它用來標記類可以當做一個 bean 的定義,被 Spring IOC 容器使用。
- 另一個例子是@Bean 註解,它表示此方法將要返回一個對象,作爲一個 bean 註冊進 Spring 應用上下文。
- 什麼是基於註解的容器配置?
- 相對於 XML 文件,註解型的配置依賴於通過字節碼元數據裝配組件,而非尖括號的聲明。
- 開發者通過在相應的類,方法或屬性上使用註解的方式,直接組件類中進行配置,而不是使用 xml 表述 bean 的裝配關係。
- 怎樣開啓註解裝配?
- 註解裝配在默認情況下是不開啓的,爲了使用註解裝配,必須在Spring配置文件中 配置 < context:annotation-config/ >元素。
- 在 Spring 框架中如何更有效地使用 JDBC?
- 使用 SpringJDBC 框架,資源管理和錯誤處理的代價都會被減輕。
- 開發者只需寫 statements 和 queries 從數據存取數據,JDBC 也可以在 Spring 框架提供的模板類的幫助下更有效地被使用,這個模板叫 JdbcTemplate 。
- JdbcTemplate 類提供了很多便利的方法解決諸如把數據庫數據轉變成基本數據類型或對象,執行寫好的或可調用的數據庫操作語句,提供自定義的數據錯誤處理。
- 使用 Spring 通過什麼方式訪問 Hibernate?
- 控制反轉 HibernateTemplate 和 Callback。
- 繼承 HibernateDAOSupport 提供一個 AOP 攔截器。
- Spring 支持的 ORM 框架有哪些?
- Hibernate、iBatis、JPA 、TopLink、JDO、OJB
- 簡單解釋一下 spring 的 AOP?
- AOP面向切面編程,可以說是OOP面向對象編程的補充和完善。
- OOP 引入封裝、繼承、多態等概念來建立一種對象層次結構,用於模擬公共行爲的一
個集合。 - OOP 允許開發者定義縱向的關係,但並不適合定義橫向的關係,例如日誌功能。
- 日誌代碼往往橫向地散佈在所有對象層次中,而與它對應的對象的核心功能毫無關係,對於其他類型的代碼,如安全性、異常處理也都是如此,這種散佈在各處的無關的代碼被稱爲橫切,在OOP設計中,它導致了大量代碼的重複,而不利於各個模塊的重用。
- AOP 技術恰恰相反,它利用"橫切"技術,剖解開被封裝的對象內部,將那些影響了多個類的公共行爲封裝到一個可重用模塊,將其命名爲"Aspect",即切面。
- 就是把那些與業務無關,卻爲業務模塊所共同調用的邏輯或責任封裝起來,便於減少系統的重複代碼,降低模塊之間的耦合度,並有利於未來的可操作性和可維護性。
- 使用"橫切"技術,AOP 把軟件系統分爲兩個部分:核心關注點和橫切關注點。
業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。- 橫切關注點的一個特點是,他們經常發生在覈心關注點的多處,而各處基本相似,比如權限認證、日誌、事物。AOP 的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。
- AOP 核心就是切面,它將多個類的通用行爲封裝成可重用的模塊,該模塊含有一組 API 提供橫切功能。比如,一個日誌模塊可以被稱作日誌的 AOP 切面。根據需求的不同,一個應用程序可以有若干切面。
- 在 Spring AOP 中,切面通過帶有@Aspect 註解的類實現。
- 在 Spring AOP 中,關注點和橫切關注的區別是什麼?
- 關注點是應用中一個模塊的行爲,一個關注點可能會被定義成一個我們想實現的一個功能。
- 橫切關注點是一個關注點,此關注點是整個應用都會使用的功能,並影響整個應用,比如日誌,幾乎應用的每個模塊都需要的功能。因此這些都屬於橫切關注點。
- 什麼是連接點?
- 被攔截到的點,因爲 Spring 只支持方法類型的連接點,所以在 Spring 中連接點指的就是被攔截到的方法,實際上連接點還可以是字段或者構造器。
- Spring 的通知是什麼?有哪幾種類型?
- 通知是個在方法執行前或執行後要做的動作,實際上是程序執行時要通過SpringAOP 框架觸發的代碼段。
- Spring 切面可以應用五種類型的通知:
- before:前置通知,在一個方法執行前被調用。
- after: 在方法執行之後調用的通知,無論方法執行是否成功。
- after-returning: 僅當方法成功完成後執行的通知。
- after-throwing: 在方法拋出異常退出時執行的通知。
- around: 在方法執行之前和之後調用的通知。
- 什麼是切點?
- 切入點是一個或一組連接點,通知將在這些位置執行。
- 可以通過表達式或匹配的方式指明切入點。
- 什麼是目標對象?
- 被一個或者多個切面所通知的對象。它通常是一個代理對象。也指被通知對象。
- 什麼是代理?
- 代理是通知目標對象之後創建的對象。
- 從客戶端的角度看,代理對象和目標對象是一樣的。
- 什麼是織入?什麼是織入應用的不同點?
- 織入是將切面和到其他應用類型或對象連接或創建一個被通知對象的過程。織入可以在編譯時,加載時,或運行時完成。
三、MyBatis
- Mybatis 中#和$的區別?
- #相當於對數據加上雙引號,$相當於直接顯示數據
- #將傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號。如:order by #user_id#,如果傳入的值是111,那麼解析成 sql 時的值爲 order by “111”, 如果傳入的值是 id,則解析成的 sql 爲 order by “id”;
- $將傳入的數據直接顯示生成在 sql 中。如:order by ,如果傳入的值是 111,那麼解析成 sql 時的值爲order by user_id, 如果傳入的值是 id,則解析成的 sql 爲 order by id;
- #方式能夠很大程度防止 sql 注入,$方式無法防止 Sql 注入。
- SQL注入即是指web應用程序對用戶輸入數據的合法性沒有判斷或過濾不嚴,攻擊者可以在web應用程序中事先定義好的查詢語句的結尾上添加額外的SQL語句,在管理員不知情的情況下實現非法操作,以此來實現欺騙數據庫服務器執行非授權的任意查詢,從而進一步得到相應的數據信息。
- $方式一般用於傳入數據庫對象,例如傳入表名。
- 一般能用#的就別用$.
- Mybatis 的編程步驟是什麼樣的?
- 創建 SqlSessionFactory
- 通過 SqlSessionFactory 創建 SqlSession
- 通過 sqlsession 執行數據庫操作
- 調用 session.commit()提交事務
- 調用 session.close()關閉會話
- JDBC 編程有哪些不足之處?MyBatis 是如何解決這些問題的?
- 數據庫鏈接創建、釋放頻繁造成系統資源浪費從而影響系統性能
- 解決:在 SqlMapConfig.xml 中配置數據鏈接池,使用連接池管理數據庫鏈接
- Sql語句寫在代碼中造成代碼不易維護,實際應用sql變化的可能較大,sql變動需要改變java代碼。
- 解決:將 Sql 語句配置在 XXXXmapper.xml 文件中與 java 代碼分離。
- 向 sql 語句傳參數麻煩,因爲 sql 語句的 where 條件不一定,可能多也可能少,佔位符需要和參數一一對應。
- 解決: Mybatis 自動將 java 對象映射至 sql 語句。
- 對結果集解析麻煩,sql 變化導致解析代碼變化,且解析前需要遍歷,如果能將數據庫記錄封裝成 pojo 對象解
析比較方便。- 解決:Mybatis 自動將 sql 執行結果映射至 java 對象。
- 使用 MyBatis 的 mapper 接口調用時有哪些要求?
- Mapper 接口方法名和 mapper.xml 中定義的每個 sql 的 id 相同
- Mapper 接口方法的輸入參數類型和 mapper.xml 中定義的每個 sql 的 parameterType 的類型相同
- Mapper 接口方法的輸出參數類型和 mapper.xml 中定義的每個 sql 的 resultType 的類型相同
- Mapper.xml 文件中的 namespace 即是 mapper 接口的類路徑。
- Mybatis 中一級緩存與二級緩存?
- 一級緩存: 基於 PerpetualCache 的 HashMap 本地緩存,其存儲作用域爲 Session,當 Session flush 或close 之後,該 Session 中的所有 Cache 就將清空。
- 二級緩存與一級緩存其機制相同,默認也是採用 PerpetualCache,HashMap 存儲,不同在於其存儲作用域爲Mapper(Namespace),並且可自定義存儲源,如 Ehcache。
-
- 對於緩存數據更新機制,當某一個作用域(一級緩存 Session/二級緩存 Namespaces)的進行了 C/U/D 操作後,默認該作用域下所有 select 中的緩存將被 clear。
- MyBatis 在 insert 插入操作時返回主鍵 ID的配置操作?
<insert id="insert" parameterType="com.test.User" keyProperty="userId"
useGeneratedKeys="true" >
- “keyProperty”表示返回的 id 要保存到對象的那個屬性中,“useGeneratedKeys”表示主鍵 id 爲自增長模式。
四、SpringBoot
- Spring Boot、Spring MVC 和 Spring 有什麼區別?
- Spring
- Spring最重要的特徵是依賴注入。所有 SpringModules 不是依賴注入就是 IOC 控制反轉。
- 當我們恰當的使用 DI 或者是 IOC 的時候,我們可以開發鬆耦合應用。鬆耦合應用的單元測試可以很容易的進行。
- Spring MVC
- Spring MVC 提供了一種分離式的方法來開發 Web 應用。
- 通過運用像 DispatcherServelet,MoudlAndView 和 ViewResolver 等一些簡單的概念,開發 Web 應用將會變的非常簡單。
- SpringBoot
- Spring 和 SpringMVC 的問題在於需要配置大量的參數。
- Spring Boot 通過一個自動配置和啓動的項來目解決這個問題。
- 爲了更快的構建產品就緒應用程序,Spring Boot 提供了一些非功能性特徵。
- 爲什麼要用SpringBoot?
- 獨立運行:
Spring Boot而且內嵌了各種servlet容器,Tomcat、Jetty等,現在不再需要打成war包部署到容器中,Spring Boot只要打成一個可執行的jar包就能獨立運行,所有的依賴包都在一個jar包內。 - 簡化配置:
spring-boot-starter-web啓動器自動依賴其他組件,簡少了maven的配置。 - 自動配置:
Spring Boot能根據當前類路徑下的類、jar包來自動配置bean,如添加一個spring-boot-starter-web啓動器就能擁有web的功能,無需其他配置。 - 無代碼生成和XML配置:
Spring Boot配置過程中無代碼生成,也無需XML配置文件就能完成所有配置工作,這一切都是藉助於條件註解完成的。 - 應用監控
Spring Boot提供一系列端點可以監控服務及應用,做健康檢測。
- Spring Boot 的核心配置文件有哪幾個?它們的區別是什麼?
- Spring Boot 中有以下兩種配置文件:
- bootstrap (.yml 或者 .properties)
- application (.yml 或者 .properties)
- bootstrap/ application 的區別:
- Spring Cloud 構建於 Spring Boot 之上,在 Spring Boot 中有兩種上下文,一種是 bootstrap,另外一種是 application, bootstrap 加載優先於 applicaton。
- bootstrap 主要用於從額外的資源來加載配置信息,還可以在本地外部配置文件中解密屬性。這兩個上下文共用一個環境,它是任何Spring應用程序的外部屬性的來源。bootstrap 裏面的屬性會優先加載,它們默認也不能被本地相同配置覆蓋。
- 對比 application 配置文件,bootstrap 配置文件具有以下幾個特性:
- boostrap 由父 ApplicationContext 加載,比 applicaton 優先加載
- boostrap 裏面的屬性不能被覆蓋
- Spring Boot 的配置文件有哪幾種格式?它們有什麼區別?
- 兩種格式: .properties和.yml
- 區別
- 書寫格式不同
- .yml格式不支持@propertySource註解導入配置
- SpringBoot的核心註解是哪個?它主要由那幾個註解組成?
- 啓動類上面的註解是@SpringBootApplication,它也是 Spring Boot 的核心註解,主要組合包含了以下 3 個註解:
- @SpringBootConfiguration:組合了 @Configuration 註解,實現配置文件的功能。
- @@EnableAutoConfiguration:打開自動配置的功能,也可關閉某個自動配置的選項
- @ComponentScan:Spring組件掃描。
- 開啓 Spring Boot 特性有哪幾種方式?
- 繼承spring-boot-starter-parent項目
- 導入spring-boot-dependencies項目依賴
- 運行 Spring Boot 有哪幾種方式?
- 打包用命令或者放到容器中運行
- 用 Maven/Gradle 插件運行
- 直接執行 main 方法運行
- Spring Boot 自動配置原理是什麼?
- Spring Boot的自動配置註解是@EnableAutoConfiguration, 從上面的@Import的類可以找到下面自動加載自動配置的映射。
org.springframework.core.io.support.SpringFactoriesLoader.loadFactoryNames(Class<?>, ClassLoader)
這個方法會加載類路徑及所有jar包下META-INF/spring.factories配置中映射的自動配置的類。
- @Configuration,@ConditionalOnClass就是自動配置的核心,首先它得是一個配置文件,其次根據類路徑下是否有這個類去自動配置。
- Spring Boot 的目錄結構是怎樣的?
- Spring Boot 與傳統項目最大的區別是,傳統項目都是打成 WAR 包部署到服務器上面,需要額外的 Servlet 容器, 而 Spring Boot 則可以直接打成 jar包,並內置集成了 Servlet 容器,通過命令 java -jar xx.jar 則可以直接運行,不需要獨立的 Servlet 容器。
- 在主入口類上加上 @SpringBootApplication 註解來開啓 Spring Boot 的各項能力,如自動配置、組件掃描等。
- 你如何理解 Spring Boot 中的 Starters?
-
Starters是什麼:
- Starters可以理解爲啓動器,它包含了一系列可以集成到應用裏面的依賴包,可以一站式集成Spring及其他技術,而不需要到處找示例代碼和依賴包。
- 如你想使用Spring JPA訪問數據庫,只要加入spring-boot-starter-data-jpa啓動器依賴就能使用了。
- Starters包含了許多項目中需要用到的依賴,它們能快速持續的運行,都是一系列得到支持的管理傳遞性依賴。
-
Starters命名:
- Spring Boot官方的啓動器都是以spring-boot-starter-命名的,代表了一個特定的應用類型。
- 第三方的啓動器不能以spring-boot開頭命名,它們都被Spring Boot官方保留。一般一個第三方的應該這樣命名,像mybatis的mybatis-spring-boot-starter。
-
Starters分類:
- Spring Boot應用類啓動器
- Spring Boot生產啓動器
- Spring Boot技術類啓動器
- 其他第三方啓動器
- Spring Boot 有哪幾種讀取配置的方式?
- 讀取application文件:
- @Value註解讀取方式
- @ConfigurationProperties註解讀取方式
- 讀取指定文件:
- @PropertySource+@Value註解讀取方式:
- @PropertySource+@ConfigurationProperties註解讀取方式
- Environment讀取方式
- 總結:
Spring Boot可以通過@PropertySource, @Value, @Environment,@ConfigurationProperties來綁定變量。
- Spring Boot 支持哪些日誌框架?推薦和默認的日誌框架是哪個?
- Spring Boot支持Java Util Logging, Log4j2, Lockback作爲日誌框架,如果使用starters啓動器,Spring Boot將使用Logback作爲默認日誌框架。
- Logback是最優秀的日誌框架,往資源目錄下創建一個logback-spring.xml即可
- 日誌初始化在ApplicationContext創建之前,所以@PropertySources加載的配置是讀取不到的,系統環境變量、Spring Environment及application,bootstrap配置文件中的信息可以讀取到
- 無論使用哪種日誌框架,Spring Boot都支持配置將日誌輸出到控制檯或者文件中。
- spring-boot-starter啓動器包含spring-boot-starter-logging啓動器並集成了slf4j日誌抽象及Logback日誌框架。
- pringBoot實現熱部署有哪幾種方式?
- 藉助Spring Loaded
- 引用Spring-boot-devtools依賴,當修改一個java類時就會熱更新。
- Spring Boot 配置加載順序?
- 使用 Spring Boot 會涉及到各種各樣的配置,如開發、測試、線上就至少 3 套配置信息了。Spring Boot 可以輕鬆的幫助我們使用相同的代碼就能使開發、測試、線上環境使用不同的配置。
- 在 Spring Boot 裏面,可以使用以下幾種方式來加載配置:
- properties文件;
- YAML文件;
- 系統環境變量;
- 命令行參數;
- 等等……
- Spring Boot 如何定義多套不同環境配置?
- 基於properties文件類型
- 基於yml文件類型,推薦此方式
- 基於Java代碼
- 指定Profile
-
Spring Boot 可以兼容老 Spring 項目嗎,如何做?
可以兼容,使用 @ImportResource 註解導入老 Spring 項目配置文件。 -
SpringBoot啓動方式?
- IDE 運行Application這個類的main方法
- 在springboot的應用的根目錄下運行mvn spring-boot:run
- 使用mvn install 生成jar後運行
- JavaBean是什麼時候創建的?
- 一個javaBean對象被創建,經過了如下方法調用:
SpringApplication.run(App.class,args);
refreshContext(context);
finishBeanFactoryInitialization(beanFactory);
beanFactory.preInstantiateSingletons();
getBean(beanName);
doGetBean();
- SpringBoot框架中,JavaBean都是單例的嗎?多例怎麼設置?
- spring bean作用域有以下5個:
- singleton(web項目中用不到):單例模式,當spring創建applicationContext容器的時候,spring會欲初始化所有的該作用域實例,加上lazy-init就可以避免預處理;
- prototype(web項目中用不到):原型模式,每次通過getBean獲取該bean就會新產生一個實例,創建後spring將不再對其管理;
- request:搞web的大家都應該明白request的域了吧,就是每次請求都新產生一個實例,和prototype不同就是創建後,接下來的管理,spring依然在監聽;
- session:每次會話,同上;
- global session:全局的web域,類似於servlet中的application。
- 爲什麼spring要默認是單例呢?
- 爲了性能:這個不用廢話了,單例不用每次都new,當然快了。
- 不需要多例:不需要多例會讓很多人迷惑,因爲spring mvc官方也沒明確說不可以多例。
- 單例是不安全的,會導致屬性重複使用:
- 不要在controller中定義成員變量。
- 萬一必須要定義一個非靜態成員變量時候,則通過註解@Scope(“prototype”),將其設置爲多例模式。
- 熱部署原理與熱加載區別是什麼?
- 部署方式
- 熱部署在服務器運行時重新部署項目
- 熱加載在運行時重新加載class
- 實現原理
- 熱部署直接重新加載整個應用
- 熱加載在運行時重新加載class
- 使用場景
- 熱部署更多的是在生產環境使用
- 熱加載則更多的是在開發環境使用
- SpringBoot多數據源事務如何管理
- @Async
- SpringBoot如何實現打包?
- pom文件中主要針對不同的環境設置對應的profile,其中默認激活的是dev環境的配置
- 然後配置需要包含和過濾的application.properties
- 然後使用maven的打包命令實現不同環境打包即可
- SpringBoot性能如何優化?
- tomcat內存調優
- 更改文件(catalina.sh)
- 啓動部分的優化
- 可以移除 @SpringBootApplication 和 @ComponentScan 兩個註解來禁用組件自動掃描,然後在我們需要的 bean 上進行顯式配置
- SpringBoot執行流程?
- 開始請求,
- 收集各種條件和回調接口,
- 通知started(),
- 創建並準備Environment,
- 通告environmentPrepared()
- 創建並初始化ApplicationContext
- 通告contextPrepare(),通告contextLoaded()
- 調用ApplicationContext的refresh()方法,完成最終程序啓動
- 執行ApplicationRunner和CommandlineRunner通告finished()
- 結束