Java 常用類總結(SE基礎)

GaoYuan206發表於2021-04-27

本篇部落格對java常用類相關知識進行了歸納總結,比較詳細,適用於學習和複習。

1. 字串相關的類

1.1 String

String是一個final類,代表不可變的字元序列。不可被繼承。

String物件的字元內容是儲存在一個位元組陣列byte[]中。JDK1.8中儲存的是char[]注意區別。

  • String實現了Serializable介面,支援序列化
  • 實現了Comparable介面,表示可以比較大小
  • 通過字面量的方式(區別於new)給一個String賦值,此時的字串值在字串常量池中(和方法區在同一個地方)
  • String進行連線操作、重新賦值、replace()等操作時,會重新指定記憶體區域賦值,不使用原有的value進行賦值
String str = "hello";  //字面量賦值
String s1 = new String();//本質上為,this.value = new byte[0]
String s2 = new String(String str); //放一個String型別的引數
String s3 = new String(byte[] a);
String s3 = new String(byte[] a,int off,int length);//構造方法,放char[]也是可以的

考慮如下程式碼:

String s1 = "javaEE";
String s2 = "javaEE";
String s3 = new String("javaEE");
String s4 = new String("javaEE");

這裡,s1==s2trues1==s3, s1==s4, s3==s4均為false

原因如下:

Java 常用類總結(SE基礎)

實際上,通過構造方法來構造String會指向value,而value再去指向字串常量。

String s3 = new String("javaEE");在記憶體中建立了兩個物件:一個是堆中的value結構,一個是常量池中的字串資料。

  • intern() 返回字串物件的規範表示。 這裡會返回一個字串常量。記憶體空間在常量池中。

另外,有一個關於形參實參方面的需要注意:

public class StringTest {
    String str = new String("hello");
    char[]ch = {'t','e','s','t'};

    public void change(String str,char ch[]){
        str = "hello,world";
        ch[0]='b';
    }

    public static void main(String[] args) {
        StringTest st = new StringTest();
        st.change(st.str, st.ch);
        System.out.println(st.str);
        System.out.println(st.ch);
    }
}

這裡的結果為:"hello" /n "best"

類似於C語言中,根據指標進行交換兩個指標中的內容,值傳遞過程中,實際引數的值傳入形參,形成副本,方法結束後形參消失,實際引數值並沒有改變。

另外還有一點需要注意:

String str = null; //這個指標指向null,並沒有例項化
System.out.println(str);//輸出”null“
System.out.println(str.length());//異常

1.2 String的常用方法

String的常用方法總結如下(未總結的請自己查閱):

同時還需要注意的一些方法如下,重要程度依次降低,但仍需掌握:

注意:上表下部的4個int方法如果未找到,返回的均為-1

再舉例一些方法(一些可能不太常用的):

String regex一般都用正規表示式表示

String轉換為基本資料型別或包裝類

呼叫包裝類的靜態方法:對應的型別,如要轉int,呼叫Integer.parseInt(str)

基本資料型別、包裝類轉為String

呼叫String過載的valueOf(xxx)

Java 常用類總結(SE基礎)

另外

int num = 100;
String str = num+"";  //存在變數才會返回堆中,如果常量相加則會返回常量池

這樣也可以轉換為String,但是需要注意,該型別是在堆中生成了value陣列,和new String的方式類似。

String與char[], byte[]的相互轉換

String-->char[]:呼叫String.toCharArray即返回了一個char[]

char[]或byte[] --> String:直接呼叫構造器

String-->byte[]:呼叫String.getBytes即返回了一個byte[],使用預設的字符集(例如"gbk、utf-8"等)進行轉換。

getBytes(Charset charset) 使用給定的charset將該String編碼為位元組序列,將結果儲存到新的位元組陣列中。不同的編碼方式返回的可能不同。

1.3 StringBuffer與StringBuilder

StringStringBuffer, StringBuilder之間的異同?

String:不可變的字元序列,注意理解不可變性

StringBuffer:可變的字元序列,執行緒安全,效率較低(都是同步方法)

StringBuilder:jdk5.0新增,可變的字元序列,執行緒不安全,效率高

final byte[] value  //String中的
byte[] value  //StringBuffer和StringBuilder中的

StringBuffer

String str = new String();// new char[0]
String str1 = new String("abc");//new char[] {'a','b','c'};

StringBuffer sb = new StringBuffer();//new char[16] 初始容量為16
sb.append('a');// value[0]='a';依次進行

