日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

stringbuilder寻找字符串位置可能存在多个 java_Java 语言基础amp;String

發(fā)布時(shí)間:2023/12/10 java 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 stringbuilder寻找字符串位置可能存在多个 java_Java 语言基础amp;String 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Java 語言基礎(chǔ)

String ?

字符串的不可變性 ?

定義一個字符串

使用變量來賦值變量 ? ?

String s2 = s; ?

s2 保存了相同的引用值, 因?yàn)樗麄兇硗粋€對象 ?

字符串連接 ?

s = s.concat("ef"); ?

s 中保存的是一個重新創(chuàng)建出來的 string 對象的引用 ?

總結(jié)

一旦一個 string 對象在內(nèi)存(堆)中被創(chuàng)建出來, 他就無法被修改。特別要注意的是,String 類的所有方法都沒有改變字符串本身的值, 都是返回了一個新的對象。

如果你需要一個可修改的字符串, 應(yīng)該使用 StringBuffer 或者 StringBuilder。否則會有大量時(shí)間浪費(fèi)在垃圾回收上, 因?yàn)槊看卧噲D修改都有新的 string 對象被創(chuàng)建出來 ?

JDK 6 和 JDK 7 中 substring 的原理及區(qū)別 ?

調(diào)用 substring()時(shí)發(fā)生了什么??

你可能知道, 因?yàn)?x 是不可變的, 當(dāng)使用 x.substring(1,3)對 x 賦值的時(shí)候, 它會指向一個全新的字符串:?

JDK 6 中的 substring ?

String 是通過字符數(shù)組實(shí)現(xiàn)的。在 jdk 6 中, String 類包含三個成員變量:char value[], int offset, int count。他們分別用來存儲真正的字符數(shù)組, 數(shù)組的第一個位置索引以及字符串中包含的字符個數(shù)。?

String 是通過字符數(shù)組實(shí)現(xiàn)的。在 jdk 6 中, String 類包含三個成員變量:char value[], int offset, int count。他們分別用來存儲真正的字符數(shù)組, 數(shù)組的第一個位置索引以及字符串中包含的字符個數(shù)。

JDK 6 中的 substring 導(dǎo)致的問題 ? ?

如果你有一個很長很長的字符串, 但是當(dāng)你使用 substring 進(jìn)行切割的時(shí)候你只需要很短的一段。這可能導(dǎo)致性能問題, 因?yàn)槟阈枰闹皇且恍《巫址蛄?#xff0c; 但是你卻引用了整個字符串( 因?yàn)檫@個非常長的字符數(shù)組一直在被引用, 所以無法被回收, 就可能導(dǎo)致內(nèi)存泄露) 。在 JDK 6 中, 一般用以下方式來解決該問題, 原理其實(shí)就是生成一個新的字符串并引用他。?

內(nèi)存泄露:在計(jì)算機(jī)科學(xué)中, 內(nèi)存泄漏指由于疏忽或錯誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存。內(nèi)存泄漏并非指內(nèi)存在物理上的消失, 而是應(yīng)用程序分配某段內(nèi)存后, 由于設(shè)計(jì)錯誤, 導(dǎo)致在釋放該段內(nèi)存之前就失去了對該段內(nèi)存的控制, 從而造成了內(nèi)存的浪費(fèi) ?

JDK 7 中的 substring ?

上面提到的問題, 在 jdk 7 中得到解決。在 jdk 7 中, substring 方法會在堆內(nèi)存中創(chuàng)建一個新的數(shù)組。?

以上是 JDK 7 中的 subString 方法, 其使用 new String 創(chuàng)建了一個新字符串, 避免對老字符串的引用。從而解決了內(nèi)存泄露問題。

所以, 如果你的生產(chǎn)環(huán)境中使用的 JDK 版本小于 1.7, 當(dāng)你使用 String 的 subString方法時(shí)一定要注意, 避免內(nèi)存泄露。?

replaceFirst、 replaceAll、 replace 區(qū)別 ?

replace(CharSequence target, CharSequence replacement) , 用replacement 替換所有的 target, 兩個參數(shù)都是字符串。

replaceAll(String regex, String replacement) , 用 replacement 替換所有的regex 匹配項(xiàng), regex 很明顯是個正則表達(dá)式, replacement 是字符串。

replaceFirst(String regex, String replacement) , 基本和 replaceAll 相同, 區(qū)別是只替換第一個匹配項(xiàng)。可以看到, 其中 replaceAll 以及 replaceFirst 是和正則表達(dá)式有關(guān)的, 而 replace 和正則表達(dá)式無關(guān)。?

