你所认识的String
概述
String作為非基本數(shù)據(jù)類型,Java開發(fā)中使用頻率最高的一種數(shù)據(jù)類型之一,對(duì)于字符號(hào)的操作也很頻繁,在使用的同時(shí)我們是否注意到了一下問題?
問題
- String a = new String("xxx")創(chuàng)建了多少個(gè)對(duì)象?
- String a = "xxx"創(chuàng)建了多少個(gè)對(duì)象?
- 為什么要用StringBuilder來代替"+"?
- 為什么String作為方法參數(shù),在方法內(nèi)部修改,不會(huì)影響原來的值?
- 字符串相等的問題?
- 如何正確的操作字符串?
如上問題我們是否都清晰明了,接下來結(jié)合示例來了解以上問題,同時(shí)讓我們更加清晰的認(rèn)識(shí)String
問題一
String a = new String("xxx") 復(fù)制代碼該語句創(chuàng)建了2個(gè)對(duì)象,首先new會(huì)在堆中創(chuàng)建了一個(gè)對(duì)象用來存放"xxx",然后變量a指向剛才創(chuàng)建的對(duì)象,緊接著會(huì)在常量池中查看是否存在該字符串,如果沒有,創(chuàng)建"xxx"字符串
問題二
String a = "xxx" 復(fù)制代碼該語句創(chuàng)建了一個(gè)對(duì)象,會(huì)在常量池中查看是否存在"xxx"這個(gè)字符串,如果存在,則直接指向,如果不存在,則需要?jiǎng)?chuàng)建"xxx"字符串,然后指向
問題三
源代碼
public class StringAppendTest {public static void main(String[] args) {String str = "abc";for (int i = 0; i < 10000; i++) {str += "def";}} } 復(fù)制代碼反編譯之后代碼
package com.primary.example.string;public class StringAppendTest {public StringAppendTest(){}public static void main(String args[]){String str = "abc";for(int i = 0; i < 10000; i++)str = (new StringBuilder()).append(str).append("def").toString();} } 復(fù)制代碼在線反編譯地址:在線反編譯,記得Decompiler類型選擇JAD
如上代碼展示可以看出來,"+"最終會(huì)被反編譯成創(chuàng)建StringBuilder對(duì)象,然后調(diào)用append()方法,最終調(diào)用toString
如果是一條語句使用"+"拼接完全沒有問題,如果在循環(huán)中使用的話就會(huì)不斷的創(chuàng)建對(duì)象,影響性能。
問題四
示例代碼1
public void test2() {Student student = new Student();student.setId(10001);student.setName("jack");System.out.println("before change,student:" + student);changeStudent(student);System.out.println("after change,student:" + student); }private void changeStudent(Student student) {student.setName("lucky"); } 復(fù)制代碼打印結(jié)果1
before change,student:Student(id=10001, name=jack) after change,student:Student(id=10001, name=lucky) 復(fù)制代碼示例代碼2
public void test4() {String str = "jack";System.out.println("before change,str:" + str);changeStr(str);System.out.println("after change,str:" + str); }/*** 通過查看String的源碼,可以看到里面定義的char[]是final,也就是不可變的* 每次對(duì)字符串的操作都相當(dāng)于new String()操作* @param str*/ private void changeStr(String str) {str = "smile"; } 復(fù)制代碼打印結(jié)果1
before change,str:jack after change,str:jack 復(fù)制代碼如上展示,示例1傳對(duì)象在方法內(nèi)部的修改會(huì)影響外部,示例2傳對(duì)象在方法內(nèi)部修改卻沒有影響外部,同樣是對(duì)象,示例1和示例2卻得到不一樣的效果?
示例1由于傳遞的是地址值,調(diào)用changeStudent()的時(shí)候,形參根據(jù)地址值找到student對(duì)象,然后對(duì)其修改,由于形參和實(shí)參指向的是同一個(gè)對(duì)象,所以方法內(nèi)部的修改會(huì)影響到外部
實(shí)例2傳遞的也是地址值,但是由于String類型是不可變的,每一次賦值都相當(dāng)于重新創(chuàng)建一個(gè)對(duì)象,所以內(nèi)部的修改不影響外部
String內(nèi)部字符數(shù)組的定義
private final char value[]; 復(fù)制代碼問題五
示例1
public void test1() {String str1 = "123";String str2 = "123";System.out.println(str1 == str2); } 復(fù)制代碼結(jié)果1
true 復(fù)制代碼示例2
public void test2() {String str1 = "123";String str2 = "12" + "3";System.out.println(str1 == str2); } 復(fù)制代碼結(jié)果2
true 復(fù)制代碼示例3
public void test3() {String str1 = "123";String temp = "3";String str2 = "12" + temp;System.out.println(str1 + "=====" + str2);System.out.println(str1 == str2); } 復(fù)制代碼結(jié)果3
false 復(fù)制代碼示例4
public void test4() {String str1 = "123";final String temp = "3";String str2 = "12" + temp;System.out.println(str1 == str2); } 復(fù)制代碼結(jié)果4
true 復(fù)制代碼示例5
public void test5() {String str1 = "123";final String temp = getTemp();String str2 = "12" + temp;System.out.println(str1 == str2); }public String getTemp() {return "3"; } 復(fù)制代碼結(jié)果5
false 復(fù)制代碼結(jié)果是不是很驚訝?為什么值一樣卻不相等?首先"=="比較的是地址,equals()方法比較的是內(nèi)容,但是由于每個(gè)類的equals()方法不一樣,所以需要看具體的實(shí)現(xiàn)
public boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String anotherString = (String)anObject;int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false; } 復(fù)制代碼可以看到String的equals()方法首先比較地址是否一樣,如果不一樣再比較內(nèi)容是否一樣
然后再回到上面"=="比較的問題,我們首先要明白一個(gè)觀點(diǎn)就是,Java中的常量是在編譯期間已經(jīng)確定好的,無法確定的就會(huì)在堆中
示例1在編譯期間可以確定
示例2在編譯期間也可以確定
示例3在編譯期間無法確定,由于存在變量,變量只有在運(yùn)行的時(shí)候才能確定
示例4在編譯期間可以確定,雖然有變量,但是聲明為常量,常量一旦定義就無法修改,所以編譯時(shí)是可以確定的
示例5在編譯期間無法確定,由于調(diào)用了方法,在運(yùn)行的時(shí)候才能知道方法的返回值
問題六
來看看我們對(duì)字符串的操作
str.length(); str.substring() str.indexOf() if (null != str && str != "") {} 復(fù)制代碼替代方案
StringUtils.length("xxx"); StringUtils.substring("xxx", 0, 5); StringUtils.indexOf("xxx", 1); if (StringUtils.isBlank("xxx")) {} 復(fù)制代碼我們完全可以使用Apache的工具類來操作,首先是方便,其次是可以避免NullPointerException異常,進(jìn)入工具類的方法實(shí)現(xiàn),可以看到,首先會(huì)對(duì)我們傳入的字符串進(jìn)行null判斷,從而避免異常
以上都是個(gè)人理解,如有錯(cuò)誤,歡迎指定,讓我提早走向光明
轉(zhuǎn)載于:https://juejin.im/post/5c94addcf265da60df410a20
總結(jié)
以上是生活随笔為你收集整理的你所认识的String的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: glide 下载golang.org包问
- 下一篇: uva 815之理解诡异的海平线题目之不