本篇部落格對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==s2
為true
,s1==s3
, s1==s4
, s3==s4
均為false
原因如下:
實際上,通過構造方法來構造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)
另外
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
String
與StringBuffer, 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
這裡就是比較growth
和oldLength + (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
,用於獲取此型別的一般有用的物件。 Calendar
的getInstance
方法返回一個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個問題:
- 可變性:例如
Calendar
的set
,它們都是可變的 - 偏移性:
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的一個時間戳(納秒級)。
相關方法:
時間標準主要有: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(不再詳細贅述):
以上三種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
:
4.2 Math
以上為Math
常用方法總結。可見開發文件。
4.3 BigInteger與BigDecimal
BigInteger
構造方法:
BigInteger
提供所有java的基本整數操作符的對應物,並提供java.lang.Math
的所有相關方法,另外,還提供一下運算:模算術,GCD計算,質數測試,素數生成,位操作等。
BigDecimal
Float
和Double
的精度不能滿足使用者需求時,可以使用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
其他方法都是與之類似的,具體可參考開發文件。