Think In Java 13章 字符串 & 16章 數(shù)組

本文發(fā)表于KuTear's Blog,轉(zhuǎn)載請注明

最簡單的例子說起

數(shù)組

粗糙數(shù)組

數(shù)組中構(gòu)成矩陣的每個向量都可以具有任意的長度

 int[][] array = new int[][]{
        new int[]{1, 2, 3},
        new int[]{1, 2}
 };
 System.out.println(Arrays.deepToString(array));//輸出 [[1, 2, 3], [1, 2]]
 System.out.println(array[1][2]);// java.lang.ArrayIndexOutOfBoundsException: 2

基礎(chǔ)

  • 新生成一個數(shù)組晤斩,其中所有引用被自動初始化為null漾唉,基本類型被初始化為0(boolean是false)

Arrays

方法 說明
equals() 比較兩個數(shù)字是否相等
deepEquals() 用于多維數(shù)組比較
fill() 填充數(shù)組
sort() 數(shù)組排序
binarySearch() 在已經(jīng)排序的數(shù)組中查找元素
toString 產(chǎn)生數(shù)組的String表示
hashCode() 產(chǎn)生數(shù)組的散列碼
asList() 接受任意的序列或數(shù)組作為其參數(shù)父虑,并轉(zhuǎn)換為List容器

數(shù)組與泛型

通常娃循,數(shù)組與泛型不能很好結(jié)合丑蛤,你不能實例化具有參數(shù)化類型的數(shù)組诸迟。Peel<Banana>[] peels = new Peel<>[10]不合法壹粟,擦除會移除參數(shù)類型信息,而數(shù)組必須知道它們所持有的確切類型呻此,以強制保證類型安全轮纫。

類型擦除

Class c1 = new ArrayList<Integer>().getClass();
Class c2 = new ArrayList<String>().getClass();
System.out.println(c1 == c2); //Output: true

參數(shù)化方法

private <T> Class get(T data){
        return data.getClass();
}

參數(shù)化類

public class Container<K, V> {
    private K key;
    private V value;

    public Container(K k, V v) {
        key = k;
        value = v;
    }
}

泛型自動打包拆包

HashMap<String,Integer> map = new HashMap<>();
map.put("one",1);  //  int ---> Integer
int value = map.get("one"); // Integer ---> int

通過反編譯查看實現(xiàn)

public class Main {
  public Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/util/HashMap
       3: dup
       4: invokespecial #3                  // Method java/util/HashMap."<init>":()V
       7: astore_1
       8: aload_1
       9: ldc           #4                  // String one
      11: iconst_1
      12: invokestatic  #5                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;[打包]
      15: invokevirtual #6                  // Method java/util/HashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/
lang/Object;
      18: pop
      19: aload_1
      20: ldc           #4                  // String one
      22: invokevirtual #7                  // Method java/util/HashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;
      25: checkcast     #8                  // class java/lang/Integer
      28: invokevirtual #9                  // Method java/lang/Integer.intValue:()I [拆包]
      31: istore_2
      32: return
}

字符串

String對象不可變

任意的包含改變String的方法其實都是重新生成對象

//String.java
public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
}

"+"重載原理

String result1 = "AAA" + "BBB";
String result2 = "AAABBB";

上面的result1==result2.
通過反編譯可得

public static void main(java.lang.String[]);
  Code:
     0: ldc           #2                  // String AAABBB
     2: astore_1
     3: ldc           #2                  // String AAABBB
     5: astore_2
     6: return

java編譯器對它進(jìn)行了優(yōu)化.

public static void main(String[] args) {
       String result1 = new String("AAA");
       String result2 = result1+"BBB";
}
  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/lang/String
       3: dup
       4: ldc           #3                  // String AAA
       6: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
       9: astore_1
      10: new           #5                  // class java/lang/StringBuilder
      13: dup
      14: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
      17: aload_1
      18: invokevirtual #7                  // Method java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: ldc           #8                  // String BBB
      23: invokevirtual #7                  // Method java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
      26: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      29: astore_2
      30: return
}

由上可以看出"+"的實現(xiàn)是利用StringBuilderappend()實現(xiàn)

for(int i = 0; i < fields.length; i++) {
            result += fields[i];
}

根據(jù)上面的原理知道這里的+=會生成臨時StringBuilderN多個,會造成不必要的消耗,這時應(yīng)主動用StringBuilder

StringBuilder result = new StringBuilder();
for(int i = 0; i < fields.length; i++) {
    result.append(fields[i]);
}
return result.toString();

StringBuilder & StringBuffer

StringBuffer是線程安全的,速度慢些焚鲜;StringBuilder是線程不安全的掌唾,但是速度快些;

性能: StringBuilder > StringBuffer > String

字符格式化

  • System.out.println("%d %f", x, y);
  • System.out.printf("%d %f", x, y);
  • java.util.Formatter
  • String.format("%d %f", x, y);

正則表達(dá)式

符號 說明 符號 說明 符號 說明
^ 一行的起始 \W 非字母數(shù)字 \w 字母數(shù)字
$ 一行的末尾 \D 非數(shù)字 \d 數(shù)字
+ >=1 ? 0或1次 * 任意次
. 非換行任意字符 [^x] 非X字符的任意字符 \S 任意非空白符字符

補充

Java中的String內(nèi)存分析

