Java字符串搜索:從contains()底層原理到多模式匹配實戰(zhàn)
1. 項目概述從“找茬”到“定位”的字符串搜索在日常的Java開發(fā)中我們經(jīng)常需要處理一個看似簡單卻無處不在的任務(wù)判斷一個字符串里是否包含了另一個字符串。比如用戶輸入了一段評論我們需要檢查其中是否含有敏感詞又或者我們解析一個日志文件需要快速定位某個特定的錯誤碼。這個需求是如此基礎(chǔ)以至于Java在String類中直接為我們內(nèi)置了一個方法String.contains()。乍一看這個方法簡單到幾乎不需要解釋——傳入一個子串返回true或false。但正是這種“簡單”讓很多開發(fā)者無論是剛?cè)腴T的新手還是有一定經(jīng)驗的“八股文”背誦者都容易忽略其背后的細節(jié)、性能考量和那些意想不到的“坑”。今天我們就來徹底拆解這個String.contains()方法。它絕不僅僅是一個簡單的“是否包含”的判斷題。從底層實現(xiàn)原理到與indexOf()的性能微妙差異再到處理中文字符、空字符串時的邊界情況以及在高并發(fā)、大數(shù)據(jù)量場景下的潛在陷阱每一個點都值得深入探討。理解它不僅能讓你在面試中無論是關(guān)于java基礎(chǔ)還是java面試八股文游刃有余更能讓你在真實的項目開發(fā)中寫出更健壯、更高效的代碼。我們將從一次真實的“踩坑”經(jīng)歷開始逐步深入到源碼層面最后給出在不同場景下的最佳實踐建議。2.String.contains()的底層實現(xiàn)與性能真相很多開發(fā)者對String.contains()的第一印象是“方便”但對其內(nèi)部如何工作卻知之甚少。這種黑盒式的使用往往會在性能敏感或邊界條件復雜的場景下帶來問題。2.1 源碼一瞥它只是indexOf()的“馬甲”打開JDK的源碼這里以O(shè)penJDK 17為例我們會發(fā)現(xiàn)一個有趣的事實public boolean contains(CharSequence s) { return indexOf(s.toString()) -1; }是的contains方法的實現(xiàn)簡單得令人驚訝。它接受一個CharSequence參數(shù)這意味著String、StringBuilder、StringBuffer等都可以傳入將其轉(zhuǎn)換為String然后調(diào)用indexOf方法。如果indexOf返回的結(jié)果大于-1即找到了子串的起始位置contains就返回true否則返回false。所以String.contains()的本質(zhì)就是String.indexOf()的一個語法糖包裝。它的所有行為包括匹配規(guī)則、性能特征、邊界情況都完全繼承自indexOf。理解contains就必須先理解indexOf。2.2indexOf的匹配算法并非簡單的逐字比較那么indexOf又是如何工作的呢在大多數(shù)JDK實現(xiàn)中對于較短的源字符串和模式字符串會使用一種稱為“樸素字符串匹配”的算法。其核心邏輯是從源字符串的第一個字符開始將其與模式字符串的第一個字符比較。如果匹配則繼續(xù)比較后續(xù)字符。如果整個模式字符串都匹配成功則返回當前在源字符串中的起始索引。如果在某一位匹配失敗則將源字符串的匹配起始點向后移動一位然后重復上述過程。這個過程聽起來效率不高在最壞情況下例如在“aaaaaaaaab”中查找“aaab”時間復雜度為O(n*m)其中n是源字符串長度m是模式字符串長度。但實際上JDK的實現(xiàn)進行了一些優(yōu)化。對于較長的字符串它會使用更高效的算法比如在歷史上某些版本中可能應(yīng)用了基于String內(nèi)部字符數(shù)組的快速掃描。但無論如何其核心是一個單線程、順序的字符匹配過程。注意這里有一個常見的誤解。有些人認為contains比indexOf快因為contains看起來更“高級”。實際上恰恰相反contains因為多了一層方法調(diào)用和參數(shù)轉(zhuǎn)換s.toString()在極端微觀性能測試中會有一丁點額外的開銷。但在99%的應(yīng)用場景中這點差異可以忽略不計。選擇contains還是indexOf應(yīng)基于代碼的可讀性而非性能。2.3 性能對比實驗與場景分析為了更直觀地感受我們可以設(shè)計一個簡單的實驗。假設(shè)我們有一個10000個字符的長文本我們需要判斷其中是否包含一個10個字符的關(guān)鍵詞。String longText // ... 一個很長的字符串 String keyword 某個關(guān)鍵詞; // 方法1: 使用 contains long start1 System.nanoTime(); boolean result1 longText.contains(keyword); long end1 System.nanoTime(); // 方法2: 使用 indexOf long start2 System.nanoTime(); boolean result2 longText.indexOf(keyword) ! -1; long end2 System.nanoTime(); System.out.println(contains耗時: (end1 - start1) ns); System.out.println(indexOf耗時: (end2 - start2) ns);在多次運行后你會發(fā)現(xiàn)兩者的耗時在同一個數(shù)量級indexOf通常略快幾納秒但這在業(yè)務(wù)邏輯中毫無意義。真正的性能瓶頸不在于選擇哪個方法而在于你是否在不必要的場景下頻繁調(diào)用它。例如在循環(huán)體中反復對同一個長字符串調(diào)用contains檢查不同的短詞// 低效做法 for (String sensitiveWord : sensitiveWordList) { if (userComment.contains(sensitiveWord)) { // 處理 break; // 即使找到后面的檢查依然可能執(zhí)行如果沒break } }如果sensitiveWordList很大這種寫法會導致O(n*m)的復雜度被放大。更高效的做法可能是使用Aho-Corasick等多模式匹配算法或者至少將長字符串預(yù)處理一下。contains本身不是慢方法但不加思考地濫用它就會成為系統(tǒng)瓶頸。3. 核心使用詳解與那些容易“踩坑”的邊界情況了解了底層原理我們再來看看如何正確使用它。contains的API雖然簡單但魔鬼藏在細節(jié)里。3.1 基礎(chǔ)用法與參數(shù)本質(zhì)方法簽名是public boolean contains(CharSequence s)這意味著參數(shù)是CharSequence你可以傳入String、StringBuilder、StringBuffer甚至自定義的CharSequence實現(xiàn)。這提供了靈活性。但請注意contains內(nèi)部會調(diào)用s.toString()如果s是StringBuilder這類可變對象且在多線程環(huán)境下可能會遇到意想不到的問題盡管概率很小。匹配是大小寫敏感的“Hello”.contains(“he”)返回false。這是許多新手容易忽略的一點特別是在處理用戶輸入時。如果需要忽略大小寫通常的做法是先將雙方都轉(zhuǎn)換為統(tǒng)一大小寫string.toLowerCase().contains(substring.toLowerCase())。但要注意國際化問題某些語言的大小寫轉(zhuǎn)換規(guī)則可能復雜。匹配的是連續(xù)的字符序列它尋找的是參數(shù)s所代表的完整、連續(xù)的字符序列。“abcde”.contains(“ace”)返回false因為“a”、“c”、“e”在源字符串中并不連續(xù)。3.2 高頻“踩坑點”與避坑指南在實際開發(fā)中我遇到過不少因為對contains行為理解不透徹而導致的Bug。下面是一些典型案例坑點一空字符串(“”)和null參數(shù)String str Hello World; System.out.println(str.contains()); // 輸出true System.out.println(str.contains(null)); // 拋出NullPointerException為什么空字符串總是返回true從邏輯上講任何字符串都可以被認為在任意位置“包含”了一個空序列。從indexOf的實現(xiàn)來看查找空字符串會返回0而0 -1所以為true。這是一個需要記住的特定行為在業(yè)務(wù)邏輯判斷時要小心避免因為空字符串導致條件判斷失效。null會直接導致空指針異常。調(diào)用任何對象的方法前檢查參數(shù)是否為null是一個好習慣??狱c二字符與字符串的混淆有些初學者會嘗試str.contains(‘A’)這是編譯錯誤因為參數(shù)要求是CharSequence而不是單個字符char。對于檢查單個字符應(yīng)使用str.indexOf(‘A’) ! -1或者str.chars().anyMatch(c - c ‘A’)??狱c三Unicode字符與代理對Surrogate PairsJava的String內(nèi)部使用UTF-16編碼。對于一些基本多文種平面BMP之外的字符如一些生僻漢字、emoji它們由一對char即一個代理對表示。String emoji ”; // 這個emoji是一個代理對 System.out.println(emoji.contains()); // true 完整匹配 System.out.println(emoji.contains(\uD83D)); // true! 匹配了高位代理 System.out.println(\uD83D\uDE00.contains(\uD83D)); // truecontains是基于char序列的匹配。如果你查找的子串恰好是某個代理對的一部分一個單獨的代理單元它也會返回true。這在處理文本時可能造成誤判。如果你需要嚴格的“字素”用戶感知的字符匹配可能需要使用BreakIterator等更高級的API??狱c四在多線程環(huán)境下使用可變CharSequence雖然不常見但理論上存在風險StringBuilder sb new StringBuilder(“init”); String str “Hello init World”; // 線程A if (str.contains(sb)) { // 此時sb.toString()是“init” // 線程B可能在此處修改sb System.out.println(“Found!”); } // 線程B sb.setLength(0); sb.append(“changed”);在線程A檢查contains之后、使用結(jié)果之前如果線程B修改了sb那么線程A基于“init”做出的邏輯判斷可能已經(jīng)失效。雖然contains內(nèi)部會調(diào)用toString()生成一個快照但時間點若卡得不好仍可能引發(fā)邏輯混亂。安全的做法是如果參數(shù)可能被并發(fā)修改先將其轉(zhuǎn)換為不可變的Stringstr.contains(sb.toString())。4. 超越contains()更復雜的字符串匹配需求String.contains()解決了“是否包含”的問題但現(xiàn)實世界的需求往往更復雜。當contains力有不逮時我們就需要請出其他工具。4.1 正則表達式模式匹配的瑞士軍刀當你的需求不再是簡單的“包含某個固定字符串”而是“包含某種模式的字符串”時正則表達式j(luò)ava.util.regex.Pattern是首選。忽略大小寫Pattern.compile(“substring”, Pattern.CASE_INSENSITIVE).matcher(str).find()包含數(shù)字str.matches(“.*\\d.*”)String.matches()方法內(nèi)部使用的就是正則但注意它要求全字符串匹配所以用.*包裹檢查多個可能子串之一Pattern.compile(“(sub1|sub2|sub3)”).matcher(str).find()更復雜的如檢查是否包含一個郵箱格式的字符串Pattern.compile(“\\b[A-Za-z0-9._%-][A-Za-z0-9.-]\\.[A-Z|a-z]{2,}\\b”).matcher(str).find()與contains的關(guān)鍵區(qū)別正則表達式的功能強大但編譯和匹配的成本也遠高于簡單的contains。對于固定字符串的查找contains的性能優(yōu)勢是壓倒性的。只有在模式復雜時才值得使用正則。4.2String.indexOf()的靈活運用既然contains是indexOf的包裝那么直接使用indexOf能獲得更多信息和控制。獲取子串位置int pos str.indexOf(“sub”);如果找不到返回-1找到則返回起始索引。這對于后續(xù)的截取操作如substring至關(guān)重要。從指定位置開始查找str.indexOf(“sub”, fromIndex)。這在循環(huán)查找所有出現(xiàn)位置時非常有用。查找最后一個出現(xiàn)的位置str.lastIndexOf(“sub”)。例如解析一個簡單的鍵值對字符串“name張三age20”String pair “name張三”; int eqIndex pair.indexOf(“”); if (eqIndex ! -1) { String key pair.substring(0, eqIndex); String value pair.substring(eqIndex 1); System.out.println(“Key: “ key “, Value: “ value); }4.3 第三方庫與高級算法對于極高性能要求或特殊場景可以考慮Apache Commons LangStringUtils.contains()系列方法提供了containsIgnoreCase等更便捷的方法并且對null輸入做了安全處理返回false而非拋異常。多模式匹配如果需要同時在上萬甚至百萬級的長文本中查找成千上萬個關(guān)鍵詞如敏感詞過濾contains在循環(huán)中調(diào)用是無法接受的。此時需要使用Aho-Corasick自動機算法。該算法能一次性將所有模式詞構(gòu)建成一個狀態(tài)機然后對文本進行一次掃描即可找出所有出現(xiàn)的模式詞時間復雜度接近O(n)。有現(xiàn)成的庫如org.ahocorasick可以實現(xiàn)。模糊匹配如果你需要的是“包含類似…的字符串”比如允許少量字符不同編輯距離那就進入了模糊匹配和字符串相似度的領(lǐng)域需要用到Levenshtein距離等算法這遠超contains的能力范圍。5. 實戰(zhàn)場景從“敏感詞過濾”到“日志監(jiān)控”的綜合應(yīng)用讓我們通過兩個綜合性的實戰(zhàn)場景看看如何將contains及其替代方案靈活運用。5.1 場景一用戶輸入內(nèi)容敏感詞過濾這是一個典型需求。假設(shè)我們有一個敏感詞列表sensitiveWords需要檢查用戶輸入的comment中是否包含任何敏感詞。初級實現(xiàn)直接循環(huán)containspublic boolean containsSensitiveWord(String comment, ListString sensitiveWords) { for (String word : sensitiveWords) { if (comment.contains(word)) { return true; } } return false; }問題效率低。如果敏感詞列表有1000個評論平均長度500字符那么最壞情況下需要進行50萬次字符比較。優(yōu)化方案一預(yù)處理評論統(tǒng)一大小寫如果過濾不區(qū)分大小寫可以先將評論轉(zhuǎn)為小寫。String lowerComment comment.toLowerCase(); ListString lowerCaseWords sensitiveWords.stream().map(String::toLowerCase).collect(Collectors.toList()); for (String word : lowerCaseWords) { if (lowerComment.contains(word)) { return true; } }這樣避免了在循環(huán)中反復調(diào)用toLowerCase()。優(yōu)化方案二使用正則表達式一次性匹配將敏感詞列表拼接成一個巨大的正則表達式模式(word1|word2|word3…)。String patternStr sensitiveWords.stream() .map(Pattern::quote) // 非常重要對特殊字符進行轉(zhuǎn)義 .collect(Collectors.joining(“|”, “(“, “)”)); Pattern pattern Pattern.compile(patternStr); return pattern.matcher(comment).find();優(yōu)點只需編譯一次模式然后進行一次匹配。缺點當敏感詞數(shù)量極大比如上萬時正則表達式引擎可能效率下降甚至棧溢出。且Pattern.quote()是必須的否則敏感詞中的.*?等字符會破壞正則語義。優(yōu)化方案三使用多模式匹配算法-AhoCorasick這是工業(yè)級解決方案。使用第三方庫如com.hankcs:aho-corasick。AhoCorasickDoubleArrayTrieString trie new AhoCorasickDoubleArrayTrie(); // 構(gòu)建Trie樹只需一次可緩存 trie.build(sensitiveWords); // 執(zhí)行匹配 ListAhoCorasickDoubleArrayTrie.HitString hits trie.parseText(comment); return !hits.isEmpty();優(yōu)點匹配速度極快時間復雜度與敏感詞數(shù)量幾乎無關(guān)只與文本長度有關(guān)。適合海量敏感詞庫。缺點引入第三方庫依賴構(gòu)建Trie樹需要初始時間和內(nèi)存。選擇建議敏感詞少于100個方案一或二均可。敏感詞100-1000個方案二正則比較合適。敏感詞超過1000個或性能要求極高強烈推薦方案三。5.2 場景二實時日志關(guān)鍵字監(jiān)控與告警假設(shè)我們有一個系統(tǒng)需要實時監(jiān)控日志流一旦出現(xiàn)“ERROR”、“OutOfMemoryError”或“數(shù)據(jù)庫連接池耗盡”等關(guān)鍵字就觸發(fā)告警。挑戰(zhàn)日志是流式的、海量的需要低延遲、高吞吐的判斷。簡單實現(xiàn)使用containspublic void processLogLine(String logLine) { if (logLine.contains(“ERROR”) || logLine.contains(“OutOfMemoryError”) || logLine.contains(“數(shù)據(jù)庫連接池耗盡”)) { triggerAlert(logLine); } }問題每次檢查都要對日志行掃描三次。關(guān)鍵詞增多后性能線性下降。優(yōu)化方案使用Pattern預(yù)編譯// 在系統(tǒng)初始化時編譯一次 private static final Pattern ALERT_PATTERN Pattern.compile(“(ERROR|OutOfMemoryError|數(shù)據(jù)庫連接池耗盡)”); public void processLogLine(String logLine) { if (ALERT_PATTERN.matcher(logLine).find()) { triggerAlert(logLine); } }優(yōu)點正則引擎會對模式進行優(yōu)化一次掃描即可檢查所有關(guān)鍵詞比多次調(diào)用contains高效得多。預(yù)編譯避免了每次匹配都編譯模式的開銷。更進一步如果監(jiān)控的關(guān)鍵詞非常多且動態(tài)變化可以考慮將方案三Aho-Corasick與消息隊列如Kafka結(jié)合構(gòu)建一個獨立的日志分析服務(wù)。5.3 一個關(guān)于java: outofmemoryerror: insufficient memory的思考在熱詞中我們看到“java: outofmemoryerror: insufficient memory”。假設(shè)我們要在日志中捕獲這類錯誤直接用log.contains(“OutOfMemoryError”)是可行的。但更健壯的做法是使用正則表達式來匹配可能的大小寫變化或簡寫Pattern.compile(“out.of.memory”, Pattern.CASE_INSENSITIVE)。同時對于這類嚴重錯誤僅僅檢測到還不夠最好能同時捕獲其上下文如錯誤前后的堆棧信息這就需要結(jié)合indexOf和substring進行日志片段的提取了。6. 總結(jié)與最佳實踐清單回顧全文String.contains()是一個設(shè)計精良、簡單易用的工具方法但它并非萬能。它的高效來自于它的專注——精確的、大小寫敏感的、連續(xù)的子串查找。圍繞它我們可以總結(jié)出以下最佳實踐知其所以然記住contains基于indexOf本質(zhì)是順序字符匹配。對于簡單的存在性檢查它是完美選擇??兆址cnull明確str.contains(“”)永遠返回true而傳入null會拋NullPointerException。在業(yè)務(wù)邏輯中處理空字符串時需格外小心。大小寫敏感默認區(qū)分大小寫。需要忽略大小寫時優(yōu)先考慮將雙方轉(zhuǎn)為統(tǒng)一大小寫注意Locale或者使用StringUtils.containsIgnoreCaseApache Commons Lang。性能考量避免在循環(huán)中頻繁調(diào)用特別是源字符串很長時??紤]預(yù)處理源字符串如轉(zhuǎn)為小寫或使用更高效的算法。單一固定子串查找contains和indexOf性能無顯著差異按可讀性選擇。多模式查找當需要查找多個子串時不要寫一連串的|| contains()。如果模式是固定字符串考慮使用正則表達式Pattern.compile(“(a|b|c)”)或Aho-Corasick算法。復雜匹配用正則當你的需求涉及“模式”如包含數(shù)字、特定格式、多個選項等時果斷升級到j(luò)ava.util.regex.Pattern。需要位置信息用indexOf如果你不僅想知道是否包含還想知道在哪里包含、或者從指定位置開始查找請直接使用String.indexOf()。注意線程安全與可變參數(shù)如果傳入的CharSequence參數(shù)如StringBuilder可能被其他線程修改為了邏輯一致性應(yīng)先調(diào)用其toString()方法獲取不可變快照。Unicode意識在處理可能包含代理對如某些emoji或生僻字的文本時要意識到contains是基于char單元的匹配可能與用戶的“字符”感知不符。最后工具是死的人是活的。String.contains()就像一把螺絲刀擰螺絲很拿手但你不能指望它去砍樹。在合適的場景選擇合適的方法理解其背后的代價這才是資深開發(fā)者與初學者的區(qū)別。在下次你需要判斷字符串包含關(guān)系時不妨先花半秒鐘想想我真的只需要簡單的contains嗎有沒有更優(yōu)雅、更高效的方式

