摘要:閱讀原文面試別再問我了字符串廣泛應用在編程中,在中字符串屬于對象,提供了類來創建和操作字符串。測試此字符串是否以指定的后綴結束。當執行此句時,因為對應的實例已經存在于字符串常量池中,所以會將此實例復制到會在堆中并返回引用地址。
閱讀原文:面試別再問我String了
字符串廣泛應用 在Java 編程中,在 Java 中字符串屬于對象,Java 提供了 String 類來創建和操作字符串。
String 簡介String定義:
public final class String implements java.io.Serializable, Comparable為什么設計為不可變類呢?, CharSequence {}
String設計為不可變類主要考慮到:效率和安全。
效率:1.在早期的JVM實現版本中,被final修飾的方法會被轉為內嵌調用以提升執行效率。而從Java SE5/6開始,就漸漸擯棄這種方式了。因此在現在的Java SE版本中,不需要考慮用final去提升方法調用效率。只有在確定不想讓該方法被覆蓋時,才將方法設置為final。2.緩存hashcode,String不可變,所以hashcode不變,這樣緩存才有意義,不必重新計算。
安全:String常被作為網絡連接,文件操作等參數類型,倘若可改變,會出現意想不到的結果。
測試掌握程度為了不浪費你的時間,請看下面的題目,若你一目了然,可以跳過本文了。
public class Test { public static void main(String[] args) { String str1 = "HelloFlyapi"; String str2 = "HelloFlyapi"; String str3 = new String("HelloFlyapi"); String str4 = "Hello"; String str5 = "Flyapi"; String str6 = "Hello" + "Flyapi"; String str7 = str4 + str5; System.out.println("str1 == str2 result: " + (str1 == str2)); System.out.println("str1 == str3 result: " + (str1 == str3)); System.out.println("str1 == str6 result: " + (str1 == str6)); System.out.println("str1 == str7 result: " + (str1 == str7)); System.out.println("str1 == str7.intern() result: " + (str1 == str7.intern())); System.out.println("str3 == str3.intern() result: " + (str3 == str3.intern())); } }String 的創建方式
從上面的題中你會知道,String的創建方式有兩種:
直接賦值
此方式在方法區中字符串常量池中創建對象
String str = "flyapi";構造器
此方式在堆內存創建對象
String str = new String();分析
要理解String,那么要了解JVM內存中的棧(stack)、堆(heap)和方法區。簡要圖如下:
str1 == str2
String str1 = "HelloFlyapi"; String str2 = "HelloFlyapi"; System.out.println(str1 == str2); // true
當執行第一句時,JVM會先去常量池中查找是否存在HelloFlyapi,當存在時直接返回常量池里的引用;當不存在時,會在字符創常量池中創建一個對象并返回引用。
當執行第二句時,同樣的道理,由于第一句已經在常量池中創建了,所以直接返回上句創建的對象的引用。
str1 == str3
String str1 = "HelloFlyapi"; String str3 = new String("HelloFlyapi"); System.out.println(str1 == str3); // false
執行第一句,同上第一句。
執行第二句時,會在堆(heap)中創建一個對象,當字符創常量池中沒有‘HelloFlyapi’時,會在常量池中也創建一個對象;當常量池中已經存在了,就不會創建新的了。
str1 == str6
String str1 = "HelloFlyapi"; String str6 = "Hello" + "Flyapi"; System.out.println(str1 == str6); // true
由于"Hello"和"Flyapi"都是常量,編譯時,第二句會被自動編譯為‘String str6 = "HelloFlyapi";’
str1 == str7
String str1 = "HelloFlyapi"; String str4 = "Hello"; String str5 = "Flyapi"; String str7 = str4 + str5; System.out.println(str1 == str7); // false
其中前三句變量存儲的是常量池中的引用地址。
第四句執行時,JVM會在堆(heap)中創建一個以str4為基礎的一個StringBuilder對象,然后調用StringBuilder的append()方法完成與str5的合并,之后會調用toString()方法在堆(heap)中創建一個String對象,并把這個String對象的引用賦給str7。
常用方法下面是 String 類支持的方法,更多詳細,參看 Java String API 文檔:
方法 | 描述 |
---|---|
char charAt(int index) | 返回指定索引處的 char 值。 |
int compareTo(Object o) | 把這個字符串和另一個對象比較。 |
int compareTo(String anotherString) | 按字典順序比較兩個字符串。 |
boolean endsWith(String suffix) | 測試此字符串是否以指定的后綴結束。 |
boolean equals(Object anObject) | 將此字符串與指定的對象比較。 |
boolean equalsIgnoreCase(String anotherString) | 將此 String 與另一個 String 比較,不考慮大小寫。 |
byte[] getBytes() | 使用平臺的默認字符集將此 String 編碼為 byte 序列,并將結果存儲到一個新的 byte 數組中。 |
byte[] getBytes(String charsetName) | 使用指定的字符集將此 String 編碼為 byte 序列,并將結果存儲到一個新的 byte 數組中。 |
int indexOf(int ch) | 返回指定字符在此字符串中第一次出現處的索引。 |
int indexOf(int ch, int fromIndex) | 返回在此字符串中第一次出現指定字符處的索引,從指定的索引開始搜索。 |
int indexOf(String str) | 返回指定子字符串在此字符串中第一次出現處的索引。 |
int indexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中第一次出現處的索引,從指定的索引開始。 |
String intern() | 返回字符串對象的規范化表示形式。 |
int lastIndexOf(int ch) | 返回指定字符在此字符串中最后一次出現處的索引。 |
int lastIndexOf(int ch, int fromIndex) | 返回指定字符在此字符串中最后一次出現處的索引,從指定的索引處開始進行反向搜索。 |
int lastIndexOf(String str) | 返回指定子字符串在此字符串中最右邊出現處的索引。 |
int lastIndexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中最后一次出現處的索引,從指定的索引開始反向搜索。 |
int length() | 返回此字符串的長度。 |
boolean matches(String regex) | 告知此字符串是否匹配給定的正則表達式。 |
String replace(char oldChar, char newChar) | 返回一個新的字符串,它是通過用 newChar 替換此字符串中出現的所有 oldChar 得到的。 |
String replaceAll(String regex, String replacement) | 使用給定的 replacement 替換此字符串所有匹配給定的正則表達式的子字符串。 |
String replaceFirst(String regex, String replacement) | 使用給定的 replacement 替換此字符串匹配給定的正則表達式的第一個子字符串。 |
String[] split(String regex) | 根據給定正則表達式的匹配拆分此字符串。 |
String[] split(String regex, int limit) | 根據匹配給定的正則表達式來拆分此字符串。 |
boolean startsWith(String prefix) | 測試此字符串是否以指定的前綴開始。 |
boolean startsWith(String prefix, int toffset) | 測試此字符串從指定索引開始的子字符串是否以指定前綴開始。 |
String substring(int beginIndex) | 返回一個新的字符串,它是此字符串的一個子字符串。 |
String substring(int beginIndex, int endIndex) | 返回一個新字符串,它是此字符串的一個子字符串。 |
char[] toCharArray() | 將此字符串轉換為一個新的字符數組。 |
String toLowerCase() | 使用默認語言環境的規則將此 String 中的所有字符都轉換為小寫。 |
String toUpperCase() | 使用默認語言環境的規則將此 String 中的所有字符都轉換為大寫。 |
String trim() | 返回字符串的副本,忽略前導空白和尾部空白。 |
由于String的不可變性導致,字符串變更時效率低下,在之后得JDK版本中出現了StringBuilder和StringBuffer.
類 | 可變性 | 線程安全 |
---|---|---|
String | 不可變 | 安全 |
StringBuffer | 可變 | 安全 |
StringBuilder | 可變 | 非安全 |
使用選擇
當有少量連接操作時,使用String
當單線程下有大量連接操作時,使用StringBuilder
當多線程下有大量連接操作時,使用StringBuffer
常見String面試題String str = new String("abc")創建了多少個實例?
這個問題其實是不嚴謹的,但面試一般會遇到,所以我們要補充來說明。
類的加載和執行要分開來講:
創建了兩個當加載類時,"abc"被創建并駐留在了字符創常量池中(如果先前加載中沒有創建駐留過)。
當執行此句時,因為"abc"對應的String實例已經存在于字符串常量池中,所以JVM會將此實例復制到會在堆(heap)中并返回引用地址。
通過字節碼我們可以看到:
源碼:String str = new String("abc")
字節碼:
Code: 0: new #2 // class java/lang/String 3: dup 4: ldc #3 // String abc 6: invokespecial #4 // Method java/lang/String."":(Ljava/lang/String;) 9: astore_1 10: return
執行時僅(#2)創建了一個對象。
關于這個面試題,可以看看一個超大牛的回答:http://rednaxelafx.iteye.com/...
本文優先發布于微信公眾號:碼上實戰 和 GitHub 上。
GitHub flyhero
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/73991.html
摘要:例如資源的獲取,支持多種消息例如的支持,對多了工具級別的支持等待。最上面的知道吧我就不講了。生命周期事件回調等。他支持不同信息源頭,支持工具類,支持層級容器,支持訪問文件資源,支持事件發布通知,支持接口回調等等。 廣義的 IOC IoC(Inversion of Control) 控制反轉,即不用打電話過來,我們會打給你。 兩種實現: 依賴查找(DL)和依賴注入(DI)。 IOC 和...
摘要:閱讀原文小而有料的想聽文章核心內容語音對話版,請到微信公眾號碼上實戰,閱讀原文這塊肉雖然小,但不可不知,因為不僅面試可能會問,實際中也常使用。參考書籍編程思想深入理解虛擬機更多精彩技術文章盡在微信公眾號碼上實戰 閱讀原文:小而有料的final(想聽文章核心內容語音對話版,請到微信公眾號——碼上實戰,閱讀原文) final這塊肉雖然小,但不可不知,因為不僅面試可能會問,實際中也常使用。就...
摘要:所以構造函數里的指的就是將要被出來的新對象。希望看完這篇文章之后,再有人問指向的問題,你可以嘴角微微上揚,冷笑一聲不要再問我的指向問題了。 this的指向已經是一個老生常談的問題,每逢面試都要去復習復習,近來鞏固js的基礎,決心徹底掌握這個知識點,一勞永逸。說明一下,為了不影響大家的思考過程,下面的代碼都不會去注釋答案,想知道答案,只需要去控制臺執行一下。 四類場景逐一擊破 首先,分析...
摘要:不過大多數講解還停留在對功能使用的層面,其底層的很多原理,很多人可能并不知曉。每個線程池里的線程就僅僅用于請求那個服務。 歡迎關注微信公眾號:石杉的架構筆記(id:shishan100) 每日更新!精品技術文章準時送上! 目錄 一、業務場景介紹 二、Spring Cloud核心組件:Eureka 三、Spring Cloud核心組件:Feign 四、Spring Cloud核心組件:R...
摘要:不過大多數講解還停留在對功能使用的層面,其底層的很多原理,很多人可能并不知曉。每個線程池里的線程就僅僅用于請求那個服務。 歡迎關注微信公眾號:石杉的架構筆記(id:shishan100) 每日更新!精品技術文章準時送上! 目錄 一、業務場景介紹 二、Spring Cloud核心組件:Eureka 三、Spring Cloud核心組件:Feign 四、Spring Cloud核心組件:R...
閱讀 1951·2021-09-07 09:59
閱讀 2520·2019-08-29 16:33
閱讀 3688·2019-08-29 16:18
閱讀 2849·2019-08-29 15:30
閱讀 1678·2019-08-29 13:52
閱讀 2035·2019-08-26 18:36
閱讀 530·2019-08-26 12:19
閱讀 694·2019-08-23 15:23