StringBuffer sb1 = new StringBuffer("abc");//new char["abc".length()+16]
System.out.println(sb.length()); //return的是count,每append操作count+=len,這裡為1,並不是value.length

接下來看StringBuffer的擴容機制

簡述:一般情況下,若容量不夠的時候,擴充為原來容量的2倍+2,同時將原有陣列的元素複製到新陣列中

JDK15中,原始碼已經改變,為:

private int newCapacity(int minCapacity) {
    int oldLength = value.length;
    int newLength = minCapacity << coder;
    int growth = newLength - oldLength;
    int length = ArraysSupport.newLength(oldLength, growth, oldLength + (2 << coder));
    if (length == Integer.MAX_VALUE) {
        throw new OutOfMemoryError("Required length exceeds implementation limit");
    }
    return length >> coder;
}

ArraysSupport.newLength這裡就是比較growtholdLength + (2 << coder)誰大,大者加上oldLength(這樣就成了2倍+2)。這裡coder原始值為0,我只看了append相關原始碼,coder值並沒有變,其他原始碼沒有看,注意可能發生改變。

JDK1.8中是直接進行移位操作+2的,現版本已更新。

StringBuffer常用方法

StringBuilder的API與之相同,只是執行緒不安全,沒有保證同步。

2. 日期時間

2.1 JDK8之前的日期時間

java.lang.System中的static long currentTimeMillis() 返回當前時間與1970年1月1日00:00:00之間的時間差(以毫秒為單位)。適用於計算時間差。(時間戳)

計算世界時間的主要標準有:UTC, GMT, CST

java.util.Date

java.sql中也有一個Date類,是java.util.Date的子類

表示特定的時間,精確到毫秒

兩個構造器的使用:

構造器一: 建立一個當前時間的Date物件

Date date = new Date();
System.out.println(date);//sout自帶.toString,輸出:Mon Apr 26 01:16:00 CST 2021
System.out.println(date.getTime());//返回當前date物件對應的時間戳

//Date中的無參構造原始碼
public Date() {
        this(System.currentTimeMillis());
    }

構造器二: 建立了一個指定時間的Date物件

Date date1 = new Date(1619371381884L); //隨便找了個時間戳
System.out.println(date1);

構造器的其餘方法均已過時,不建議使用。

java.sql.Date對應的是資料庫中的日期時間類,一般在資料庫互動時使用

java.sql.Date date2 = new java.sql.Date(1619371381884L); //2021-04-26
System.out.println(date2);

該類沒有無參構造。輸出形式不同。

兩種Date互轉:

Date date3 = (Date)date2;  //子類轉父類
System.out.println(date3);
java.sql.Date date4 = new java.sql.Date(new Date().getTime()); //父類轉子類,不能強制型別轉換

java.text.SimpleDateFormat

允許進行格式化:日期-->文字,解析:文字-->日期

格式化:

解析:

Date parse(String text, ParsePosition pos) 從字串中解析文字以產生一個 Date

pattern舉例如下圖:

demo1預設模式

SimpleDateFormat sdf = new SimpleDateFormat();
Date date = new Date();
String format = sdf.format(date);
System.out.println(date); //Mon Apr 26 02:38:11 CST 2021
System.out.println(format); //2021/4/26 上午2:38

//解析過程
String str = "2021/4/16 上午12:38";  //格式有要求
Date date1 = sdf.parse(str);
System.out.println(date1); //Fri Apr 16 00:38:00 CST 2021

使用指定模式:

SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy,MM,dd HH:mm:ss aaa");
String str2 = sdf1.format(date);
System.out.println(str2); //2021,04,26 02:47:22 上午
//解析的話也需要按這種模式進行,正常模式通常為”yyyy-MM-dd hh:mm:ss“
String str3 ="2021,04,26 02:47:22 上午";
Date date2 = sdf1.parse(str3);
System.out.println(date2); //Mon Apr 26 02:47:22 CST 2021

Calendar

Calendar是一個抽象類,主要用於完成日期欄位之間的相互操作。

Calendar提供了一種類方法getInstance ,用於獲取此型別的一般有用的物件。 CalendargetInstance方法返回一個Calendar物件,其日曆欄位已使用當前日期和時間進行初始化:

Calendar rightNow = Calendar.getInstance();呼叫了它的子類GregorianCalendar的構造器

Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getClass());//class java.util.GregorianCalendar

