Oh! You closed up the window, so you cannot see raining

[Java] 淺談 Java MVC

前言 MVC MVC 是一種軟體架構模式。 模型 (Model) 視圖 (View) 控制器 (Controller) 目的是實現一種動態且有彈性的程式設計,使後續對程式設計的維護與擴充都變得更容易,另一方面也能使程式的某一部分被重複使用而提升設計效率。 SSH SSH 是 MVC 的一種,是常用的系統框架,由下面三種集合而成: Struts Spring Hibernate SSM SSH 是 MVC 的一種,是常用的系統框架,由下面三種集合而成: Spring-MVC Spring MyBatis SSH v.s. SSM Spring-MVC v.s. Struts Struts 和 Spring-MVC 都負責取轉發,但兩者針對 request 的請求上區別很大, Struts 是針對一個 Action class 來進行 request,即一個 Action 對應一個 request,屬於類攔截,請求的數據類共享。 Spring-MVC 則是針對 method 級別的 request,即一個 method 對應一個 request,屬於方法攔截,請求的數據方法不共享。 Spring-MVC 的配置文件相對較少,容易上手,方便開發。 Spring-MVC 的入口是 Servlet 級別的而 Struts 的級別是 Filter 級別的。 Hibernate v.s. MyBatis Hibernate 是一種 O/R 關係型,即完成資料庫和持久化類別之間的映射;而 MyBatis 是針對的 SQL-Mapping。猶如 Hibernate 是對資料庫封裝完成後,調用相對應的語句(HQL)來控制資料庫;而 MyBatis 是用原生的資料庫語法。 基於以上原因,Hibernate 的優化較 MyBatis 難,MyBatis 不需要額外學習新的語法,入門較快。 對於更高級的 Queuy,MyBatis 需要編寫 SQL 語句與 ResultMap。而 Hibernate 有因應的映射機制,無需關心 SQL 的生成與結果映射,可以專注於開發流程。 Hibernate 的資料庫移植性很好,MyBatis 的資料庫移植性不好,不同的資料庫需要寫不同的 SQL。 Spring Spring、Spring MVC、Spring Boot Spring 是一種框架,包含一系列的 IoC 容器的設計和依賴注入(DI) 及 整合AOP功能。 Spring MVC 是一種以 Spring 為核心的框架。 Spring Boot 是一種以 Spring 為核心的框架,同時又能簡化配置(configuration)。 Spring 的核心基礎 DI DI = 依賴注入 Dependency Injection 一種 coding style,為了未來在維護上能更加的靈活,概念類似: // 1 System....

<span title='2022-04-29 15:38:18 +0800 +0800'>April 29, 2022</span>&nbsp;·&nbsp;3 min&nbsp;·&nbsp;Rain Hu
Oh! You closed up the window, so you cannot see raining

[Java] HashMap中的hashCode設計原理

程式碼 static final int hash(Object key){ int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } h » 16 的用途 h是key.hashCode(),h >>> 16代表的是取其高位的16位 key.hashCode() ^ (h » 16) 這與 Java1.8 中 tab[(n-1) & hash] 的原理有關 static int indexFor(int h, int length){ return h & (length - 1); } 返回的值即為陣列的下標。 大多數情況下,capacity 都小於2^16,所以在此的 & 運算,只會對 h 的低16位進行 & 運算。 若將高位16位也加入計算,可以增加下標的發散度,避免衝突的次數。 而使用 XOR 的原因是,更較於 AND 或 OR 均勻,因為 AND 會使結果趨向於 0,OR 會使結果趨向於 1。

<span title='2022-04-22 11:22:39 +0800 +0800'>April 22, 2022</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;Rain Hu
Oh! You closed up the window, so you cannot see raining

[Java] 面試常見問題

1. 請說明 Final, Finally, Finalize 三者不同? Final: 一種修飾關鍵字。 加在變數前,使變數成為常數。 加在方法前,使方法無法被覆寫(override)。 加在類別前,使類別不能被繼承(extend)。 Finally: 例外處理關鍵字,Try-Catch-Finally 功能為保證一定執行,用意是做資源釋放。 Finalize: 是Object類別的方法,故所有物件都一定有此方法。 當物件要銷毀前會執行的方法,此外可以透過 System.gc() 呼叫資源回收。 2. 請說明 String 字串中 == 與 .equals() 哪裡不同? ==: 比較儲存的值,基本型別(primitives)是儲存在 Stack 中,因此值會相同,字串是儲存在 String Pool 中,故 Stack 中存的是址。 使用 == 比較字串時,其實是比較他們的址。 equals(): 是 String 覆寫後的 equals 方法,比較值。 補充: Java 的字串有 String Pool 機制,當宣告一個新的字串時,Java 會先去 String Pool 中尋找是否有相同的字串,有則共用,無則新增。 若使用 String s1 = "Hello World"; 來宣告,則會透過字串池。 若使用 String s2 = new String("Hello World") 來宣告,則字串會存在 Heap 中,與上者的址不同。 3....

