【Java基礎】HashMap、HashTable與HashSet:區別、聯系與實踐指南

Java中HashMap、HashTable與HashSet的深度解析:區別、聯系與實踐指南

引言

在Java集合框架中,HashMap、HashTable與HashSet是最常用的哈希型數據結構。它們因高效的查找、插入與刪除性能(平均時間復雜度O(1)),廣泛應用于緩存設計、數據去重、鍵值映射等場景。但三者在設計定位、線程安全性、底層實現等方面存在顯著差異,若使用不當可能導致性能問題或邏輯錯誤。本文將從基礎概念出發,結合源碼與典型代碼,系統解析三者的核心特性,幫助開發者深入理解其適用場景。


一、基礎概念鋪墊:哈希表與集合的底層邏輯

1.1 Map與Set的核心定義

Java集合框架中,MapSet是兩大核心接口類型:

  • Map(鍵值對映射表):存儲Key-Value鍵值對,鍵(Key)具有唯一性,值(Value)可重復。典型實現包括HashMap、HashTable、TreeMap等。
  • Set(唯一元素集合):存儲無序且不重復的元素,本質是“只有鍵的Map”。典型實現包括HashSet、TreeSet、LinkedHashSet等。

二者的核心差異在于:Map關注鍵與值的映射關系,Set關注元素的唯一性。但從底層實現看,HashSet與HashMap存在強關聯(后文詳述)。

1.2 哈希表的底層原理

HashMap、HashTable與HashSet均基于**哈希表(Hash Table)實現。哈希表的核心思想是通過哈希函數(Hash Function)**將元素的鍵(或元素本身)映射到數組的某個位置(桶,Bucket),從而實現快速的增刪查操作。其關鍵步驟如下:

  1. 哈希計算:通過鍵的hashCode()方法計算哈希值,再通過(n-1) & hash(n為數組長度)將哈希值映射到數組索引(桶位置)。
  2. 沖突處理:不同鍵可能映射到同一桶(哈希沖突),Java采用鏈地址法解決:每個桶存儲一個鏈表(或紅黑樹),沖突元素按順序鏈入。
  3. 擴容機制:當元素數量超過容量×加載因子(閾值)時,哈希表會擴容(數組長度翻倍),并重新哈希所有元素到新數組。

關鍵概念

  • 容量(Capacity):哈希表底層數組的長度,默認16(HashMap/HashSet)或11(HashTable)。
  • 加載因子(Load Factor):觸發擴容的閾值比例,默認0.75(三者均如此)。
  • 閾值(Threshold):容量×加載因子,超過則觸發擴容。

二、HashMap深度解析:高效的非線程安全映射表

2.1 核心特性

HashMap是Java中使用最廣泛的Map實現,自JDK1.2引入,其核心特性如下:

  • 線程非安全:未使用同步機制,單線程環境下性能最優。
  • 支持null鍵值:允許1個null鍵(因鍵唯一)和任意數量的null值。
  • 底層結構進化:JDK1.7及之前使用“數組+鏈表”;JDK1.8優化為“數組+鏈表+紅黑樹”,當鏈表長度≥8且數組長度≥64時,鏈表轉為紅黑樹(查詢時間復雜度從O(n)降至O(logn))。

2.2 關鍵參數與底層細節

2.2.1 默認參數
  • 初始容量:16(DEFAULT_INITIAL_CAPACITY)。
  • 加載因子:0.75(DEFAULT_LOAD_FACTOR)。
  • 紅黑樹轉換閾值:8(TREEIFY_THRESHOLD)。
  • 紅黑樹退化為鏈表閾值:6(UNTREEIFY_THRESHOLD)。
  • 觸發樹化的最小數組長度:64(MIN_TREEIFY_CAPACITY)。
2.2.2 哈希計算邏輯

HashMap通過以下步驟計算桶索引:

// 鍵的原始hashCode()
int hash = key.hashCode();
// 高位異或(擾動函數):將高16位與低16位異或,減少哈希沖突
int擾動Hash = hash ^ (hash >>> 16);
// 計算桶索引(n為當前數組長度,必為2的冪次)
int bucketIndex = (n - 1) & 擾動Hash;

擾動函數的設計是為了讓哈希值的高位參與索引計算(因數組長度n較小,直接取模會丟失高位信息),從而降低沖突概率。

2.3 核心操作代碼示例