http://www.51gjie.com/java/771.html ?

String 對“ +” 的重載 ?

1、 String s = "a" + "b", 編譯器會進(jìn)行常量折疊(因?yàn)閮蓚€都是編譯期常量, 編譯期可知), 即變成 String s = "ab ?

2、 對于能夠進(jìn)行優(yōu)化的(String s = "a" + 變量 等)用 StringBuilder 的 append()方法替代, 最后調(diào)用 toString() 方法 (底層就是一個 new String()) ?

字符串拼接的幾種方式和區(qū)別 ?

字符串不變性與字符串拼接 ?

其實(shí), 所有的所謂字符串拼接, 都是重新生成了一個新的字符串。下面一段字符串拼接代碼:String s = "abcd";s = s.concat("ef");其實(shí)最后我們得到的 s 已經(jīng)是一個新的字符串了。?

使用+拼接字符串 ?

運(yùn)算符重載:在計(jì)算機(jī)程序設(shè)計(jì)中, 運(yùn)算符重載( 英語:operator overloading) 是多態(tài)的一種。運(yùn)算符重載, 就是對已有的運(yùn)算符重新進(jìn)行定義, 賦予其另一種功能, 以適應(yīng)不同的數(shù)據(jù)類型。?

語法糖:語法糖( Syntactic sugar), 也譯為糖衣語法, 是由英國計(jì)算機(jī)科學(xué)家彼得· 蘭丁發(fā)明的一個術(shù)語, 指計(jì)算機(jī)語言中添加的某種語法, 這種語法對語言的功能沒有影響, 但是更方便程序員使用。語法糖讓程序更加簡潔, 有更高的可讀性。?

Concat ?

StringBuffer ?

StringBuilder

StringUtils.join ?

除了 JDK 中內(nèi)置的字符串拼接方法, 還可以使用一些開源類庫中提供的字符串拼接方法名, 如 apache.commons 中提供的 StringUtils 類, 其中的 join 方法可以拼接字符串。String wechat = "Hollis";String introduce = "每日更新 Java 相關(guān)技術(shù)文章";System.out.println(StringUtils.join(wechat, ",", introduce)); ?

以上就是比較常用的五種在 Java 種拼接字符串的方式, 那么到底哪種更好用呢?為什么 Java 開發(fā)手冊中不建議在循環(huán)體中使用+進(jìn)行字符串拼接呢??

使用+拼接字符串的實(shí)現(xiàn)原理 ?

通過查看反編譯以后的代碼, 我們可以發(fā)現(xiàn), 原來字符串常量在拼接過程中, 是將String 轉(zhuǎn)成了 StringBuilder 后, 使用其 append 方法進(jìn)行處理的。

那 么 也 就 是 說 , J a v a 中 的 + 對 字 符 串 的 拼 接 , 其 實(shí) 現(xiàn) 原 理 是 使 用StringBuilder.append ? ?

concat 是如何實(shí)現(xiàn)的 ?

concat 方法的源代碼 ?

這段代碼首先創(chuàng)建了一個字符數(shù)組, 長度是已有字符串和待拼接字符串的長度之和, 再把兩個字符串的值復(fù)制到新的字符數(shù)組中, 并使用這個字符數(shù)組創(chuàng)建一個新的 String 對象并返回。

通過源碼我們也可以看到, 經(jīng)過 concat 方法, 其實(shí)是 new 了一個新的 String, 這也就呼應(yīng)到前面我們說的字符串的不變性問題上了。?

StringBuffer 和 StringBuilder ?

append 會直接拷貝字符到內(nèi)部的字符數(shù)組中, 如果字符數(shù)組長度不夠, 會進(jìn)行擴(kuò)展。

StringBuffer 和 StringBuilder 類似, 最大的區(qū)別就是 StringBuffer 是線程安全的,看一下 StringBuffer 的 append 方法。?

StringUtils.join 是如何實(shí)現(xiàn)的 ?

通過查看 StringUtils.join 的源代碼, 我們可以發(fā)現(xiàn), 其實(shí)他也是通過 StringBuilder來實(shí)現(xiàn)的。?

效率比較 ?

從結(jié)果可以看出, 用時(shí)從短到長的對比是:StringBuilderStringBuffer 在 StringBuilder 的基礎(chǔ)上, 做了同步處理, 所以在耗時(shí)上會相對多一些。

