1. 程式人生 > 其它 >php使用漢字作為進位制轉換

php使用漢字作為進位制轉換

1,String的基本特性

  2,String的記憶體分配

   3,String基本操作

    4,字串拼接操作

      5,intern()的使用

       6,StringTable的垃圾回收

        7,G1中String去重操作

 


 

String的基本特性

String:字串,使用一對 “” 引起來表示

  •       String s1 = “ylcandzy”;//字面量的定義方式

  •       String s2 = new String("hello");

String宣告為final的,不可被繼承

 

String實現了Serializable介面;表示字串是支援序列化的,實現Comparable介面:表示String可以比較大小

 

String在jdk8及以前內部定義了final char[] value用於儲存字串資料。jdk9時改為byte[]

 

  • String儲存結構變更

        結論:String再也不用 char[] 來儲存,改為 byte[] 加上編碼標記,節約了一些空間

   public final class String
    implements java.io.Serializable,Comparable<String>,CharSequence{
        @Stable
        private final byte[] value;
    }

 

        那StringBuffer 和 StringBuilder 是否仍然無動於衷?

  String-related classes such as AbstractStringBuilder,StringBuilder,
  and StringBuffer will be updated to use the same representation,as will the
  HotSpot VM’s intrinsic(固有的,內建的)string operations        

 

  • String:代表不可變的字元序列。簡稱:不可變性
  1.           當對字串重新賦值時,需要重寫指定記憶體區域賦值,不能使用原有的value進行賦值。
  2.           當對現在的字串進行連線操作時,也需要重新指定記憶體區域賦值,不能使用功能原有的value進行賦值。
  3.           當呼叫String的 replace() 方法修改指定字串或字串時,也需要重新指定記憶體區域賦值,不能使用原有的value進行賦值。
  •  通過字面量的方式(區別於new)給一個字串賦值,此時的字串值宣告在字串常量池中。
package com.ylc.java05;

import org.junit.Test;

/**
 *
 *
 * String基本使用:驗證String的不可變性
 * 並不會在原有的地址上進行修改,只會建立一個新的地址
 *
 * @Author ylc
 * @Date 2022/3/25 16:02
 * @Version 1.0
 */
public class StringTest01 {

    @Test
    public void test01(){
        String s1 = "abc";//字面量定義的方式,"abc"儲存在字串常量池中
        String s2 = "abc";
        s2 = "hello";

        System.out.println(s1 == s2); //判斷地址
        System.out.println(s1);
    }

    @Test
    public void test02(){
        String s1 = "abc";
        String s2 = "abc";
        s2 += "ylc";

        System.out.println(s1 == s2);
        System.out.println(s2);
    }

    @Test
    public void test03(){
        String s1 = "abc";
        String s2 = s1.replace("a","y");

        System.out.println(s1 == s2);
    }
}

字串常量池中是不會儲存相同內容的字串的。

  • String的String Pool是一個固定大小的Hashtable,預設值大小長度是1009。如果放進String Pool的String非常多,就會造成Hash衝突嚴重,從而導致連結串列會很長,而連結串列長了後直接會造成的影響就是當呼叫String.intern時效能會大幅下降。
  • 使用-XX:StringTableSize可以設定StringTable的長度
  • 在jdk6中StringTable是固定的,就是1009的長度,所以如果常量池中的字串過多就會導致效率下降很快。StringTableSize設定沒有要求。
  • 在jdk7中StringTable的長度預設值60013,1009是可以設定的最小值。
  • jdk8開始,1009是可設定的最小值。

 

String記憶體分配

  • 常量池就是類似一個Java系統級別提供的快取。8種基本資料型別的常量池都是系統協調的,String型別的常量池比較特殊。它是主要使用方法有兩種
  1. 直接使用雙引號宣告出來的String物件會直接儲存在常量池中。(比如:String info = “ylcandzy”);
  2. 如果不是用雙引號宣告的String物件,可以使用String提供的intern()方法。
  • Java 6及以前,字串常量池存放在永久代。
  • Java 7中字串常量池的位置調整到Java堆中。
  • Java 8元空間,字串常量在堆。
  • StringTable為什麼要調整?
  1. permSize預設比較小
  2. 永久代垃圾回收頻率低
package com.ylc.java05;

import java.util.HashSet;
import java.util.Set;

/**
 *
 * jdk6:
 * -XX:MetaspaceSize=6m -XX:MaxMetaspaceSize=6m -Xms6m -Xmx6m
 *
 * jdk8:
 * -XX:MetaspaceSize=6m -XX:MaxMetaspaceSize=6m -Xms6m -Xmx6m
 * @Author ylc
 * @Date 2022/3/25 17:47
 * @Version 1.0
 */
public class StringTest02 {
    public static void main(String[] args) {
        //使用Set保持著常量池引用,避免full gc 回收常量池行為
        Set<String> set = new HashSet<String>();

        //在short可以取值的範圍內足以讓6MB的PermSize或heap產生OOM
        short i = 0;
        while (true){
            set.add(String.valueOf(i++).intern());

        }
    }
}

String的基本操作

 

 

package com.ylc.java05;

/**
 * @Author ylc
 * @Date 2022/3/25 18:23
 * @Version 1.0
 */
public class StringTest03 {
    public static void main(String[] args) {
        int i = 1;
        Object obj = new Object();
        StringTest03 mem = new StringTest03();
        mem.foo(obj);
    }

    private void foo(Object param){
        String str = param.toString();
        System.out.println(str);
    }
}

字串拼接操作

  1. 常量與常量的拼接結果在常量池,原理是編譯期優化
  2. 常量池中不會存在相同內容的常量。
  3. 只要其中有一個變數,結果就是在堆中。變數拼接的原理是StringBuilder
  4. 如果拼接的結果呼叫intern()方法,則主動將常量池中還沒有的字串物件放入池中,並返回此物件地址。
    @Test
    public void test02(){
        String s1 = "ylc";
        String s2 = "zy";

        String s3 = "ylcandzy";
        String s4 = "ylcand" + "zy";//編譯期間優化
        //如果拼接符號的前後出現了變數,則相當於堆空間new String(),具體的內容為拼接的結果:ylcandzy
        String s5 = s1 + "zy";
        String s6 = "ylc" +s2;
        String s7 = s1 + s2;

        System.out.println(s3 == s4);
        System.out.println(s3 == s5);
        System.out.println(s3 == s6);
        System.out.println(s3 == s7);
        System.out.println(s5 == s6);
        System.out.println(s5 == s7);
        System.out.println(s6 == s7);
        //intern():判斷字串常量池中是否存在ylcandzy值,如果存在,則返回常量池中ylcandzy的地址;
        //如果字串常量池不存在ylcandzy,則在常量池中載入一份ylcandzy,並返回物件的地址
        String s8 = s6.intern();
        System.out.println(s3 == s8);
    }
}