1. 程式人生 > 程式設計 >JDK9的新特性之String壓縮和字元編碼的實現方法

JDK9的新特性之String壓縮和字元編碼的實現方法

簡介

String的底層儲存是什麼?相信大部分人都會說是陣列。如果要是再問一句,那麼是以什麼陣列來儲存呢?相信不同的人有不同的答案。

在JDK9之前,String的底層儲存結構是char[],一個char需要佔用兩個位元組的儲存單位。

據說是JDK的開發人員經過調研了成千上萬的應用程式的heap dump資訊,然後得出了一個結論:大部分的String都是以Latin-1字元編碼來表示的,只需要一個位元組儲存就夠了,兩個位元組完全是浪費。

據說他們用了大資料+人工智慧,得出的結論由不得我們不信。

於是在JDK9之後,字串的底層儲存變成了byte[]。

底層實現

先看下java9之前的String是怎麼實現的:

public final class String
 implements java.io.Serializable,Comparable<String>,CharSequence {
 
 //The value is used for character storage.
 private final char value[];
}

再看下java9中String的實現和一些關鍵的變數:

public final class String
 implements java.io.Serializable,CharSequence {
 
 /** The value is used for character storage. */
 @Stable
 private final byte[] value;

 private final byte coder;

 @Native static final byte LATIN1 = 0;
 @Native static final byte UTF16 = 1;

 static final boolean COMPACT_STRINGS;

 static {
  COMPACT_STRINGS = true;
 }

從程式碼我們可以看到底層的儲存已經變成了byte[]。

再看一下coder變數,coder代表編碼的格式,目前String支援兩種編碼格式LATIN1和UTF16。

LATIN1需要用一個位元組來儲存。而UTF16需要使用2個位元組或者4個位元組來儲存。

而COMPACT_STRINGS則是用來控制是否開啟String的compact功能。預設情況下COMPACT_STRINGS功能是開啟的。

如果我們想關閉COMPACT_STRINGS功能則可以使用-XX:-CompactStrings引數。

ps:下面看下jdk8日期格式化的例項程式碼

package time;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
/***
 * 總結: java.util.Date和 SimpleDateFormat 都是非執行緒安全的
 * 1. LocalDate
 * 2. LocalTime
 * 3. LocalDateTime
 * 4. DateTimeFormatter
 * 5. ChronoUnit
 */
public class Java8Date {
  public static void main(String[] args) {
    /** #0. Calendar
     * 區別於calendar的month: canlendar中:[]
     * 1. LocalDate的年月日直接是日期中的值;
     * 2. date.getMonthValue() 和 c.get(Calendar.MONTH) 有區別: c:0表示1月
     */
    Calendar c = Calendar.getInstance(); // 測試日期:2019-04-02
    System.out.println(c.get(Calendar.YEAR)); // 2019
    System.out.println(c.get(Calendar.MONTH)); // 3(0=1月)
    System.out.println(c.get(Calendar.DAY_OF_MONTH)); //2
    // #1. LocalDate 2019-04-02 : 今日日期: LocalDate.now()
    System.out.println("=-==-==-==-==-==-==-==-==-==-==");
    LocalDate date = LocalDate.now();
    System.out.println(date); // 2019-04-02
    // #2. year month day: 年月日獲取
    System.out.println("=-==-==-==-==-==-==-==-==-==-==");
    int year = date.getYear(); // 2019
    int month = date.getMonthValue();// 4
    int day = date.getDayOfMonth(); // 2
    System.out.println(year + "-" + month + "-" + day); // 2019-4-2
    // #3. 構造日期: 給定年月日
    System.out.println("=-==-==-==-==-==-==-==-==-==-==");
    LocalDate dt1 = LocalDate.of(2019,3,8);
    LocalDate dt2 = LocalDate.of(2019,8);
    // #4. 日期比較: equals
    // true: 內部是比較的 year-year month-month day-day
    System.out.println(dt2.equals(dt1)); 
    // #5. 週期性日期,比如: 判斷使用者的生日
    System.out.println("=-==-==-==-==-==-==-==-==-==-==");
    // 生日:0308
    MonthDay uBirth = MonthDay.of(3,8);
    MonthDay dtMD = MonthDay.from(dt1);
    // dt1 是不是 使用者u的生日:true
    System.out.println("dt1==使用者u的生日:" + dtMD.equals(uBirth));
    // #6. 獲取當前時間 [HH:mm:ss.SSS]
    System.out.println("=-==-==-==-==-==-==-==-==-==-==");
    LocalTime time = LocalTime.now();
    System.out.println(time);
    // #7. 增減時間 plus/minus
    System.out.println("=-==-==-==-==-==-==-==-==-==-==");
    // dt1=2019-03-08
    LocalDate dt1Plus2d = dt1.plusDays(2); 
    LocalDate dt1Plus2y = dt1.plusYears(2); 
    LocalDate dt1Plus2m = dt1.plusMonths(2);
    System.out.println(dt1Plus2d); // 2019-03-10
    System.out.println(dt1Plus2y); // 2021-03-08
    System.out.println(dt1Plus2m); // 2019-05-08
    // dt1=2019-03-08
    LocalDate plus1w = dt1.plus(1,ChronoUnit.WEEKS);
    LocalDate plus1d = dt1.plus(1,ChronoUnit.DAYS);
    LocalDate plus18y = dt1.plus(18,ChronoUnit.YEARS);
    LocalDate minus1y = dt1.minus(1,ChronoUnit.YEARS);
    System.out.println(plus1w); // 2019-03-15
    System.out.println(plus1d); // 2019-03-09
    System.out.println(plus18y); // 2037-03-08
    System.out.println(minus1y); // 2018-03-08
    // #8. 日期dt1 早於/晚於 minus1y
    System.out.println("=-==-==-==-==-==-==-==-==-==-==");
    // dt1=2019-03-08 minus1y=2018-03-08
    System.out.println(dt1.isAfter(minus1y)); // true
    System.out.println(dt1.isBefore(minus1y)); // false
    // #9. 計算日期差
    System.out.println("=-==-==-==-==-==-==-==-==-==-==");
    // dt1=2019-03-08 dt20190402
    LocalDate dt20190402 = LocalDate.of(2019,4,2);
    Period btPeriod = Period.between(dt1,dt20190402);
    Period btPeriod2 = Period.between(dt1,dt20190402);
    System.out.println(btPeriod); // P25D
    System.out.println(btPeriod.getMonths()); // 0
    System.out.println(btPeriod.getDays()); // 25
    // 25 可見是標量,不是向量,只計算差數
    System.out.println(btPeriod2.getDays()); 
    // #10. 時間戳Instant->java.util.Date[getTime()==toEpochMilli()]
    System.out.println("=-==-==-==-==-==-==-==-==-==-==");
    Instant now = Instant.now(); // 2019-04-02T08:48:46.755Z
    Date dtNow = Date.from(now); // Tue Apr 02 16:48:46 CST 2019
    long millisInstant = now.toEpochMilli();
    long millisDate = dtNow.getTime();
    System.out.println(millisInstant); // 1554195038598
    System.out.println(millisDate); // 1554195038598
    // #11# ** 日期格式化
    System.out.println("=-==-==-==-==-==-==-==-==-==-==");
    DateTimeFormatter pattern1 = DateTimeFormatter.ofPattern("yyyyMMdd-HH:mm:ss,SSS");
    DateTimeFormatter pattern2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    /**
     * 命題:--> 將 "20190215-22:10:30,333" 日期
     * 格式化為 "yyyyMMdd-HH mm:ss.SSS" 字串
     * @.1. 字串轉物件LocalDateTime
     * @.2. LocalDateTime物件轉字串
     */
    String strDt = "20190215-22:10:30,333"; // @.1.
    LocalDateTime dateTime = LocalDateTime.parse(strDt,pattern1); 
    String fmtDtString = dateTime.format(pattern2); // @.2.
    System.out.println(dateTime); // 2019-02-15T22:10:30.333
    System.out.println(fmtDtString); // 2019-02-15 22:10:30
    System.out.println("=-==-==-==-==-==-==-==-==-==-==");
  }
}

總結

本文講解了新的String實現和COMPACT_STRINGS模式的關閉方法。

到此這篇關於JDK9的新特性之String壓縮和字元編碼的實現方法的文章就介紹到這了,更多相關JDK9 新特性內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!