內容:創建String 的方式,String比較方式,String類,實例對象的小區別,一些工具包
首先,查看String源碼:有幾個比較重要的點
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
}
class被final修飾,這意味着String不能被繼承,也不能使用Object instanceof String得到bool;
private final char value[];
value對應的是String實例出來的具體的值對應的char[],被final修飾,意味着該值不能被修改(但是可以重新給實例對象指向新的地址)
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;
}
String重寫equlas()equals是在不爲空的情況下比較char的長度,長度相同 再一一比較char
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
String 類下的方法substring 我們可以看到返回的值 是new String的,所以使用substring的時候並不會影響原對象本身。其他的方法也是如此。
在Java中有字符串常量池舉個栗子
下面是對字符串“hello”的幾種聲明方式,發現value都是一樣的。但是用"=="來進行比較的時候,前面三個是true.
最後一個與前面任何一個在棧內地址都不相同。
- 字符串常量池是爲了減少在JVM中創建的字符串的數量,字符串類維護了一個字符串常量池,該池是Java堆內存中一個特殊的存儲區域。
String str2 = "hell"+"o";
String str3 = "hello";
上面這兩種在JVM字符串常量池中爲什麼不是創建了三個"hell",“o”,"hello"呢,因爲JVM對字符串這個特殊的數據進行了特殊的處理。上面兩種聲明在字符串常量池中申請的是同一個。
- new String(“hello”);在字符串常量池中與上面幾種申請的其實是同一處地址,但是爲什麼與前面幾種方式的任意一種使用==的時候返回false。雖然在常量池中是同一個值,但是對應對象的"棧"卻是不同的,new關鍵字創建的對象是開闢內存新的地址。
StringBuffer
是我們常用的字符串處理的一個類。
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{}
該類也是被final修飾的,意味着不能被繼承。
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
在他的append字符串拼接值的方法是被synchronized 意味着該類在多線程中是線程安全的。
StringBuilder
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{}
StringBuilder同樣被final修飾,該類也是不能被繼承的最終。
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
沒有被鎖鎖着,所以多線程下“寫”不安全。
String對象被傳值
private static void changesValue(String str){
str = "hello zhangsan";
}
public static void main(String[] args) {
String lisi = "lisi";
changesValue(lisi);
System.out.println(lisi);
lisi = "hello wangwu";
System.out.println(lisi);
}
結果:
lisi
hello wangwu
觀察上面的結果可以發現,String爲不可變類型,在方法內對String修改的時候,相當於傳入的是String的副本,並不是對象本身,所以修改之後也只是修改備份,並不會修改對象本身的值。
但是使用StringBuffer或者StringBuilder的時候是可以進行修改的,因爲StringBuffer下對應的具體的值並沒有被final修飾,在本文的開頭就看到String類下的value是被fianl修飾的。
private transient char[] toStringCache;//StringBuffer
private final char value[];//String
Utils
我常使用的String工具類:
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
裏面有判空,去空格等處理。