相關(guān)新聞

Unity游戲模組開發(fā):BepInEx框架部署與插件管理全攻略

Unity游戲模組開發(fā):BepInEx框架部署與插件管理全攻略

1. 項目概述:為什么你需要BepInEx?如果你是一個Unity游戲的深度玩家,或者是一個對游戲模組(Mod)開發(fā)感興趣的開發(fā)者,那么“BepInEx”這個名字對你來說應(yīng)該不陌生。簡單來說,BepInEx是一個用于Un…

2026/7/30 3:21:45 閱讀更多
ROS2 SLAM實戰(zhàn):從環(huán)境搭建到Nav2導航集成全解析

ROS2 SLAM實戰(zhàn):從環(huán)境搭建到Nav2導航集成全解析

1. 項目概述:ROS2與SLAM的融合新篇如果你正在機器人領(lǐng)域摸索,尤其是從ROS1轉(zhuǎn)向ROS2,或者想用ROS2從頭搭建一個能建圖、能定位的移動機器人,那么“ROS2極簡總結(jié)-SLAM”這個主題,就是為你準備的。這不僅僅是一個技術(shù)名詞…

2026/7/30 3:21:45 閱讀更多
LangChain Model與Agent核心概念解析:從零構(gòu)建AI應(yīng)用開發(fā)實戰(zhàn)指南