StringUtils.join 也是使用了 StringBuilder, 并且其中還是有很多其他操作, 所以耗時(shí)較長, 這個也容易理解。其實(shí) StringUtils.join 更擅長處理字符串?dāng)?shù)組或者列表的拼接。

那么問題來了, 前面我們分析過, 其實(shí)使用+拼接字符串的實(shí)現(xiàn)原理也是使用的StringBuilder, 那為什么結(jié)果相差這么多, 高達(dá) 1000 多倍呢??

我們可以看到反編譯后的代碼, 在 for 循環(huán)中, 每次都是 new 了一個 StringBuilder,然后再把 String 轉(zhuǎn)成 StringBuilder, 再進(jìn)行 append。而頻繁的新建對象當(dāng)然要耗費(fèi)很多時(shí)間了, 不僅僅會耗費(fèi)時(shí)間, 頻繁的創(chuàng)建對象, 還會造成內(nèi)存資源的浪費(fèi)。

所以, Java 開發(fā)手冊建議:循環(huán)體內(nèi), 字符串的連接方式, 使用 StringBuilder 的append 方法進(jìn)行擴(kuò)展。而不要使用+。?

總結(jié)

本文介紹了什么是字符串拼接, 雖然字符串是不可變的, 但是還是可以通過新建字符串的方式來進(jìn)行字符串的拼接。常用的字符串拼接方式有五種, 分別是使用+、 使用 concat、 使用 StringBuilder、 使用 StringBuffer 以及使用 StringUtils.join。由于字符串拼接過程中會創(chuàng)建新的對象, 所以如果要在一個循環(huán)體中進(jìn)行字符串拼接,就要考慮內(nèi)存問題和效率問題。

因此, 經(jīng)過對比, 我們發(fā)現(xiàn), 直接使用 StringBuilder 的方式是效率最高的。因?yàn)镾tringBuilder 天生就是設(shè)計(jì)來定義可變字符串和字符串的變化操作的。但是, 還要強(qiáng)調(diào)的是:1、 如果不是在循環(huán)體中進(jìn)行字符串拼接的話, 直接使用+就好了。2 、 如 果 在 并 發(fā) 場 景 中 進(jìn) 行 字 符 串 拼 接 的 話 , 要 使 用 St r i n g B u f f e r 來 代 替StringBuilder。?

String.valueOf 和 Integer.toString 的區(qū)別 ?

String.valueOf 和 Integer.toString 的區(qū)別 ?

1.int i = 5;2.String i1 = "" + i;3.String i2 = String.valueOf(i);4.String i3 = Integer.toString(i);第三行和第四行沒有任何區(qū)別, 因?yàn)?String.valueOf(i)也是調(diào)用 Integer.toString(i)來實(shí)現(xiàn)的。第二行代碼其實(shí)是 String i1 = (new StringBuilder()).append(i).toString();, 首先創(chuàng)建一個 StringBuilder 對象, 然后再調(diào)用 append 方法, 再調(diào)用 toString 方法。?

字符串池 ?

在 JVM 中, 為了減少相同的字符串的重復(fù)創(chuàng)建, 為了達(dá)到節(jié)省內(nèi)存的目的。會單獨(dú)開辟一塊內(nèi)存, 用于保存字符串常量, 這個內(nèi)存區(qū)域被叫做字符串常量池 ?

當(dāng)代碼中出現(xiàn)雙引號形式( 字面量) 創(chuàng)建字符串對象時(shí), JVM 會先對這個字符串進(jìn)行檢查, 如果字符串常量池中存在相同內(nèi)容的字符串對象的引用, 則將這個引用返回;否則,創(chuàng)建新的字符串對象, 然后將這個引用放入字符串常量池, 并返回該引用 ?

這種機(jī)制, 就是字符串駐留或池化 ?

字符串常量池的位置 ?

在 JDK 7 以前的版本中, 字符串常量池是放在永久代中的。

因?yàn)榘凑沼?jì)劃, JDK 會在后續(xù)的版本中通過元空間來代替永久代, 所以首先在 JDK7 中, 將字符串常量池先從永久代中移出, 暫時(shí)放到了堆內(nèi)存中。在 JDK 8 中, 徹底移除了永久代, 使用元空間替代了永久代, 于是字符串常量池再次從堆內(nèi)存移動到永久代中 ?

Class 常量池 ?

談到常量池, 在 Java 體系中, 共用三種常量池。分別是字符串常量池、 Class 常量池和運(yùn)行時(shí)常量池。?