棧(Stack) :存放基本類型的變量數(shù)據(jù)和對象的引用忿磅,但對象本身不存放在棧中糯彬,而是存放在堆(new 出來的對象)或者常量池中(字符串常量對象存放在常量池中)
堆(heap):存放所有new出來的對象和數(shù)組。
常量池(constant pool):在堆中分配出來的一塊存儲區(qū)域葱她,存放儲顯式的String常量和基本類型常量(float撩扒、int等)。另外吨些,可以存儲不經(jīng)常改變的東西(public static final)搓谆。常量池中的數(shù)據(jù)可以共享。
靜態(tài)存儲:存放靜態(tài)成員(static定義的)锤灿。

Java中字符串對象創(chuàng)建有兩種形式挽拔,一種為字面量形式,如String str = "droid";但校,另一種就是使用new這種標(biāo)準(zhǔn)的構(gòu)造對象的方法螃诅,如String str = new String("droid").
當(dāng)代碼中出現(xiàn)字面量形式創(chuàng)建字符串對象時,JVM首先會對這個字面量進(jìn)行檢查,如果字符串常量池中存在相同內(nèi)容的字符串對象的引用术裸,則將這個引用返回倘是,否則新的字符串對象被創(chuàng)建,然后將這個引用放入字符串常量池袭艺,并返回該引用搀崭。
當(dāng)我們使用了new來構(gòu)造字符串對象的時候,不管字符串常量池中有沒有相同內(nèi)容的對象的引用猾编,新的字符串對象都會創(chuàng)建瘤睹。

String str1 = "droid";
String str2 = "droid";
String str3 = new String("droid");
System.out.println(str1 == str2); //true
System.out.println(str1 == str3);//false

使用new創(chuàng)建對象,會在中創(chuàng)建對象(真正的內(nèi)存占用),同時會在中創(chuàng)建指向堆中該對象的首地址的一個引用(相當(dāng)于指針,同樣占一小部分內(nèi)存),當(dāng)程序運行到該變量的作用域之后,棧中的引用會被置為空,但是此時堆中的內(nèi)存并沒有被即可釋放,會根據(jù)程序所占用的內(nèi)存Java GC在合適的時候回收堆中的內(nèi)存.

對于String的比較問題,我們需要記住

String a = new String("A");
String b = new String("A");

對于new出來的對象,==操作是不相等的.

String a = "A";
String b = a + "B";

String c = "A" + "B";

通過反編譯,發(fā)現(xiàn)b這里其實利用StringBuilder,最后用StringBuilder#toString()方法生成String,是經(jīng)過new出來的,而前面說過,new出來的對象是棧中的引用指向堆中的地址,而字面量形式是棧中的引用指向常量區(qū)的地址.當(dāng)然是不相等的.
c經(jīng)編譯器優(yōu)化等同于String c = "AB".

//StringBuilder.java
@Override
public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市答倡,隨后出現(xiàn)的幾起案子轰传,更是在濱河造成了極大的恐慌,老刑警劉巖瘪撇,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件获茬,死亡現(xiàn)場離奇詭異,居然都是意外死亡倔既,警方通過查閱死者的電腦和手機恕曲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來渤涌,“玉大人佩谣,你說我怎么就攤上這事〖吣螅” “怎么了稿存?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長瞳秽。 經(jīng)常有香客問我,道長率翅,這世上最難降的妖魔是什么练俐? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮冕臭,結(jié)果婚禮上腺晾,老公的妹妹穿的比我還像新娘。我一直安慰自己辜贵,他們只是感情好悯蝉,可當(dāng)我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著托慨,像睡著了一般鼻由。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天蕉世,我揣著相機與錄音蔼紧,去河邊找鬼。 笑死狠轻,一個胖子當(dāng)著我的面吹牛奸例,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播向楼,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼查吊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了湖蜕?” 一聲冷哼從身側(cè)響起菩貌,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎重荠,沒想到半個月后箭阶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡戈鲁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年仇参,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片婆殿。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡诈乒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出婆芦,到底是詐尸還是另有隱情怕磨,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布消约,位于F島的核電站肠鲫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏或粮。R本人自食惡果不足惜导饲,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望氯材。 院中可真熱鬧渣锦,春花似錦、人聲如沸氢哮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冗尤。三九已至听盖,卻和暖如春胀溺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背媳溺。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工月幌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人悬蔽。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓扯躺,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蝎困。 傳聞我的和親對象是個殘疾皇子录语,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法禾乘,內(nèi)部類的語法澎埠,繼承相關(guān)的語法,異常的語法始藕,線程的語...
    子非魚_t_閱讀 31,632評論 18 399
  • (一)Java部分 1蒲稳、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨云閱讀 7,107評論 0 62
  • 前言 不知道大家有沒有這樣一種感覺江耀,程序員的數(shù)量井噴了∷咧玻可能是因為互聯(lián)網(wǎng)火了祥国,也可能是各家培訓(xùn)機構(gòu)為我們拉來了大量...
    活這么大就沒飽過閱讀 2,727評論 6 26
  • 語出《孟子:盡心章句上》舌稀。 孟子曰:“君子有三樂,而王天下不與存焉灼擂。父母俱存壁查,兄弟無故,一樂也缤至;仰不愧于天潮罪,俯不怍...
    神農(nóng)堂朱家閱讀 1,448評論 3 5
  • 《三妹》今天看到15集完,對之前女主何三妹堅定的愛情信念有了進(jìn)一步的理解沃暗。在前面幾集里月洛,有些氣憤,這個何三妹每天跑...
    梅園遺珠閱讀 278評論 0 1