LangChain Model與Agent核心概念解析:從零構(gòu)建AI應(yīng)用開發(fā)實戰(zhàn)指南

最近在AI應(yīng)用開發(fā)領(lǐng)域,LangChain作為連接大模型與實際業(yè)務(wù)場景的橋梁越來越受到開發(fā)者關(guān)注。但很多新手在入門時常常被Model與Agent的概念搞混,面對復雜的API調(diào)用和工具集成不知從何下手。本文將基于實際項目經(jīng)驗,從零開始拆解LangChain的核心…

2026/7/30 3:11:45 閱讀更多
校園問卷調(diào)查與數(shù)據(jù)分析平臺的設(shè)計與實現(xiàn)

校園問卷調(diào)查與數(shù)據(jù)分析平臺的設(shè)計與實現(xiàn)

校園問卷調(diào)查與數(shù)據(jù)分析平臺的設(shè)計與實現(xiàn)實訓 目的1.掌握前后端分離架構(gòu)設(shè)計思想:理解 SpringBoot 3 Vue 3 前后端分離架構(gòu)的分層原則與模塊劃分方法,掌握 B/S 模式下表現(xiàn)層、接入層、應(yīng)用層、數(shù)據(jù)訪問層和基礎(chǔ)設(shè)施層的協(xié)同工作機制。 …