Class 常量池可以理解為是 Class 文件中的資源倉庫。Class 文件中除了包含類的版本、 字段、 方法、 接口等描述信息外, 還有一項(xiàng)信息就是常量池(constant pool table),用于存放編譯器生成的各種字面量(Literal)和符號引用(Symbolic References)。?

常量池中有什么 ?

字面量 ?

用于表達(dá)源代碼中一個固定值的表示法( notation) ?

字面量只可以右值出現(xiàn), 所謂右值是指等號右邊的值, 如:int a=123 這里的 a 為左值, 123 為右值。在這個例子中 123 就是字面量 ?

符號引用 ?

符號引用是編譯原理中的概念, 是相對于直接引用來說的。主要包括了以下三類常量:* 類和接口的全限定名 * 字段的名稱和描述符 * 方法的名稱和描述符 ?

Class 常量池有什么用 ?

Class 常量池是 Class 文件中的資源倉庫, 其中保存了各種常量。而這些常量都是開發(fā)者定義出來, 需要在程序的運(yùn)行期使用的 ?

Class 是用來保存常量的一個媒介場所, 并且是一個中間場所。在 JVM 真的運(yùn)行時(shí), 需要把常量池中的常量加載到內(nèi)存中 ?

運(yùn)行時(shí)常量池 ?

它包括了若干種不同的常量:從編譯期可知的數(shù)值字面量到必須運(yùn)行期解析后才能獲得的方法或字段引用。運(yùn)行時(shí)常量池扮演了類似傳統(tǒng)語言中符號(SymbolTable)的角色,不過它存儲數(shù)據(jù)范圍比通常意義上的符號表要更為廣泛 ?

每一個運(yùn)行時(shí)常量池都分配在 Java 虛擬機(jī)的方法區(qū)之中, 在類和接口被加載到虛擬機(jī)后, 對應(yīng)的運(yùn)行時(shí)常量池就被創(chuàng)建出來 ?

intern ?(運(yùn)行時(shí))

在 JVM 中, 為了減少相同的字符串的重復(fù)創(chuàng)建, 為了達(dá)到節(jié)省內(nèi)存的目的。會單獨(dú)開辟一塊內(nèi)存, 用于保存字符串常量, 這個內(nèi)存區(qū)域被叫做字符串常量池。?

intern 的功能很簡單:在每次賦值的時(shí)候使用 String 的 intern 方法, 如果常量池中有相同值, 就會重復(fù)使用該對象, 返回對象引用。?

String 的長度限制 ?

那么, 明明 String 的構(gòu)造函數(shù)指定的長度是可以支持 2147483647(2^31 - 1)的, 為什么像以上形式定義的時(shí)候無法編譯呢?其實(shí), 形如 String s = "xxx";定義 String 的時(shí)候, xxx 被我們稱之為字面量, 這種字面量在編譯之后會以常量的形式進(jìn)入到 Class 常量池 ?

常量池限制 ?

字符串有長度限制, 在編譯期, 要求字符串常量池中的常量不能超過 65535, 并且在javac 執(zhí)行過程中控制了最大值為 65534。在運(yùn)行期, 長度不能超過 Int 的范圍, 否則會拋異常 ?

運(yùn)行期限制 ?

前面提到的這種 String 長度的限制是編譯期的限制, 也就是使用 String s= “ ” ;這種字面值方式定義的時(shí)候才會有的限制。

那么。String 在運(yùn)行期有沒有限制呢, 答案是有的, 就是我們前文提到的那個 Integer.MAX_VALUE , 這個值約等于 4G, 在運(yùn)行期, 如果 String 的長度超過這個范圍, 就可能會拋出異常 ?

總結(jié)

字符串有長度限制, 在編譯期, 要求字符串常量池中的常量不能超過 65535, 并且在javac 執(zhí)行過程中控制了最大值為 65534。在運(yùn)行期, 長度不能超過 Int 的范圍, 否則會拋異常。

最后, 這個知識點(diǎn) , 我錄制了視頻(https://www.bilibili.com/video/BV1uK4y1t7H1/),

其中有關(guān)于如何進(jìn)行實(shí)驗(yàn)測試、如何查閱 Java 規(guī)范以及如何對 javac 進(jìn)行 deubg 的技巧。歡迎進(jìn)一步學(xué)習(xí)。?

這是筆記!

作者 Hollis:https://github.com/hollischuang

總結(jié)

以上是生活随笔為你收集整理的stringbuilder寻找字符串位置可能存在多个 java_Java 语言基础amp;String的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。