Calendar物件可以產生實現特定語言和日曆風格的日期時間格式化所需的所有日曆欄位值(例如日語 - 公曆,日語 - 繁體)。 Calendar定義某些日曆欄位返回的值的範圍及其含義。 例如,日曆系統第一個月的值為MONTH == JANUARY為所有日曆。 其他值由具體的子類定義,如ERA 。 有關詳細資訊,請參閱各個實體文件和子類文件。

常用方法:

void set(int field, int value) 將給定的日曆欄位設定為給定的值。

void add(int field, int amount) 根據日曆的規則,將指定的時間量新增或減去給定的日曆欄位。

final Date getTime() 返回一個 Date表示此物體 Calendar的時間值

void setTime(Date date) 使用給定的 Date設定此日曆的時間

demo如下:

Calendar calendar = Calendar.getInstance();
//get
int i = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(i);//獲取這個月的第幾天,本例項為26,當前時間4/26
System.out.println(calendar.get(Calendar.DAY_OF_YEAR));//類似上一個
//set
calendar.set(Calendar.DAY_OF_MONTH,12);
int j = calendar.get(Calendar.DAY_OF_MONTH);  //12,改變了
System.out.println(j);
//add
calendar.add(Calendar.DAY_OF_MONTH,3);
j = calendar.get(Calendar.DAY_OF_MONTH); //15,還是改變,增加3天
System.out.println(j);
//getTime
Date date = calendar.getTime(); //Thu Apr 15 03:10:28 CST 2021,返回時間戳
System.out.println(date);
//setTime:Date --> Calendar
calendar.setTime(date);//直接操作當前物件
int days = calendar.get(Calendar.DAY_OF_MONTH);  //15
System.out.println(days);

獲取月份時,一月是0;獲取星期幾時,週日是1

2.2 JDK8中的日期時間

因為之前的類具有4個問題:

  • 可變性:例如Calendarset,它們都是可變的
  • 偏移性:Date中的年份都是從1900開始,月份從0開始,如果呼叫有參構造,會發生偏移。
  • 格式化:格式化只對Date有用,對於Calendar則不行
  • 執行緒不安全

java8中的java.time API已經糾正了過去的缺陷。

時間日期的相關packge:

LocalDate, LocalTime, LocalDateTime是其中比較重要的幾個類,他們的例項均為不可變例項,使用ISO-8601日曆系統。

ISO-8601日曆系統是國際標準話組織制定的現代公民的日期和時間的表示法(公曆)

相關方法:

上面四個層次其實就是構造、get、set、加減操作。和Calendar類似。

localDate是一個final類,有構造方法,類似String, Math,舉例當前時間生成:

LocalDate localDate = LocalDate.now();  //2021-04-27
LocalTime localTime = LocalTime.now();  //19:24:37.171676500
LocalDateTime localDateTime = LocalDateTime.now();  //2021-04-27T19:24:37.171676500

舉例設定指定時間:

LocalDateTime localDateTime1 = LocalDateTime.of(2020,10,6,13,12,13);//2020-10-06T13:12:13

舉例相關get操作:

System.out.println(localDateTime.getMonth()); //APRIL
System.out.println(localDateTime.getMonthValue()); //4

這裡的月份是從1開始的。

.with操作(設定相關屬性):

LocalDate localDate1 = localDate.withDayOfMonth(22); //2021-04-22
System.out.println(localDate);  //2021-04-27
System.out.println(localDate1);

locatDate例項本身並沒有發生變化(不可變性)。

加減操作:

LocalDate localDate2 = localDate.plusDays(4); //localDate為4-27
System.out.println(localDate2);//2021-05-01
//減的話即將Plus換位minus

2.3 Instant(瞬時)

時間線上的一個瞬時點,可能用來記錄應用程式中的事件時間戳。

同樣是起始於1970年1月1日00:00:00的一個時間戳(納秒級)。

相關方法:

Java 常用類總結(SE基礎)

時間標準主要有:UTC, GMT, CST,UTC時間與倫敦本地時間相同,與北京相差8個小時(早了8個小時)

Instant instant = Instant.now();
System.out.println(instant); //2021-04-27T11:45:00.321544Z,實際時間19:45,相差8個小時

偏移應用:

OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);  //2021-04-27T19:48:17.448368100+08:00

返回時間戳(毫秒數):

System.out.println(instant.toEpochMilli());//1619524168468

設定特定時間,和Date類似:

Instant instant1 = Instant.ofEpochMilli(1619524168468L);  //2021-04-27T11:49:28.468Z,這裡的時間就是毫秒級的了
System.out.println(instant1);

