一.字符串相關的類
1.String及常用方法
1.1 String的特性
String:字符串,使用一對""引起來表示。
- String聲明爲
final
的,不可被繼承 - String實現了
Serializable
接口:表示字符串是支持序列化的。
實現了Comparable
接口:表示String可以比較大小 - String內部定義了
final char[] value
用於存儲字符串數據 - String:代表不可變的字符序列。簡稱:不可變性。
體現:
- 當對字符串重新賦值時,需要重寫指定內存區域賦值,不能使用原有的value進行賦值。
- 當對現有的字符串進行連接操作時,也需要重新指定內存區域賦值,不能使用原有的value進行賦值。
- 當調用String的
replace()
方法修改指定字符或字符串時,也需要重新指定內存區域賦值,不能使用原有的value進行賦值。
- 通過字面量的方式(區別於new)給一個字符串賦值,此時的字符串值聲明在字符串常量池中。
- 字符串常量池中是不會存儲相同內容的字符串的。
String s1 = "abc";//字面量的定義方式
String s2 = "abc";
s1 = "hello";
System.out.println(s1 == s2); // false 比較s1和s2的地址值
System.out.println(s1); // hello
System.out.println(s2); // abc
System.out.println("*****************");
String s3 = "abc";
s3 += "def";
System.out.println(s3); // abcdef
System.out.println(s2); // abc
System.out.println("*****************");
String s4 = "abc";
String s5 = s4.replace('a', 'm');
System.out.println(s4); // abc
System.out.println(s5); // mbc
1.2 String對象的創建
String的實例化方式:
- 通過字面量定義的方式:
String.valueOf()
- 通過new + 構造器的方式:
new String()
//通過字面量定義的方式:此時的s1和s2的數據javaEE聲明在方法區中的字符串常量池中。
String s1 = "javaEE";
String s2 = "javaEE";
//通過new + 構造器的方式:此時的s3和s4保存的地址值,是數據在堆空間中開闢空間以後對應的地址值。
String s3 = new String("javaEE");
String s4 = new String("javaEE");
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println(s3 == s4);//false
System.out.println("***********************");
Person p1 = new Person("Tom",12);
Person p2 = new Person("Tom",12);
System.out.println(p1.name.equals(p2.name));//true
System.out.println(p1.name == p2.name);//true
p1.name = "Jerry";
System.out.println(p2.name);//Tom
面試題:String s = new String(“abc”);方式創建對象,在內存中創建了幾個對象?
兩個: 一個是堆空間中new結構,另一個是char[]對應的常量池中的數據:“abc”
1.3 String使用陷阱
關於拼接字符串後兩個變量地址是否相等。
- 常量與常量的拼接結果在常量池。且常量池中不會存在相同內容的常量。
- 只要其中有一個是變量,結果就在堆中
- 如果拼接的結果調用intern()方法,返回值就在常量池中
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
final String s8 = "javaEE";//s8:常量
String s9 = s8 + "hadoop";
String s11 = s8 + s2;
System.out.println(s3 == s9); // true
System.out.println(s3 == s11); // false
System.out.println(s3 == s4);//true
System.out.println(s3 == s5);//false
System.out.println(s3 == s6);//false
System.out.println(s3 == s7);//false
System.out.println(s5 == s6);//false
System.out.println(s5 == s7);//false
System.out.println(s6 == s7);//false
String s10 = s6.intern();//返回值得到的s8使用的常量值中已經存在的“javaEEhadoop”
System.out.println(s3 == s10);//true
面試題:
String str = new String("good");
char[] ch = { 't', 'e', 's', 't' };
public void change(String str, char ch[]) { // 傳遞的是引用
str = "test ok"; // 給傳遞過來的地址重新賦值,而不是改變引用重新指向
ch[0] = 'b';
}
public static void main(String[] args) {
StringTest ex = new StringTest();
ex.change(ex.str, ex.ch);
System.out.println(ex.str); // good string是不可變的,不能重新賦值
System.out.println(ex.ch); // best 數組是可變的
}
1.4 String常用方法
a.基本方法:
方法 | 描述 |
---|---|
int length() | 返回字符串的長度: return value.length |
char charAt(int index) | 返回某索引處的字符return value[index] |
boolean isEmpty() | 判斷是否是空字符串:return value.length == 0 |
String toLowerCase() | 使用默認語言環境,將 String 中的所有字符轉換爲小寫 |
String toUpperCase() | 使用默認語言環境,將 String 中的所有字符轉換爲大寫 |
String trim() | 返回字符串的副本,忽略前導空白和尾部空白 |
boolean equals(Object obj) | 比較字符串的內容是否相同 |
boolean equalsIgnoreCase(String anotherString) | 與equals方法類似,忽略大小寫 |
String concat(String str) | 將指定字符串連接到此字符串的結尾。 等價於用“+” |
int compareTo(String anotherString) | 比較兩個字符串的大小 |
String substring(int beginIndex) | 返回一個新的字符串,它是此字符串的從beginIndex開始截取到最後的一個子字符串。 |
String substring(int beginIndex, int endIndex) | 返回一個新字符串,它是此字符串從beginIndex開始截取到endIndex(不包含)的一個子字符串。 |
b.包含:
方法 | 描述 |
---|---|
boolean endsWith(String suffix) | 測試此字符串是否以指定的後綴結束 |
boolean startsWith(String prefix) | 測試此字符串是否以指定的前綴開始 |
boolean startsWith(String prefix, int toffset) | 測試此字符串從指定索引開始的子字符串是否以指定前綴開始 |
boolean contains(CharSequence s) | 當且僅當此字符串包含指定的 char 值序列時,返回 true |
int indexOf(String str) | 返回指定子字符串在此字符串中第一次出現處的索引 |
int indexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中第一次出現處的索引,從指定的索引開始 |
int lastIndexOf(String str) | 返回指定子字符串在此字符串中最右邊出現處的索引 |
int lastIndexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中最後一次出現處的索引,從指定的索引開始反向搜索 |
注:indexOf和lastIndexOf方法如果未找到都是返回-1
String str1 = "hellowworld";
boolean b1 = str1.endsWith("rld");
System.out.println(b1); // true
boolean b2 = str1.startsWith("He");
System.out.println(b2); // false
boolean b3 = str1.startsWith("ll",2);
System.out.println(b3); // true
String str2 = "wor";
System.out.println(str1.contains(str2)); // true
System.out.println(str1.indexOf("lol")); // -1
System.out.println(str1.indexOf("lo",5)); // -1 (3+2)
String str3 = "hellorworld";
System.out.println(str3.lastIndexOf("or")); // 7
System.out.println(str3.lastIndexOf("or",6)); // 4 (7-1)
//什麼情況下,indexOf(str)和lastIndexOf(str)返回值相同?
//情況一:存在唯一的一個str。情況二:不存在str
c.替換:
方法 | 描述 |
---|---|
String replace(char oldChar, char newChar) | 返回一個新的字符串,它是通過用 newChar 替換此字符串中出現的所有 oldChar 得到的。 |
String replace(CharSequence target, CharSequence replacement) | 使用指定的字面值替換序列替換此字符串所有匹配字面值目標序列的子字符串。 |
String replaceAll(String regex, String replacement) | 使用給定的 replacement 替換此字符串所有匹配給定的正則表達式的子字符串。 |
String replaceFirst(String regex, String replacement) | 使用給定的 replacement 替換此字符串匹配給定的正則表達式的第一個子字符串。 |
d.匹配:
方法 | 描述 |
---|---|
boolean matches(String regex) | 告知此字符串是否匹配給定的正則表達式。 |
e.切片:
方法 | 描述 |
---|---|
String[] split(String regex) | 根據給定正則表達式的匹配拆分此字符串。 |
String[] split(String regex, int limit) | 根據匹配給定的正則表達式來拆分此字符串,最多不超過limit個,如果超過了,剩下的全部都放到最後一個元素中。 |
String str1 = "helloworld";
String str2 = str1.replace('o', 'u');
System.out.println(str1); // helloworld
System.out.println(str2); // helluwurld
String str3 = str1.replace("he", "do");
System.out.println(str3); // dolloworld
System.out.println("*************************");
String str = "12hello34world5java7891mysql456";
//把字符串中的數字替換成,,如果結果中開頭和結尾有,的話去掉
String string = str.replaceAll("\\d+", ",").replaceAll("^,|,$", "");
System.out.println(string); // hello,world,java,mysql
System.out.println("*************************");
str = "12345";
//判斷str字符串中是否全部有數字組成,即有1-n個數字組成
boolean matches = str.matches("\\d+");
System.out.println(matches); // true
String tel = "0571-4534289";
//判斷這是否是一個杭州的固定電話
boolean result = tel.matches("0571-\\d{7,8}");
System.out.println(result); // true
System.out.println("*************************");
str = "hello|world|java";
String[] strs = str.split("\\|");
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]); // hello world java
}
System.out.println();
str2 = "hello.world.java";
String[] strs2 = str2.split("\\.");
for (int i = 0; i < strs2.length; i++) {
System.out.println(strs2[i]); // hello world java
}
1.5 string類與其他結構之間的轉換
a.String 與基本數據類型、包裝類之間的轉換
- String --> 基本數據類型、包裝類:調用
包裝類的靜態方法
:parseXxx(str) - 基本數據類型、包裝類 --> String:調用String重載的
valueOf(xxx)
String str1 = "123";
// int num = (int)str1; // 錯誤的
int num = Integer.parseInt(str1);
String str2 = String.valueOf(num); // "123"
String str3 = num + "";
System.out.println(str1 == str3); // false
b.String 與 char[]之間的轉換
- String --> char[] : 調用String的
toCharArray()
- char[] --> String : 調用String的
構造器
String str1 = "abc123";
char[] charArray = str1.toCharArray();
for (int i = 0; i < charArray.length; i++) {
System.out.println(charArray[i]);
}
char[] arr = new char[]{'h','e','l','l','o'};
String str2 = new String(arr);
System.out.println(str2);
c.String 與 byte[]之間的轉換
- 編碼:String --> byte[] : 調用String的
getBytes()
編碼:字符串 -->字節數組 (看得懂 —>看不懂的二進制數據) - 解碼:byte[] --> String : 調用String的
構造器
解碼:編碼的逆過程,字節數組 --> 字符串 (看不懂的二進制數據 —> 看得懂) - 說明:解碼時,要求解碼使用的字符集必須與編碼時使用的字符集一致,否則會出現亂碼。
String str1 = "abc123中國";
byte[] bytes = str1.getBytes();//使用默認的字符集,進行編碼。
System.out.println(Arrays.toString(bytes));
byte[] gbks = str1.getBytes("gbk");//使用gbk字符集進行編碼。
System.out.println(Arrays.toString(gbks));
System.out.println("******************");
String str2 = new String(bytes);//使用默認的字符集,進行解碼。
System.out.println(str2);
String str3 = new String(gbks);
System.out.println(str3);//出現亂碼。原因:編碼集和解碼集不一致!
String str4 = new String(gbks, "gbk");
System.out.println(str4);//沒有出現亂碼。原因:編碼集和解碼集一致!
2.StringBuffer與StringBuilder
2.1 概念
StringBuffer與StringBuilder都是可變的字符序列,都可以對字符串內容進行增刪,不會產生新的對象。兩者非常相似,很多方法與String相同。
下面是StringBuffer、StringBuilder及AbstractStringBuilder的部分源碼:
// StringBuffer
* @since JDK1.0
*/
public final class StringBuffer extends AbstractStringBuilder
implements java.io.Serializable, CharSequence {
private transient char[] toStringCache;
static final long serialVersionUID = 3388685877147921107L;
public StringBuffer() {
super(16); // AbstractStringBuilder(int capacity)
}
public StringBuffer(int capacity) {
super(capacity);
}
public StringBuffer(String str) {
super(str.length() + 16); // AbstractStringBuilder(int capacity)
append(str);
}
}
// -------------------------------------------------------------------------
// StringBuilder
* @since 1.5
*/
public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, CharSequence {
static final long serialVersionUID = 4383685877147921099L;
public StringBuilder() {
super(16); // AbstractStringBuilder(int capacity)
}
public StringBuilder(int capacity) {
super(capacity);
}
public StringBuilder(String str) {
super(str.length() + 16); // AbstractStringBuilder(int capacity)
append(str);
}
}
// -------------------------------------------------------------------------
// AbstractStringBuilder
abstract class AbstractStringBuilder implements Appendable, CharSequence {
// 沒有final聲明,value可以不斷擴容
char[] value;
// 記錄有效字符的個數
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
// 容量擴展機制
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);// 有效字符個數+附加字符長度
str.getChars(0, len, value, count);
count += len;
return this;
}
// append(String str):當str==null時
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
// 容量擴充
private void ensureCapacityInternal(int minimumCapacity) {
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));// 創建新的容量
}
}
private int newCapacity(int minCapacity) {
int newCapacity = (value.length << 1) + 2;// (count+len)*2+2
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
}
源碼分析:
String str = new String(); //char[] value = new char[0];
String str1 = new String("abc"); //char[] value = new char[]{'a','b','c'};
StringBuffer sb1 = new StringBuffer(); //char[] value = new char[16];創建了一個長度是16的數組。
StringBuffer sb2 = new StringBuffer("abc"); //char[] value = new char["abc".length() + 16];
問題:
System.out.println(sb1.length()); //0;System.out.println(sb2.length());//3
- 擴容問題:如果要添加的數據底層數組盛不下了,那就需要擴容底層的數組。默認情況下,擴容爲原來容量的2倍 + 2,同時將原有數組中的元素複製到新的數組中。
- 指導意義:開發中建議大家使用:
StringBuffer(int capacity) 或 StringBuilder(int capacity)
2.2 構造器及常用方法
構造器:
構造器 | 描述 |
---|---|
StringBuffer() | 初始容量爲16 的字符串緩衝區 |
StringBuffer(int size) | 構造指定容量的字符串緩衝區 |
StringBuffer(String str) | 將內容初始化爲指定字符串內容 |
常用方法:
方法 | 描述 |
---|---|
StringBuffer append(xxx) | 增 |
StringBuffer delete(int start,int end) | 刪 |
public void setCharAt(int n ,char ch) | 改 |
StringBuffer replace(int start, int end, String str) | 改:把[start,end)位置替換爲str |
public char charAt(int n ) | 查 |
StringBuffer insert(int offset, xxx) | 插 |
public int length() | 長度 |
for() + charAt() / toString() | 遍歷 |
注意:
String str = null;
StringBuffer sb = new StringBuffer();
sb.append(str); // 當添加null時,會返回"null"字符
System.out.println(sb.length());//4
System.out.println(sb);//"null"
StringBuffer sb1 = new StringBuffer(str);// 創造對象時爲null,則是空對象
System.out.println(sb1);//java.lang.NullPointerException
3.String, Stringbuffer, StringBuilder區別
相同點:
- 都是final類,都不能被繼承;
- 都是採用的char[]存儲。
異同點:
- String是不可變的字符序列(char[] 是final修飾的),每次對String對象改變,都會返回一個新的String對象;StringBuffer、StringBuilder是可變的字符序列(char[]沒有final修飾),不會產生新的對象;
- StringBuffer是線程安全的,效率低;StringBuilder是線程不安全的,效率高;StringBuilder > StringBuffer > String。
- StringBuffer和StringBuilder擴容都是value長度的2倍+2。
二.日期時間API
1.JDK8之前
java.util.Date、java.sql.Date、SimpleDateFormat、Calendar、GregorianCalendar
1.1 System靜態方法
java.lang.System類提供的public static long currentTimeMillis()
用來返回當前時間與1970年1月1日0時0分0秒之間以毫秒爲單位的時間差
long time = System.currentTimeMillis();
//返回當前時間與1970年1月1日0時0分0秒之間以毫秒爲單位的時間差。
//稱爲時間戳
System.out.println(time);
1.2 Date類
java.util.Date類表示特定的瞬間,精確到毫秒。子類java.sql.Date類。
構造器:
構造器 | 描述 |
---|---|
Date() | 創建一個對應當前時間的Date對象 |
Date(long date) | 創建指定毫秒數的Date對象 |
常用方法:
方法 | 描述 |
---|---|
toString() | 把此 Date 對象轉換爲以下形式的 String: dow mon dd hhmmss zzz yyyy |
getTime() | 獲取當前Date對象對應的毫秒數。(時間戳) |
示例:
//構造器一:Date():創建一個對應當前時間的Date對象
Date date1 = new Date();
System.out.println(date1.toString());//Sat Feb 16 16:35:31 GMT+08:00 2019
System.out.println(date1.getTime());//1550306204104
//構造器二:創建指定毫秒數的Date對象
Date date2 = new Date(155030620410L);
System.out.println(date2.toString());
java.sql.Date類:
實例化:new java.sql.Date(long date)
util.Date與sql.Date相互轉換:
sql.Date --> util.Date:子類對象轉父類對象自動轉型(多態)
util.Date --> sql.Date:new java.sql.Date( (new Date()).getTime() )
示例:
//創建java.sql.Date對象
java.sql.Date date3 = new java.sql.Date(35235325345L);
System.out.println(date3);//1971-02-13
//如何將java.util.Date對象轉換爲java.sql.Date對象
//情況一:
// Date date4 = new java.sql.Date(2343243242323L);
// java.sql.Date date5 = (java.sql.Date) date4;
//情況二:
Date date6 = new Date();
java.sql.Date date7 = new java.sql.Date(date6.getTime());
1.3 SimpleDataFormat類
SimpleDateFormat類對日期Date類的格式化和解析:
- 格式化:日期 --> 字符串
- 解析:字符串 --> 日期
相關構造器及方法:
方法 | 描述 |
---|---|
public SimpleDateFormat(String pattern) | 該構造方法可以用參數pattern指定的格式創建一個對象 |
public String format(Date date) | 格式化時間對象date |
public Date parse(String source) | 從給定字符串的開始解析文本,以生成一個日期 |
示例:
// SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyy.MMMMM.dd GGG hh:mm aaa");
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
//格式化
String format1 = sdf1.format(date);
System.out.println(format1);//2019-02-18 11:48:27
//解析:要求字符串必須是符合SimpleDateFormat識別的格式(通過構造器參數體現),否則,拋異常
Date date2 = sdf1.parse("2020-02-18 11:48:27");
System.out.println(date2);
1.4 Calendar類
Calendar是一個抽象基類,主用用於完成日期字段之間相互操作的功能。
構造器及常用方法:
int field:靜態屬性(YEAR、MONTH、DAY_OF_WEEK、HOUR_OF_DAY 、MINUTE、SECOND)等
方法 | 描述 |
---|---|
Calendar.getInstance() | 獲取Calendar實例 |
public int get(int field) | 獲取指定部位的時間信息 |
public void set(int field,int value) | 設置指定部位的時間信息 |
public void add(int field,int amount) | 修改指定部位的時間信息 |
public final Date getTime() | 日曆類—> Date |
public final void setTime(Date date) | Date —> 日曆類 |
注意:
- 獲取月份時:一月是0,二月是1,以此類推,12月是11
- 獲取星期時:週日是1,週二是2 , 。。。。週六是7
示例:
//1.實例化
//方式一:創建其子類(GregorianCalendar)的對象
//方式二:調用其靜態方法getInstance()
Calendar calendar = Calendar.getInstance();
// System.out.println(calendar.getClass());
//2.常用方法
//get()
int days = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
System.out.println(calendar.get(Calendar.DAY_OF_YEAR));
//set()
//calendar可變性
calendar.set(Calendar.DAY_OF_MONTH,22);
days = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
//add()
calendar.add(Calendar.DAY_OF_MONTH,-3);
days = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
//getTime():日曆類---> Date
Date date = calendar.getTime();
System.out.println(date);
//setTime():Date ---> 日曆類
Date date1 = new Date();
calendar.setTime(date1);
days = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
2.JDK8
Calendar面臨的問題:
可變性:像日期和時間這樣的類應該是不可變的。
偏移性:Date中的年份是從1900開始的,而月份都從0開始。
格式化:格式化只對Date有用,Calendar則不行。
此外,它們也不是線程安全的;不能處理閏秒等
Java 8 吸收了 Joda-Time 的精華,以一個新的開始爲 Java 創建優秀的 API。新的 java.time 中包含了所有關於本地日期(LocalDate)、本地時間(LocalTime)、本地日期時間(LocalDateTime)、時區(ZonedDateTime)和持續時間(Duration)的類。
API:
包 | 描述 |
---|---|
java.time | 包含值對象的基礎包 |
java.time.chrono | 提供對不同的日曆系統的訪問 |
java.time.format | 格式化和解析時間和日期 |
java.time.temporal | 包括底層框架和擴展特性 |
java.time.zone | 包含時區支持的類 |
2.1 LocalDate、LocalTime、LocalDateTime
這三個類的實例都是不可變的對象。LocalDate代表IOS格式(yyyy-MM-dd)的日期;LocalTime表示一個時間;LocalDateTime是用來表示日期和時間的。
LocalDateTime使用頻率偏高,用法類似於Calendar。
方法 | 描述 |
---|---|
now() | 靜態方法,根據當前時間創建對象 |
of() | 靜態方法,根據指定日期/時間創建對象 |
getDayOfMonth() / getDayOfYear() | 獲得月份天數(1-31) /獲得年份天數(1-366) |
getDayOfWeek() | 獲得星期幾(返回一個 DayOfWeek 枚舉值) |
getMonth() | 獲得月份, 返回一個 Month 枚舉值 |
getMonthValue() / getYear() | 獲得月份(1-12) /獲得年份 |
getHour() / getMinute() / getSecond() | 獲得當前對象對應的小時、分鐘、秒 |
withDayOfMonth() / withDayOfYear() / withMonth() / withYear() | 將月份天數、年份天數、月份、年份修改爲指定的值並返回新的對象 |
plusDays() / plusWeeks() / plusMonths() / plusYears() / plusHours() | 向當前對象添加幾天、幾周、幾個月、幾年、幾小時 |
minusMonths() / minusWeeks() / minusDays() / minusYears() / minusHours() | 從當前對象減去幾月、幾周、幾天、幾年、幾小時 |
示例:
//now():獲取當前的日期、時間、日期+時間
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDate); // 2019-12-18
System.out.println(localTime); // 10:14:29.600
System.out.println(localDateTime); // 2019-12-18T10:14:29.600
//of():設置指定的年、月、日、時、分、秒。沒有偏移量
LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 6, 13, 23, 43);
System.out.println(localDateTime1); // 2020-10-06T13:23:43
//getXxx():獲取相關的屬性
System.out.println(localDateTime.getDayOfMonth()); // 18
System.out.println(localDateTime.getDayOfWeek()); // WEDNESDAY
System.out.println(localDateTime.getMonth()); // DECEMBER
System.out.println(localDateTime.getMonthValue()); // 12
System.out.println(localDateTime.getMinute()); // 14
//體現不可變性
//withXxx():設置相關的屬性
LocalDate localDate1 = localDate.withDayOfMonth(22);
System.out.println(localDate); // 2019-12-18
System.out.println(localDate1); // 2019-12-22
LocalDateTime localDateTime2 = localDateTime.withHour(4);
System.out.println(localDateTime); // 2019-12-18T10:14:29.600
System.out.println(localDateTime2); // 2019-12-18T04:14:29.600
LocalDateTime localDateTime3 = localDateTime.plusMonths(3);
System.out.println(localDateTime3); // 2020-03-18T10:14:29.600
LocalDateTime localDateTime4 = localDateTime.minusDays(6);
System.out.println(localDateTime4); // 2019-12-12T10:14:29.600
2.2 Instant
Instant:時間線上的一個瞬時點,不需要任何上下文信息。這可以用來記錄應用程序中的事件時間戳。用法類似於 java.util.Date 類。
年月日時分秒是面向人類的一個時間模型,時間線中一點是面向機器的另一個時間模型。在Java中,也是從1970年開始,但以毫秒爲單位。
1秒 = 1000毫秒 =10^6 微妙=10^9納秒
方法 | 描述 |
---|---|
now() | 靜態方法,返回默認UTC時區的Instant類的對象 |
ofEpochMilli(long epochMilli) | 靜態方法,返回在1970-01-01 00 00 00基礎上加上指定毫秒數之後的Instant類的對象 |
atOffset(ZoneOffset offset) | 結合即時的偏移來創建一個 OffsetDateTime |
toEpochMilli() | 返回1970-01-01 00 00 00到當前時間的毫秒數,即爲時間戳 |
時間戳是指格林威治時間1970 年01 月01 日00 時00 分00 秒( 北京時間1970 年01 月01
日08 時00 分00 秒) 起至現在的總秒數(東八區)。
示例:
//now():獲取本初子午線對應的標準時間
Instant instant = Instant.now();
System.out.println(instant);//2019-12-18T02:42:50.214Z
//添加時間的偏移量
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);//2019-12-18T10:42:50.214+08:00
//toEpochMilli():獲取自1970年1月1日0時0分0秒(UTC)開始的毫秒數 ---> Date類的getTime()
long milli = instant.toEpochMilli();
System.out.println(milli); // 1576636970214
//ofEpochMilli():通過給定的毫秒數,獲取Instant實例 -->Date(long millis)
Instant instant1 = Instant.ofEpochMilli(1576636970214L);
System.out.println(instant1); // 2019-12-18T02:42:50.214Z
2.3 DateTimeFormatter
java.time.format.DateTimeFormatter類:格式化與解析日期或時間類。用法類似於SimpleDateFormat類。DateTimeFormatter提供了三種格式化方法:
-
預定義的標準格式。靜態常量:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
-
本地化相關的格式。靜態方法:ofLocalizedDateTime(FormatStyle.LONG)、ofLocalizedDate(FormatStyle.MEDIUM)。
ofLocalizedDateTime():
-
FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT :適用於LocalDateTime
DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
ofLocalizedDate():
-
FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT : 適用於LocalDate
DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
-
-
自定義的格式(常用)。如:ofPattern(“yyyy-MM-dd hh mm ss”)
方法 | 描述 |
---|---|
ofPattern(String pattern) | 靜態方法,返回一個指定字符串格式的DateTimeFormatter |
format(TemporalAccessor t) | 格式化一個日期、時間,返回字符串 |
parse(CharSequence text) | 將指定格式的字符序列解析爲一個日期、時間 |
示例:
//重點:自定義的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
//格式化
String str4 = formatter3.format(LocalDateTime.now());
System.out.println(str4);// 2019-12-18 11:08:46 沒有偏移量
//解析
TemporalAccessor accessor = formatter3.parse("2019-12-18 11:08:46");
System.out.println(accessor);
// {SecondOfMinute=46, NanoOfSecond=0, MicroOfSecond=0, MinuteOfHour=8, MilliOfSecond=0,
// HourOfAmPm=11},ISO resolved to 2019-12-18
2.4 其它API
-
ZoneId :該類中包含了所有的時區信息,一個時區的ID,如 Europe/Paris
-
ZonedDateTime :一個在ISO-8601日曆系統時區的日期時間,如 2007-12-03T10 15 30+01 00 Europe/Paris。
- 其中每個時區都對應着ID,地區ID都爲“{區域}/{城市}”的格式,例如:Asia/Shanghai等
-
Clock :使用時區提供對當前即時、日期和時間的訪問的時鐘。
-
持續時間:Duration,用於計算兩個“時間”間隔
-
日期間隔:Period,用於計算兩個“日期”間隔
-
TemporalAdjuster : 時間校正器。有時我們可能需要獲取例如:將日期調整到“下一個工作日”等操作。
-
TemporalAdjusters : 該類通過靜態方法
(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用TemporalAdjuster 的實現
三.java比較器
Java中的對象,正常情況下,只能進行比較:== 或 != 。不能使用 > 或 < 的
- 但是在開發場景中,我們需要對多個對象進行排序,言外之意,就需要比較對象的大小。
- 如何實現?使用兩個接口中的任何一個:Comparable 或 Comparator
Java實現對象數組排序的方式有兩種:
- 自然排序:java.lang.Comparable (實現類的對象在任何位置都可以比較大小)
- 定製排序:java.util.Comparator (屬於臨時性的比較)
1.Comparable接口
Comparable接口強行對實現它的每個類的對象進行整體排序。這種排序被稱爲類的自然排序。
1.像String、包裝類等實現了Comparable接口,重寫了compareTo(obj)方法,給出了比較兩個對象大小的方式,進行從小到大的排列。
2.對於自定義類來說,如果需要排序,我們可以讓自定義類實現Comparable接口,重寫compareTo(obj)方法。在compareTo(obj)方法中指明如何排序。
3.實現Comparable接口的對象列表(和數組)可以通過 Collections.sort
或Arrays.sort
進行自動排序。實現此接口的對象可以用作有序映射中的鍵或有序集合中的元素,無需指定比較器。
4.重寫compareTo(obj)的規則:
- 如果當前對象this大於形參對象obj,則返回正整數
- 如果當前對象this小於形參對象obj,則返回負整數
- 如果當前對象this等於形參對象obj,則返回零
5.Comparable的典型實現:(默認都是從小到大排列)
- String:按照字符串中字符的Unicode值進行比較
- Character:按照字符的Unicode值來進行比較
- 數值類型對應的包裝類以及BigInteger、BigDecimal:按照它們對應的數值大小進行比較
- Boolean:true 對應的包裝類實例大於 false 對應的包裝類實例
- Date、Time等:後面的日期時間比前面的日期時間大
6.示例:
// 1.String類已經實現了Comparable接口
String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"};
// 調用Arrays工具類進行自動排序
Arrays.sort(arr);
// [AA, CC, DD, GG, JJ, KK, MM]
System.out.println(Arrays.toString(arr));
// ------------------------------------------------------------------
// 2.自定義Goods類
Goods[] arr = new Goods[5];
arr[0] = new Goods("lenovoMouse",34);
arr[1] = new Goods("dellMouse",43);
arr[2] = new Goods("xiaomiMouse",12);
arr[3] = new Goods("huaweiMouse",65);
arr[4] = new Goods("microsoftMouse",43);
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
// [Goods{name='xiaomiMouse', price=12.0},
// Goods{name='lenovoMouse', price=34.0},
// Goods{name='microsoftMouse', price=43.0},
// Goods{name='dellMouse', price=43.0},
// Goods{name='huaweiMouse', price=65.0}]
// ------------------------------------------------------------------
// 自定義Goods類,實現Comparable接口,重寫compareTo()方法
public class Goods implements Comparable{
private String name;
private double price;
public Goods(String name, double price) {
this.name = name;
this.price = price;
}
//指明商品比較大小的方式:按照價格從低到高排序,再按照產品名稱從高到低排序
@Override
public int compareTo(Goods g) {
if(this.price == g.price){
return -this.name.compareTo(g.name); // 添加符號則從高到低
}else{
return Double.compare(this.price,g.price);
}
}
}
2.Comparator接口
1.背景:當元素的類型沒有實現java.lang.Comparable接口而又不方便修改代碼,或者實現了java.lang.Comparable接口的排序規則不適合當前的操作,那麼可以考慮使用 Comparator 的對象來排序。
2.重寫compare(Object o1,Object o2)方法,比較o1和o2的大小:如果方法返回正整數,則表示o1大於o2;如果返回0,表示相等;返回負整數,表示o1小於o2。
3.示例:
// 1.String類數組
String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"};
Arrays.sort(arr,new Comparator<String>(){ // 匿名對象
//按照字符串從大到小的順序排列
@Override
public int compare(String s1, String s2) {
return -s1.compareTo(s2);
}
});
System.out.println(Arrays.toString(arr)); // [MM, KK, JJ, GG, DD, CC, AA]
// ------------------------------------------------------------------
// 2.自定義類數組
Goods[] arr = new Goods[6];
arr[0] = new Goods("lenovoMouse",34);
arr[1] = new Goods("dellMouse",43);
arr[2] = new Goods("xiaomiMouse",12);
arr[3] = new Goods("huaweiMouse",65);
arr[4] = new Goods("huaweiMouse",224);
arr[5] = new Goods("microsoftMouse",43);
Arrays.sort(arr, new Comparator<Goods>() { // 匿名對象
//指明商品比較大小的方式:按照產品名稱從低到高排序,再按照價格從高到低排序
@Override
public int compare(Goods g1, Goods g2) {
if(g1.getName().equals(g2.getName())){
return -Double.compare(g1.getPrice(),g2.getPrice());
}else{
return g1.getName().compareTo(g2.getName());
}
}
});
System.out.println(Arrays.toString(arr));
// [Goods{name='dellMouse', price=43.0},
// Goods{name='huaweiMouse', price=224.0},
// Goods{name='huaweiMouse', price=65.0},
// Goods{name='lenovoMouse', price=34.0},
// Goods{name='microsoftMouse', price=43.0},
// Goods{name='xiaomiMouse', price=12.0}]
// ------------------------------------------------------------------
// 自定義Goods類,不實現Comparable接口
public class Goods {
private String name;
private double price;
public Goods(String name, double price) {
this.name = name;
this.price = price;
}
}
四.System類
System類代表系統,系統級的很多屬性和控制方法都放置在該類的內部。該類位於java.lang包。
由於該類的構造器是private的,所以無法創建該類的對象,也就是無法實例化該類。其內部的成員變量和成員方法都是static的。
成員變量:
成員變量 | 描述 |
---|---|
in | 標準輸入流(鍵盤輸入) |
out | 標準輸出流(顯示器) |
err | 標準錯誤輸出流(顯示器) |
成員方法:
成員方法 | 描述 |
---|---|
native long currentTimeMillis() | 返回當前的計算機時間(1970-01-01 00-00-00) |
void exit(int status) | 退出程序。其中status的值爲0代表正常退出,非零代表 |
void gc() | 請求系統進行垃圾回收(不一定是立刻回收) |
String getProperty(String key) | 獲得系統中屬性名爲key的屬性對應的值 |
系統中常見的屬性名以及屬性的作用:
屬性名 | 屬性說明 |
---|---|
java.version | java運行時環境版本 |
java.home | java安裝目錄 |
os.name | 操作系統的名稱 |
os.version | 操作系統的版本 |
user.name | 用戶的賬戶名稱 |
user.home | 用戶的主目錄 |
user.dir | 用戶的當前工作目錄 |
五.Math類
java.lang.Math 提供了一系列靜態方法用於科學計算。其方法的參數和返回值類型一般爲double 型。
方法 | 描述 |
---|---|
abs | 絕對值 |
sqrt | 平方根 |
pow(double a, double b) | a的b次冪 |
log | 自然對象 |
exp | e爲底指數 |
max(double a, double b) / min(double a, double b) | a和b的最大值/最小值 |
random() | 返回[0.0, 1.0)的隨機數 |
long round(double a) | double 型數據a轉換爲long型(四捨五入) |
toDegrees(double angrad) | 弧度—> 角度 |
toRadians(double angdeg) | 角度—> 弧度 |
六.BigInteger與BigDecimal
1.BigInteger類
java.math包的BigInteger 可以表示不可變的任意精度的整數。BigInteger 提供所有 Java 的基本整數操作符的對應物,並提供 java.lang.Math 的所有相關方法。
構造方法:
BigInteger(String val)
:根據字符串構建BigInteger對象
常用方法:
方法 | 描述 |
---|---|
BigInteger add(BigInteger val) | 返回其值爲 (this + val) 的 BigInteger |
BigInteger subtract(BigInteger val) | 返回其值爲 (this - val) 的 BigInteger |
BigInteger multiply(BigInteger val) | 返回其值爲 (this * val) 的 BigInteger |
BigInteger divide(BigInteger val) | 返回其值爲 (this / val) 的 BigInteger。整數相除只保留整數部分 |
BigInteger remainder(BigInteger val) | 返回其值爲 (this % val) 的 BigInteger |
BigInteger[] divideAndRemainder(BigInteger val) | 返回包含 (this / val) 後跟(this % val) 的兩個 BigInteger 的數組 |
2.BigDecimal類
一般的Float類和Double類可以用來做科學計算或工程計算,但在商業計算中,要求數字精度比較高,故用到java.math.BigDecimal 類 。BigDecimal對象是不可變的。
BigDecimal類支持不可變的、任意精度的有符號十進制定點數。
常用構造方法:
public BigDecimal(double val)
:根據double構建BigDecimal對象(有精確度缺失)public BigDecimal(String val)
:根據字符串構建BigDecimal對象(建議採用)
常用方法:
方法 | 描述 |
---|---|
public BigDecimal add(BigDecimal augend) | 加 |
public BigDecimal subtract(BigDecimal subtrahend) | 減 |
public BigDecimal multiply(BigDecimal multiplicand) | 乘 |
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) | 除 |
public String toString() | 數值轉換成字符串 |
public double doubleValue() | 以雙精度數返回 |
public BigDecimal setScale(int newScale, int roundingMode) | 格式化小數點 |
注意:
-
setScale(int newScale, int roundingMode)
由於BigDecimal對象是不可變的,所以此方法的調用不會導致原始對象被修改。
setScale
返回具有適當比例的對象; 返回的對象可能會被新分配( 值發生改變),也可能不會被新分配( 值沒有發生改變:如13.16格式化2位小數)。 -
BigDecimal(String val)構造是靠譜的,BigDecimal(“57.3”)就是妥妥的等於57.3,建議採用這種方式;
BigDecimal(double val)等構造不太靠譜,在精確度上有缺失。
float a = 57.3f; BigDecimal decimalA = new BigDecimal(a); System.out.println(decimalA); // 57.299999237060546875 double b = 57.3; BigDecimal decimalB = new BigDecimal(b); System.out.println(decimalB); // 57.2999999999999971578290569595992565155029296875 double c = 57.3; BigDecimal decimalC = new BigDecimal(Double.toString(c)); System.out.println(decimalC); // 57.3 double d = 57.3; BigDecimal decimalD = BigDecimal.valueOf(d); System.out.println(decimalD); // 57.3
示例:
BigDecimal bd = new BigDecimal("12435.351");
BigDecimal bd2 = new BigDecimal("11");
// System.out.println(bd.divide(bd2)); // 當不能整除時,必須給出小數位精確位,不然會報異常
// ROUND_HALF_UP:表示四捨五入模式
System.out.println(bd.divide(bd2, BigDecimal.ROUND_HALF_UP)); // 1130.486
System.out.println(bd.divide(bd2, 12, BigDecimal.ROUND_HALF_UP)); // 1130.486454545455
// 四捨五入
BigDecimal b = new BigDecimal("111231.5585");
// 調用setScale方法格式化小數點
double result = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
System.out.println(result); //111231.56
// 保留兩位小數
double num = 13.154256
//方式一
DecimalFormat df1 = new DecimalFormat("0.00");
String str = df1.format(num);
System.out.println(str); //13.15
//方式二
// #.00 表示兩位小數 #.0000四位小數
DecimalFormat df2 =new DecimalFormat("#.00");
String str2 =df2.format(num);
System.out.println(str2); //13.15
//方式三
//%.2f %.:表示小數點前任意位數; 2:表示兩位小數格式後的結果 f:表示浮點型
String result = String.format("%.2f", num);
System.out.println(result); //13.15