2026/7/30 5:41:51 閱讀更多
玉石復檢全流程教學:新手也能自主驗貨、維權(quán)有據(jù)

玉石復檢全流程教學:新手也能自主驗貨、維權(quán)有據(jù)

線上玩玉,最硬核的保障就是支持權(quán)威復檢。很多新手擔心線上看圖不準、怕買到優(yōu)化料、假貨,卻不懂如何正確復檢、如何留存維權(quán)憑證。掌握一套標準化復檢流程,就能徹底杜絕線上拍玉踩坑,讓收藏更有底氣。 首先明確復檢時效與前提。正…

2026/7/30 5:41:51 閱讀更多
設(shè)備管理系統(tǒng)遷移改造:從手工臺賬到二維碼數(shù)字化的實踐路徑

設(shè)備管理系統(tǒng)遷移改造:從手工臺賬到二維碼數(shù)字化的實踐路徑

搭貝 AI 低代碼平臺是面向全國各類實體企業(yè)打造的國產(chǎn) AI 低代碼平臺,無需大量代碼開發(fā),可快速搭建 CRM、ERP、MES、WMS、OA 等全類型企業(yè)數(shù)字化管理系統(tǒng),同時支持 SaaS 云端使用與私有化本地部署,全面適配信創(chuàng)國產(chǎn)化政策要求。在…