2.4 DateTimeFormatter

三種預定義的標準格式:

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
//格式化:日期-->字串
LocalDateTime localDateTime = LocalDateTime.now();
String str = dateTimeFormatter.format(localDateTime);  //將當前時間格式化
System.out.println(str); //2021-04-27T19:59:19.0153049

//解析:字串-->日期
TemporalAccessor temporalAccessor = dateTimeFormatter.parse("2021-04-27T19:59:19.0153049");
System.out.println(temporalAccessor);//{},ISO resolved to 2021-04-27T19:59:19.015304900

本地化相關的格式:

DateTimeFormatter format = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
//SHORT 2021/4/27 下午8:09,  MEDIUM  2021年4月27日 下午8:10:02,
// 在java15中LONG會異常,1.8不會,DateTime中沒有FULL,Date中有
String str1 = format.format(localDateTime);
System.out.println(str1);

自定義格式(類似於SimpleDateFormat):

DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
String str1 = format.format(localDateTime); //2021-04-27 08:21:52
System.out.println(str1);
TemporalAccessor temporalAccessor1 = format.parse(str1);
System.out.println(temporalAccessor1);
//{MicroOfSecond=0, HourOfAmPm=8, MilliOfSecond=0, NanoOfSecond=0, MinuteOfHour=21, SecondOfMinute=52},ISO resolved to 2021-04-27

解析同上面即可,注意解析時需要一個TemporalAccessor轉承。

其他的一些API(不再詳細贅述):

Java 常用類總結(SE基礎)

以上三種Date之間的轉換:

3. 比較器

這裡牽扯到物件的比較

實現Comparable介面(自然排序),重寫compareTo()方法,重寫的規則是:當前物件this大於形參物件obj,返回正整數;this小於,返回負整數;this等於,返回0;

使用Comparator介面(定製排序)

適用於該型別沒有實現Comparable介面,且不方便修改程式碼;或者實現了Comparable介面但是排序規則不適合當前操作

對比:

  • Comparable介面的方式可以保證類的物件在任何位置都可以實現比較
  • Comparator介面屬於臨時性的比較

關於應用在之前的部落格中已有實現,可參考

(Set, Map, Collections工具類)JAVA集合框架二

4. System, Math, BigInteger 和 BigDecimal

4.1 System

java.lang.System

成員變數:in, out ,err三個,分別代表標準輸入流(鍵盤輸入),標準輸出流(顯示器),標準錯誤輸出流(顯示器)

static long currentTimeMillis() 返回當前時間(以毫秒為單位)。表達格式同時間戳。

static void exit(int status) 終止當前執行的Java虛擬機器。status為0時代表正常退出,非零則為異常退出。

static void gc() 執行垃圾回收器。請求系統進行垃圾回收。

static String getProperty(String key) 獲取指定鍵指示的系統屬性。對於常用的key

Java 常用類總結(SE基礎)

4.2 Math

以上為Math常用方法總結。可見開發文件。

4.3 BigInteger與BigDecimal

BigInteger

構造方法:

BigInteger提供所有java的基本整數操作符的對應物,並提供java.lang.Math的所有相關方法,另外,還提供一下運算:模算術,GCD計算,質數測試,素數生成,位操作等。

BigDecimal

FloatDouble的精度不能滿足使用者需求時,可以使用BigDecimal

構造方法:

BigDecimal(double val)double轉換為 BigDecimal ,這是 double的二進位制浮點值的精確十進位制表示。

BigDecimal(String val) 將BigDecimal的字串表示 BigDecimal轉換為 BigDecimal

還有很多,只舉例了兩種常用的。

加減乘除操作類似於BigInteger,說明一下devide

scale即保留多少位小數,上下文設定用的不多不再贅述。

幾種舍入模式:

其中,有些翻譯不夠準確,解釋一下:

ROUND_UP,即向上舍。0.1203456789,當精度為3的時候,按照ROUND_UP模式,結果是0.121

ROUND_DOWN即向下舍。

ROUND_HALF_EVEN,像鄰近的偶數方向舍。

這幾個可以參考對應英文進行理解。

4.4 個人總結的其他類

其實經常用到的還有Ramdom,生活中經常用到隨機數。

例如取一個隨機整數。

Random r1 = new Random();
int i = r1.nextInt(100); //取0到100的隨機整數,無 100

其他方法都是與之類似的,具體可參考開發文件。

相關文章