<span title='2022-03-16 02:45:45 +0800 +0800'>March 16, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;Rain Hu
Oh! You closed up the window, so you cannot see raining

[Java] transient 關鍵字

1. transient 的作用及使用方法 當一個物件繼承(implements)了 Serializable 介面,這個物件就可以被序列化,Java 的序列化模式為開發者提供了許多便利,開發者可以不必關心具體序列化的過程,只要繼承了 Serializable 介面,該類別(class)的所有屬性(property)和方法(method)都會自動序列化。 然而在實際開發過程中,有些屬性需要序列化,有些屬性則不需要。 用戶的私密訊息如密碼、銀行帳號等,通常不希望在網路操作時被傳輸。 此時,便可在這些對應的變數前加上 transient。 如此一來,這些私密訊息的生命週期只會存在於調用者的記憶體(memory)中,不會寫到磁碟(disk)裡。 注意讀取時,讀取數據的順序一定要和存放數據的順序保持一致。 範例: import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.Serializable; public class TransientExample { public static void main(String[] args){ User user = new User(); user.setUsername("Rain"); user.setPassword("12345678"); System.out.println("Read before Serializable: "); System.out.println("Username: " + user.getUsername()); System.out.println("Password: " + user.getPassword()); try { ObjectOutput os = new ObjectOutputStream(new FileOutputStream("/Users/rainhu/workspace/algo/temp/user.txt")); os.writeObject(user); os.flush(); os....

<span title='2022-03-08 23:53:27 +0800 +0800'>March 8, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;Rain Hu
Oh! You closed up the window, so you cannot see raining

[Java] Integer.bitCount 解析

Integer.bitCount 的函式解析 要計算整數以二進制的方式表示時,所有 bit 位為 1 的總和。 雛形 從低位開始,檢查是否為 1。 public static int bitCount(int i){ int count = 0; while (i > 0) { if ((i & 1) == 1) // 如果最低位為 1,count就加 1 count++; i >>= 1; // 向右推進 1 位,等同於 num /= 2; } return count; } 時間複雜度為 \(O(n)\),\(n\) 為整數的位數(bit 數)。 優化 利用(i - 1) & i 可以消除最低位數的 1 的性質來計算。 public static bitCount(int i){ int count = 0; while (i > 0){ i = i & (i - 1); // 0b0101_1100 - 1 = 0b0101_1011, 且 0b0101_1100 & 0b0101_1011 = 0b0101_1000; count++; } return count; } 時間複雜度為 \(O(n))\),\(n\) 為位數為 1 的個數。 利用 int 的特性再優化 因為 int 的最大正整數為 2^31,故我們可以兩兩錯位相加來求和 private static int bitCount(int i){ i = (i & 0x55555555) + ((i >>> 1) & 0x55555555); // 0b0101_0101_0101_0101_0101_0101_0101_0101 i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); // 0b0011_0011_0011_0011_0011_0011_0011_0011 i = (i & 0x0f0f0f0f) + ((i >>> 4) & 0x0f0f0f0f); // 0b0000_1111_0000_1111_0000_1111_0000_1111 i = (i & 0x00ff00ff) + ((i >>> 8) & 0x00ff00ff); // 0b0000_0000_1111_1111_0000_0000_1111_1111 i = (i & 0x0000ffff) + ((i >>>16) & 0x0000ffff); // 0b0000_0000_0000_0000_1111_1111_1111_1111 return i; } 時間複雜度為 \(O(1))\)。 Source Code(final) public static int bitCount(int i) { // HD, Figure 5-2 i = i - ((i >>> 1) & 0x55555555); i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); i = (i + (i >>> 4)) & 0x0f0f0f0f; i = i + (i >>> 8); i = i + (i >>> 16); return i & 0x3f; } 一、三、四、五步不進行消位,在最後再利用 i & 0x3f 消去不必要的位數

<span title='2022-03-01 20:37:02 +0800 +0800'>March 1, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;Rain Hu