您好,登錄后才能下訂單哦!
字符串是一個特殊的數(shù)據(jù)類型,屬于引用類型。String類在Java中使用關(guān)鍵字final修飾,所以這個類是不可以繼承擴(kuò)展和修改它的方法。String類用處極廣泛,在對String對象進(jìn)行初始化時,和基本類型的包裝器類型一樣,可以不使用new關(guān)鍵字構(gòu)造對象。(是真的妖嬈...)
特點(diǎn):final關(guān)鍵字修飾,實現(xiàn)Serializable序列化接口,Comparable比較接口,和CharSequence字符序列接口。
final class String
implements java.io.Serializable,
Comparable<String>, CharSequence
兩種方式,常量和創(chuàng)建對象。
String var1 = "cicada" ;
String var2 = new String("smile") ;
var1:聲明的是一個常量,顯然是放在常量池中。
var2:創(chuàng)建字符串對象,對象存放在堆內(nèi)存中。
常量池用來存放常量;堆內(nèi)存用來存放new出來的引用對象。
public class String02 {
public static void main(String[] args) {
String var1 = "cicada" ;
String var2 = "cicada" ;
// true;true
System.out.println((var1==var2)+";"+var1.equals(var2));
String var3 = new String("cicada");
String var4 = new String("cicada");
// false;true
System.out.println((var3==var4)+";"+var3.equals(var4));
// false;true
System.out.println((var1==var4)+";"+var2.equals(var4));
String var5 = "ci"+"cada";
// true;true
System.out.println((var1==var5)+";"+var5.equals(var4));
String var6 = new String02().getVar6 () ;
// true;true
System.out.println((var1==var6)+";"+var6.equals(var4));
}
public String getVar6 (){
return "cicada" ;
}
}
==
:對于基本類型,比較的是值,對于引用類型,比較的是地址的值;
equals
:該方法源自O(shè)bject中一個最基礎(chǔ)的通用方法,在Object的方法中使用==
判斷地址的值,只是到了String類中進(jìn)行了重寫,用于字符內(nèi)容的比較,該方法在繼承關(guān)系中的變化,追蹤JDK源碼,變化非常清楚。
字符串在String內(nèi)部是通過一個char[]數(shù)組表示,Unicode統(tǒng)一的編碼表示的字符,char類型的字符編碼由此來。
這里看下構(gòu)造方法就會明白上面的概念邏輯。
private final char value[];
public String() {this.value = "".value;}
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
不同的國家和地區(qū),使用的編碼可能是不一樣的,互聯(lián)網(wǎng)中有UTF8編碼又是最常用,一次在程序開發(fā)中,經(jīng)常需要編碼之間轉(zhuǎn)換。
public class String03 {
public static void main(String[] args) throws Exception {
String value = "Hello,知了";
// UTF-8
byte[] defaultCharset = value.getBytes(Charset.defaultCharset());
System.out.println(Arrays.toString(defaultCharset));
System.out.println(new String(defaultCharset,"UTF-8"));
// GBK
byte[] gbkCharset = value.getBytes("GBK");
System.out.println(Arrays.toString(gbkCharset));
System.out.println(new String(gbkCharset,"GBK"));
// ISO-8859-1:表示的字符范圍很窄,無法表示中文字符,轉(zhuǎn)換之后無法解碼
byte[] isoCharset = value.getBytes("ISO8859-1");
System.out.println(Arrays.toString(isoCharset));
System.out.println(new String(isoCharset,"ISO8859-1"));
// UTF-16
byte[] utf16Charset = value.getBytes("UTF-16");
System.out.println(Arrays.toString(utf16Charset));
System.out.println(new String(utf16Charset,"UTF-16"));
}
}
兩個基礎(chǔ)概念:
編碼Encode
:信息按照規(guī)則從一種形轉(zhuǎn)換為另一種形式的過程,簡稱編碼;
解碼Decode
:解碼就是編碼的逆向過程。
在日常開發(fā)中,字符串的格式不會都滿足業(yè)務(wù)要求,通常就需要進(jìn)行指定格式化操作。
public class String04 {
public static void main(String[] args) {
// 指定位置拼接字符串
String var1 = formatStr("cicada","smile");
System.out.println("var1="+var1);
// 格式化日期:2020-03-07
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = new Date() ;
System.out.println(format.format(date));
// 浮點(diǎn)數(shù):此處會四舍五入
double num = 3.14159;
System.out.print(String.format("浮點(diǎn)類型:%.3f %n", num));
}
public static String formatStr (String ...var){
return String.format("key:%s:route:%s",var);
}
}
上面案例演示應(yīng)用場景:Redis緩存Key生成,日期類型轉(zhuǎn)換,超長浮點(diǎn)數(shù)的截取。
String對象形參傳遞到方法里的時候,實際上傳遞的是引用的拷貝。
public class String05 {
String var1 = "hello" ;
int[] intArr = {1,2,3};
public static void main(String[] args) {
String05 objStr = new String05() ;
objStr.change(objStr.var1,objStr.intArr);
// hello 4
System.out.println(objStr.var1);
System.out.println(objStr.intArr[2]);
}
public void change (String var1,int[] intArr){
var1 = "world" ;
intArr[2] = 4 ;
}
}
案例中改變的是var1引用的拷貝,方法結(jié)束執(zhí)行結(jié)束,形參var1被銷毀, 原對象的引用保持不變。數(shù)組作為參數(shù)傳遞時傳遞是數(shù)組在內(nèi)存中的地址值,這樣直接找到數(shù)組在內(nèi)存中的位置。
字符串的處理在系統(tǒng)開發(fā)中十分的常見,通常會提供一個工具類統(tǒng)一處理,可以基于一個框架中的工具類二次封裝,也可以全部自行封裝。
class StringUtil {
private StringUtil(){}
public static String getUUid (){
return UUID.randomUUID().toString().replace("-","");
}
}
上面是字符串工具類最基礎(chǔ)的一個。不同框架中自帶的工具類也不錯。
org.apache.commons.lang3.StringUtils
org.springframework.util.StringUtils
com.alibaba.druid.util.StringUtils
這里推薦第一個,也可以把自定義的工具類繼承該工具類,提供更豐富的公共方法。
絮叨一句
:代碼整潔之道的基礎(chǔ),就是有一顆《偷懶》的心,花點(diǎn)心思該封裝的封裝,該刪除的刪除。
字符串修改拼接常用的API,內(nèi)部的實現(xiàn)過程和String類似。
public class String07 {
public static void main(String[] args) {
StringBuffer var = new StringBuffer(2) ;
var.append("what");
var.append("when");
System.out.println(var);
}
}
看到上面幾行代碼的反應(yīng),基本能反應(yīng)編程的年齡:
一年
:API是這樣用的,沒毛?。?/p>
三年
:StringBuffer是線程安全的,效率相對偏低;
五年
:默認(rèn)字符數(shù)組大小是16,這里自定義字符數(shù)組的大小,如果長度不夠需要擴(kuò)容,所以要預(yù)估一下字符串的可能大小,減小消耗;
絮叨一句
:Java中許多容器對象的大小默認(rèn)是16,且具備動態(tài)擴(kuò)容機(jī)制,這就是傳說中的編程思想,在開發(fā)中照葫蘆畫瓢的寫兩段,這就是格調(diào)。
這個類出現(xiàn)比StringBuffer要晚很多,從JDK1.5才開始出現(xiàn)。
public class String08 {
public static void main(String[] args) {
StringBuilder var = new StringBuilder() ;
var.append("how").append("what") ;
System.out.println(var);
}
}
用法和StringBuffer差不多,不過是非線程安全操作,效率自然要高。
補(bǔ)刀一句
:對于線程安全和操作和非安全操作,還有初始容量和擴(kuò)容這種邏輯,都可以在源碼中查看,這是進(jìn)階程序員的必備意識。
這里原理解釋同上,根本邏輯是一致的。
public class String09 {
public static void main(String[] args) {
String var1 = new String("A");
String var2 = new String("B");
StringBuffer var3 = new StringBuffer("C");
StringBuffer var4 = new StringBuffer("D");
join(var1,var2);
join(var3,var4);
//A<>B
System.out.println(var1+"<>"+var2);
//C<>DD
System.out.println(var3+"<>"+var4);
}
public static void join (String s1,String s2){
s1 = s2 ;
s2 = s1+s2 ;
}
public static void join (StringBuffer s1,StringBuffer s2){
s1 = s2 ;
s2 = s2.append(s1) ;
}
}
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。