2.3.1 基礎操作
import java.util.HashMap;
import java.util.Map;public class HashMapDemo {public static void main(String[] args) {// 1. 創建HashMap(默認初始容量16,加載因子0.75)Map<String, Integer> map = new HashMap<>();// 2. 插入鍵值對(允許null鍵和null值)map.put("apple", 10);    // 常規鍵值map.put(null, 0);        // null鍵map.put("banana", null); // null值// 3. 查詢值Integer appleCount = map.get("apple");  // 10Integer nullKeyCount = map.get(null);   // 0// 4. 替換值(put()會覆蓋舊值)map.put("apple", 20);  // 原10被替換為20// 5. 刪除鍵值對map.remove("banana");  // 移除null值的鍵// 6. 遍歷鍵值對(推薦entrySet())for (Map.Entry<String, Integer> entry : map.entrySet()) {System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());}}
}
2.3.2 自定義鍵類型(重寫hashCode與equals)

若使用自定義類作為鍵,需重寫hashCode()equals()方法,否則無法正確判斷鍵的唯一性。例如:

class Student {private String id;private String name;public Student(String id, String name) {this.id = id;this.name = name;}// 重寫hashCode:基于id計算(保證相同id的對象哈希值相同)@Overridepublic int hashCode() {return id.hashCode();}// 重寫equals:僅比較id(保證相同id的對象視為同一鍵)@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return id.equals(student.id);}
}// 使用示例
Map<Student, String> studentMap = new HashMap<>();
Student s1 = new Student("001", "Alice");
Student s2 = new Student("001", "Bob"); // id相同,視為同一鍵
studentMap.put(s1, "Math");
studentMap.put(s2, "Physics"); // 覆蓋s1的值為"Physics"
System.out.println(studentMap.size()); // 輸出1(鍵唯一)

2.4 JDK1.8的關鍵優化:鏈表轉紅黑樹

在JDK1.7及之前,HashMap的底層結構是“數組+鏈表”。當鏈表過長時(如長度10),查詢時間復雜度退化為O(n)。JDK1.8引入紅黑樹優化:

  • 觸發樹化條件:鏈表長度≥8且數組長度≥64。
    (選擇8的原因:鏈表長度符合泊松分布,長度8的概率僅0.00000006,屬于小概率事件;若頻繁觸發樹化,說明哈希函數設計不合理。)
  • 樹化優勢:紅黑樹的查找、插入、刪除時間復雜度為O(logn),顯著優于鏈表的O(n)。
  • 退化條件:當樹的大小≤6時,紅黑樹退化為鏈表(避免頻繁樹化與退化的性能損耗)。

三、HashTable深度解析:線程安全的“老派”映射表

3.1 核心特性與歷史背景

HashTable是JDK1.0的“古董級”類,早于HashMap(JDK1.2)。其核心特性如下:

  • 線程安全:所有方法均用synchronized修飾(全局鎖),保證多線程操作的原子性。
  • 不支持null鍵值put(null, value)put(key, null)會拋出NullPointerException
  • 底層結構落后:JDK1.8仍使用“數組+鏈表”,無紅黑樹優化。
  • 設計定位過時:因全局鎖性能低下,已被ConcurrentHashMap(JDK1.5引入)替代。

3.2 關鍵參數與底層差異

3.2.1 默認參數
  • 初始容量:11(DEFAULT_INITIAL_CAPACITY)。
  • 加載因子:0.75(與HashMap一致)。
  • 擴容機制:舊容量×2+1(如初始11→擴容后23→47…),而HashMap是舊容量×2(始終為2的冪次)。
3.2.2 哈希計算邏輯

HashTable的哈希計算未做高位擾動,直接使用鍵的hashCode()取模:

int hash = key.hashCode();
int bucketIndex = (hash & 0x7FFFFFFF) % table.length; // 取模避免負數索引

這種方式在數組長度非2的冪次時,哈希沖突概率高于HashMap的(n-1) & hash(當n是2的冪次時,(n-1) & hash等價于hash % n,但位運算更快)。

3.3 核心操作代碼示例

3.3.1 基礎操作(注意null限制)
import java.util.Hashtable;public class HashTableDemo {public static void main(String[] args) {// 1. 創建HashTable(默認初始容量11,加載因子0.75)Hashtable<String, Integer> table = new Hashtable<>();// 2. 插入鍵值對(不允許null鍵或null值)table.put("apple", 10);    // 合法// table.put(null, 0);     // 拋出NullPointerException// table.put("banana", null); // 拋出NullPointerException// 3. 查詢值(與HashMap類似)Integer appleCount = table.get("apple"); // 10// 4. 線程安全演示(多線程插入)Runnable task = () -> {for (int i = 0; i < 1000; i++) {table.put(Thread.currentThread().getName() + "-" + i, i);}};Thread t1 = new Thread(task, "Thread-1");Thread t2 = new Thread(task, "Thread-2");t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("最終大小:" + table.size()); // 輸出2000(無數據丟失)}
}
3.3.2 性能對比(HashTable vs HashMap)

在單線程環境下,HashTable的全局鎖會帶來顯著性能損耗。測試插入100萬條數據:

// 單線程插入測試(時間單位:ms)
long start = System.currentTimeMillis();
Map<String, Integer> hashMap = new HashMap<>();
for (int i = 0; i < 1_000_000; i++) {hashMap.put("key-" + i, i);
}
System.out.println("HashMap耗時:" + (System.currentTimeMillis() - start)); // ~50msstart = System.currentTimeMillis();
Hashtable<String, Integer> hashTable = new Hashtable<>();
for (int i = 0; i < 1_000_000; i++) {hashTable.put("key-" + i, i);
}
System.out.println("HashTable耗時:" + (System.currentTimeMillis() - start)); // ~120ms

可見,單線程下HashTable性能約為HashMap的40%。

3.4 為什么HashTable被淘汰?

HashTable的全局鎖設計導致多線程競爭時,所有操作需串行執行(即使操作不同桶)。例如,線程1操作桶A,線程2操作桶B,仍需等待鎖釋放。而ConcurrentHashMap(JDK1.8)采用CAS+ synchronized細粒度鎖(僅鎖定鏈表頭或紅黑樹根節點),多線程性能提升10倍以上。因此,HashTable僅用于兼容舊代碼,新場景應優先選擇ConcurrentHashMap


四、HashSet深度解析:基于HashMap的唯一元素集合

4.1 核心特性

HashSet是Set接口的實現類,其核心特性如下:

  • 元素唯一性:依賴HashMap的鍵唯一性,通過add(E e)調用HashMap.put(e, PRESENT)實現(PRESENT是靜態常量)。
  • 無序性:元素存儲順序與插入順序無關(區別于LinkedHashSet的有序性)。
  • 線程非安全:底層依賴HashMap,未做同步處理。
  • 支持null元素:允許存儲1個null(因HashMap允許1個null鍵)。

4.2 與HashMap的依賴關系(源碼級解析)

查看HashSet的JDK源碼(JDK1.8):

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {// 底層依賴HashMap,元素作為鍵,值固定為PRESENTprivate transient HashMap<E, Object> map;private static final Object PRESENT = new Object();// 構造方法:初始化HashMappublic HashSet() {map = new HashMap<>();}// add方法:調用HashMap的put,若鍵已存在則返回舊值(null),否則返回nullpublic boolean add(E e) {return map.put(e, PRESENT) == null;}// contains方法:調用HashMap的containsKeypublic boolean contains(Object o) {return map.containsKey(o);}// remove方法:調用HashMap的removepublic boolean remove(Object o) {return map.remove(o) == PRESENT;}
}

可見,HashSet完全是HashMap的“包裝器”,其所有操作均委托給底層的HashMap實例,元素作為鍵存儲,值統一為靜態的PRESENT對象。

4.3 核心操作代碼示例

4.3.1 基礎操作
import java.util.HashSet;
import java.util.Set;public class HashSetDemo {public static void main(String[] args) {// 1. 創建HashSet(底層是HashMap)Set<String> set = new HashSet<>();// 2. 添加元素(允許1個null)set.add("apple");set.add("banana");set.add(null); // 合法set.add("apple"); // 重復元素,添加失敗// 3. 查詢元素是否存在boolean hasApple = set.contains("apple"); // trueboolean hasNull = set.contains(null);     // true// 4. 刪除元素set.remove("banana");// 5. 遍歷元素(迭代器或增強for)for (String element : set) {System.out.println(element); // 輸出:null, apple(順序不確定)}}
}
4.3.2 元素唯一性的實現原理

HashSet的元素唯一性由HashMap的鍵唯一性保證,依賴hashCode()equals()方法:

  • 若兩個元素的hashCode()不同,直接存儲在不同桶,視為不同元素。
  • hashCode()相同(哈希沖突),則通過equals()比較內容:若返回true,視為同一元素,不重復存儲;否則鏈入同一桶的鏈表/紅黑樹。

4.4 性能與HashMap的一致性

由于HashSet的所有操作均委托給HashMap,其時間復雜度與HashMap完全一致:

  • 插入(add()):O(1)(平均),O(n)(鏈表)或O(logn)(紅黑樹)(最壞)。
  • 查詢(contains()):O(1)(平均),O(n)或O(logn)(最壞)。
  • 刪除(remove()):O(1)(平均),O(n)或O(logn)(最壞)。

五、三者的區別對比:從設計到實現的全方位解析

為更清晰對比三者差異,我們從10個維度總結如下表:

維度HashMapHashTableHashSet
線程安全性非線程安全(無同步機制)線程安全(所有方法synchronized修飾,全局鎖)非線程安全(依賴底層HashMap)
是否支持null鍵/值支持null鍵(1個)、null值(任意)不支持null鍵或null值(拋NPE)支持null元素(1個,作為鍵存儲)
底層數據結構(JDK1.8+)數組+鏈表+紅黑樹(鏈表≥8且數組≥64時樹化)數組+鏈表(無紅黑樹優化)底層為HashMap(數組+鏈表+紅黑樹)
初始容量默認16(DEFAULT_INITIAL_CAPACITY默認11(DEFAULT_INITIAL_CAPACITY默認由底層HashMap決定(即16)
擴容機制舊容量×2(始終為2的冪次)舊容量×2+1(如11→23→47…)同HashMap(舊容量×2)
哈希計算邏輯擾動函數(高16位異或低16位)+(n-1)&hash直接取模(hash % table.length同HashMap(依賴鍵的哈希計算)
適用場景單線程鍵值映射(緩存、配置存儲等)兼容舊代碼(新場景推薦ConcurrentHashMap單線程元素去重、唯一性校驗
JDK版本引入JDK1.2JDK1.0(古董級)JDK1.2
父類/接口繼承AbstractMap,實現Map接口繼承已過時的Dictionary,實現Map接口繼承AbstractSet,實現Set接口
性能特點單線程性能最優(無鎖開銷)單線程性能差(全局鎖);多線程仍低效(鎖競爭)與HashMap一致(操作委托給底層HashMap)

六、實踐指南:如何選擇三者?

6.1 單線程場景:優先HashMap與HashSet

  • 鍵值映射需求:直接使用HashMap。其無鎖設計、紅黑樹優化及支持null的特性,完美適配緩存、配置存儲、對象屬性映射等場景。
    示例:緩存用戶信息(userId為鍵,User對象為值)。
  • 元素唯一性需求:使用HashSet。通過包裝HashMap實現,代碼簡潔且性能與HashMap一致。
    示例:去除列表中的重復元素(new HashSet<>(list)后轉回列表)。

6.2 多線程場景:避免HashTable,選擇ConcurrentHashMap

  • 鍵值映射需求:優先ConcurrentHashMap(JDK1.5+)。其采用CAS+細粒度鎖(僅鎖定鏈表頭或紅黑樹根節點),多線程性能遠超HashTable的全局鎖。
    示例:多線程統計日志中的IP訪問次數(ConcurrentHashMap<IP, Integer>)。
  • 元素唯一性需求:若需線程安全,可通過Collections.synchronizedSet(new HashSet<>())包裝,或直接使用CopyOnWriteArraySet(寫時復制,適合讀多寫少場景)。

6.3 兼容舊代碼:僅當必要時使用HashTable

HashTable僅推薦用于維護JDK1.0時代的遺留代碼。若項目需兼容極低版本JDK(如無ConcurrentHashMap),且必須保證線程安全,可謹慎使用;否則應升級為更高效的并發容器。


結語

HashMap、HashTable與HashSet是Java哈希型數據結構的核心成員,其設計差異本質上源于線程安全需求功能定位的不同:

  • HashMap以性能為優先,通過紅黑樹優化和無鎖設計成為單線程鍵值映射的首選;
  • HashTable因全局鎖的歷史局限性逐漸被淘汰,僅作為兼容方案存在;
  • HashSet通過“鍵唯一”的HashMap特性,簡潔實現了元素去重與唯一性校驗。

理解三者的底層邏輯與適用場景,是寫出高效、健壯Java代碼的關鍵。開發者應根據具體需求(線程安全、數據類型、性能要求)選擇合適的容器,避免“為了用而用”的錯誤實踐。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/94421.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/94421.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/94421.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

互聯網大廠Java面試實戰:核心技術棧與場景化提問解析(含Spring Boot、微服務、測試框架等)

互聯網大廠Java面試實戰&#xff1a;核心技術棧與場景化提問解析 本文通過模擬面試官與求職者謝飛機的對話&#xff0c;深入探討互聯網大廠Java開發的核心技術棧面試問題&#xff0c;涵蓋Java SE、Spring生態、微服務、大數據等多個領域&#xff0c;結合音視頻、電商、AIGC等業…

人工智能-python-深度學習-參數初始化與損失函數

文章目錄參數初始化與損失函數一、參數初始化1. 固定值初始化1.1 全零初始化1.2 全1初始化1.3 任意常數初始化2. 隨機初始化2.1 均勻分布初始化2.2 正態分布初始化3. Xavier初始化4. He初始化5. 總結二、損失函數1. 線性回歸損失函數1.1 MAE&#xff08;Mean Absolute Error&am…

Android Glide常見問題解決方案:從圖片加載到內存優化

全面總結Glide使用中的典型問題與解決方案&#xff0c;助力提升應用性能與用戶體驗作為Android開發中最流行的圖片加載庫之一&#xff0c;Glide以其簡單易用的API和強大的功能深受開發者喜愛。然而&#xff0c;在實際使用過程中&#xff0c;我們往往會遇到各種問題&#xff0c;…

linux系統ollama監聽0.0.0.0:11434示例

docker應用如dify訪問本地主機部署的ollama&#xff0c;base_url不管配"http://localhost:11434"&#xff0c;還是"http://host_ip:11434"都會報錯。這是因為1&#xff09;docker容器訪問http://localhost:11434&#xff0c;其實訪問的是docker容器自身的服…

Java微服務AI集成指南:LangChain4j vs SpringAI

今天想再完善一下做的微服務項目&#xff0c;想著再接入一個人工客服&#xff0c;于是學習了一下langchan4j的內容&#xff0c;未完一、技術定位辨析&#xff1a;LangChain4j vs Spring AI vs OpenAIOpenAI&#xff1a;AI模型提供商 提供大語言模型API&#xff08;如GPT-4o&…

華為光學設計面試題

16. 題目&#xff1a;設計一個用于機器視覺檢測的光學系統時&#xff0c;如何保證在高速運動下成像的清晰度和穩定性&#xff1f;(出處&#xff1a;華為智能制造光學檢測項目組招聘面試題)17. 題目&#xff1a;請說明在光學系統設計中&#xff0c;如何權衡景深和分辨率的關系&a…

vue3和react的異同點

這是一個前端領域非常核心的話題。Vue 3 和 React 都是極其優秀的現代前端框架&#xff0c;它們在理念和實現上既有相似之處&#xff0c;也有顯著區別。 下面我將從多個維度詳細對比它們的異同點。核心哲學與設計理念特性Vue 3React設計理念漸進式框架與 “救世主”聲明式 UI 庫…

assetbuddle hash 比對

1.測試 &#xff1a;當在預設上的數據有修改時&#xff0c;生成的ab也會有修改&#xff0c;具體到某個ab的.manifest里會有相應的變化&#xff0c;AssetFileHash 會修改 如圖所示&#xff1a; ManifestFileVersion: 0 CRC: 2818930197 Hashes: AssetFileHash: serializedVersio…

Spring Boot `@Configuration` 與 `@Component` 筆記

Spring Boot Configuration 與 Component 筆記 1?? 基本概念注解作用是否有代理適用場景Component標記普通組件&#xff0c;將類交給 Spring 容器管理? 沒有 CGLIB 代理普通 Bean&#xff0c;工具類、過濾器、監聽器等Configuration標記配置類&#xff0c;用來聲明 Bean? 有…

二、JVM 入門——(三)棧

棧的定義 棧也是一塊區域&#xff0c;用來存放數據的。棧也叫棧內存&#xff0c;主管Java程序的運行。 棧是私有的&#xff0c;是在線程創建時創建&#xff0c;所以它的生命期是跟隨線程的生命期&#xff0c;線程結束棧內存也就釋放。 因此對于棧來說不存在垃圾回收問題&…

深度學習入門第一課——神經網絡實現手寫數字識別

昨天我們講了深度學習的大致框架&#xff0c;下面我們用深度學習網絡來實現一個小項目——手寫數字識別。完整代碼import torch from torch import nn from torch.utils.data import DataLoader from torchvision import datasets from torchvision.transforms import ToTensor…

Vue中的scoped屬性

理解&#xff1a; 在 .vue 文件中&#xff0c;scoped 是 <style> 標簽的一個屬性&#xff0c;作用是讓樣式只作用于當前組件&#xff0c;避免樣式污染其他組件 scoped 讓樣式只在自己的組件內生效&#xff0c;不會影響到其他組件的同名元素 舉例 沒有 scoped 的情況&…

S2B2B系統哪個好,商淘云、數商云、金蝶云蒼穹供應鏈批發哪個比較靠譜

在數字化商業浪潮洶涌的當下&#xff0c;S2B2B系統已成為眾多企業優化供應鏈、提升運營效率、拓展業務版圖的關鍵利器。從大型企業的復雜產業鏈協同&#xff0c;到中小企業對上下游資源的整合與把控&#xff0c;S2B2B系統的身影無處不在。但面對市場上層出不窮的各類S2B2B系統&…

利用3臺機器搭建Kubernetes集群

文章目錄1 機器準備修改主機名(可選)配置IP地址和主機名映射關閉防火墻關閉swap2 安裝docker修改并更新軟件源安裝docker設置路由轉發規則&#xff0c;并使配置生效安裝 kubelet&#xff0c;kubeadm&#xff0c;kubectl3 初始化集群4 集群初始化5 work節點加入6 部署網絡插件本…

C6.3:發射結交流電阻

當一個小交流電壓加在發射結上&#xff0c;會產生發射極交流電流&#xff0c;該交流電流的大小取決于Q點位置&#xff0c;而曲線是彎曲的&#xff0c;所以Q點在曲線上的位置越高&#xff0c;發射極交流電流的峰值越大。發射極總電流是直流分量和交流分量疊加而成&#xff0c;即…

python中生成器

生成器是根據算法生成數據的一種機制&#xff0c;每次調用生成器只生成一個值&#xff0c;可以節省大量內存生成器推導式gg ( i * 2 for i in range(5))print(gg)print(next(gg)) # 0 print(next(gg)) # 2 print(next(gg)) # 4 print(next(gg)) # 6 print(next(gg)) # 8yield…

【RAGFlow代碼詳解-28】部署和基礎設施

Docker 部署架構 RAGFlow 使用多階段 Docker 構建過程和 Docker Compose 編排進行部署。該系統支持完整和輕量級部署變體。 多階段 Docker 構建構建過程由 Dockerfile 2-214中定義的三個階段組成&#xff1a; 基礎階段 &#xff1a;使用系統依賴項、ML 模型和運行時環境設置 Ub…

【prism】Prism 彈窗在 ViewModel 中控制大小的實踐總結

好 &#x1f44d; 這個思路非常適合寫成一篇 實用型博客&#xff0c;主題就是 “Prism 彈窗如何在 ViewModel 中控制窗口大小”。我幫你整理了一篇文章草稿&#xff0c;你可以直接拿去修改/發布。Prism 彈窗在 ViewModel 中控制大小的實踐總結 在 WPF 中使用 Prism 的 IDialogS…

項目管理進階——研發項目立項管理制度

為使公司研究開發(以下簡稱研發)項目的管理工作規范化、程序化、充分調度研發人員的積極性,提高研發成果的產出率和成果轉化率,特制定管理辦法。 一、 研發項目的立項: 原則上公司部設立基礎研究項目。研發項目的重點放在符合市場需要。能很快轉化成產品,或對現有生產工…

CMake構建學習筆記20-iconv庫的構建

1. 構建 iconv是一個用于在不同字符編碼&#xff08;如 UTF-8、GBK、ISO-8859-1 等&#xff09;之間進行轉換的開源庫。筆者在《c中utf8字符串和gbk字符串的轉換》這篇文章中介紹過如何在Windows下實現utf8字符串和gbk字符串的轉換&#xff0c;不過該實現是基于Win32 API的&am…