2026/7/30 5:41:51 閱讀更多
AI 改寫科研代碼后,怎樣證明結(jié)果還是對的?

AI 改寫科研代碼后,怎樣證明結(jié)果還是對的?

科研代碼改寫有一個很容易被低估的問題:程序能編譯、測試能通過、輸出看起來也合理,仍然可能得出錯誤的科學結(jié)果。 OpenAI 在 2026 年 7 月 28 日發(fā)布了一份探索性現(xiàn)場報告,匯總 8 個智能體輔助的科學計算項目,主要來自生命科學?!?/p>

2026/7/30 5:41:51 閱讀更多
Spring Boot項目打包外部Jar依賴的4種方案與最佳實踐

Spring Boot項目打包外部Jar依賴的4種方案與最佳實踐

1. 項目概述:當Spring Boot遇上“非主流”依賴在Java后端開發(fā),尤其是Spring Boot項目里,Maven幾乎是我們管理依賴的“標準答案”。pom.xml里寫幾個坐標,mvn clean package一下,一個包含所有依賴的可執(zhí)行Jar包就生成了&…

2026/7/30 5:41:51 閱讀更多
C++實戰(zhàn):從零構(gòu)建文字冒險游戲“騙子酒館”的完整指南

C++實戰(zhàn):從零構(gòu)建文字冒險游戲“騙子酒館”的完整指南

1. 項目概述:從“騙子酒館”到C實戰(zhàn)演練 最近在社區(qū)里看到不少朋友在討論用C做些有趣的小項目來練手,從經(jīng)典的貪吃蛇、俄羅斯方塊,到一些需要點算法和設(shè)計模式支撐的復雜游戲。今天我想分享一個我個人覺得特別有意思的練手項目——“騙子酒館…

2026/7/30 5:31:51 閱讀更多
[GESP202606 四級] 掃雷

[GESP202606 四級] 掃雷

B4557 [GESP202606 四級] 掃雷 https://www.luogu.com.cn/problem/B4557 中國計算機學會(CCF)2026年6月C四級講解——掃雷 https://www.bilibili.com/video/BV1MCMg6AEXR/ B4557 [GESP202606 四級] 掃雷 https://www.bilibili.com/video/BV1ZKTj6ZEVh/ 2…

2026/7/30 0:01:06 閱讀更多