【Java 基礎】字符串(String、StringBuilder),日期(Date、SimpleDateFormat、Calendar)

Java筆記目錄可以點這裏:Java 強化筆記

字符串(String)

Java 中用 java.lang.String 代表字符串:

  • Java 9 以前,底層使用 char[] 存儲字符數據
    從 Java 9 開始,底層使用 byte[] 存儲字符數據
  • 所有字符串字面量(比如 "abc" )都是 String 類的實例
  • String 對象一旦創建完畢,它的字符內容不可以修改
    在這裏插入圖片描述

首先來看一段代碼:並思考一下這段代碼的輸出是否與你想的不一樣。

public class Main {
	public static void main(String[] args) {
		String s = "555";
		s += "555";
		s = "666";
		test(s);
		System.out.println(s); // 666
	}
	static void test(String str) {
		str += "555";
	}
}

String s = "555";s += "555";s = "666" 等操作都會在堆空間開闢一塊新的內存空間,因爲 String 是不可變字符串,每次要修改棧空間的變量sstr的值,只能改變它的指針指向,令指針指向堆空間新的內存。

我們知道,成員變量、函數形參等都是開闢在棧空間的(因爲隨時可能銷燬),而上面代碼中的 sstr 實際上在棧空間不是同一塊佈局,test 方法修改的是 str 的指向的值,所以 s 的值不會變。
在這裏插入圖片描述

字符串常量池(String Constant Pool)

Java 中有個字符串常量池(String Constant Pool,簡稱 SCP)

  • 從 Java 7 開始屬於堆空間的一部分(以前放在方法區)

當遇到字符串字面量時,會去查看 SCP

  • 如果 SCP 中存在與字面量內容一樣的字符串對象 A 時,就返回 A
  • 否則,創建一個新的字符串對象 D,並加入到 SCP 中,返回 D
String s1 = "mj"; // SCP中不存在字符串對象"mj"
String s2 = "mj"; // SCP中存在字符串對象"mj", 直接返回SCP中的"mj"
// 因此上面兩個字符串對象是同一個對象
System.out.println(s1 == s2); // true

在這裏插入圖片描述

字符串的初始化

在 C語言裏,字符數組就是字符串;在 Java 中,String 底層是由 char[] 組成的,但是他們不完全是一個東西。
在這裏插入圖片描述
利用 Java 的斷點調試功能來驗證上圖:右半部分中的表示不是真實的內存地址,但是可以理解爲標識不同則內存地址不同,相同則內存地址相同。可以看到 s1s2s3s4css5s6 的標識都是不同的;但是 s1s2s3s4 指向的value 的標識都是30,與上圖展示的一致;s5s6 指向的value 的標識都是31。

在這裏插入圖片描述

intern 方法

A.intern 方法的作用:

  • 如果 SCP 中存在與 A 內容一樣的字符串對象 C 時,就返回 C
  • 否則,將 A 加入到 SCP 中,返回 A
int a = 1, b = 2, c = 3;
String s1 = String.format("%d%d%d", a, b, c);
String s2 = String.format("%d%d%d", a, b, c);
// 去常量池中尋找"123", 發現沒有, 就將s1的值"123"放入常量池
String s3 = s1.intern(); // s3、s1都指向了常量池中的"123"
String s4 = s2.intern(); // 返回常量池的"123"
String s5 = "123"; // s5指向常量池中的"123"

System.out.println(s1 == s2); // false
System.out.println(s1 == s3); // true
System.out.println(s1 == s4); // true
System.out.println(s1 == s5); // true

字符串的常用方法(截取)

// 去除左右的空格: "123  456"
" 123  456  ".trim();

// 轉爲大寫字母: "ABC"
"abc".toUpperCase();
// 轉爲小寫字母: "abc"
"ABC".toLowerCase();

// 是否包含某個字符串: true
"123456".contains("34");
// 是否以某個字符串開頭: true
"123456".startsWith("123");
// 是否以某個字符串結尾: true
"123456".endsWith("456");

// 將字符串分隔爲數組: [1, 2, 3, 4]
"1_2_3_4".split("_");

// 比較字符串的大小: <
"abc".compareTo("adc");
// 忽略大小寫比較字符串的大小: <
"abc".compareTo("ADC");

String s1 = "abc";
String s2 = new String("abc");
// 查看字符串的內容是否相等: true
s1.equals(s2);
// 忽略大小寫查看字符串的內容是否相等: true
"abc".equalsIgnoreCase("ABC");

// 字符串的替換
String str = "hello123";
// 由於String是不可變字符串, 必須用變量接收
str = str.replace("123", "666"); // hello666

穿插個知識點,Eclipse 中 抽取代碼塊的快捷鍵:先選中代碼塊,ALT + SHIFT + M
在這裏插入圖片描述
字符串截取

String str = "abcdea";
// 字符串的截取區間: [2, 4)
str.substring(2, 4);  // cd
str.substring(2); 	  // cdea

str.indexOf("a"); 	  // 0
str.lastIndexOf("a"); // 5
str.indexOf("z"); 	// -1

在這裏插入圖片描述

可變字符串(StringBuilder)

在進行大量字符串的改動操作時(比如拼接、替換)

  • 使用 String 會非常消耗內存、降低程序性能
  • 使用 StringBuilder 可以節省內存、提高程序性能
String s1 = "";
s1 += "123";
s1 += "456";

StringBuilder s2 = new StringBuilder();
s2.append("123").append("456");

StringStringBuilder 性能對比:50000 次字符串拼接操作

public static void main(String[] args) {
	testString(); 	// 2511ms
	testStringBuilder(); // 2ms
}

static void testString() {
	long begin = System.currentTimeMillis();
	String str = "";
	for (int i = 0; i < 50000; i++) {
		str += i;
	}
	long end = System.currentTimeMillis();
	System.out.println("String ->" + (end - begin) + "ms");
}
static void testStringBuilder() {
	long begin = System.currentTimeMillis();
	StringBuilder str = new StringBuilder();
	for (int i = 0; i < 50000; i++) {
		str.append(i);
	}
	long end = System.currentTimeMillis();
	System.out.println("StringBuilder ->" + (end - begin) + "ms");
}
String -> 2511ms
StringBuilder -> 2ms

StringBuilder 的常用方法有:appendinsertdeletereplacereverse等;

注意:

  • StringBuilder 並不是 String 的子類 或者 父類
  • StringBuilderString 都實現了 CharSequence 接口

StringBuilder 的 append 原理

StringBuilder 的原理類似動態數組 ArrayList:底層會自動擴容;
在這裏插入圖片描述
源碼中可以看到擴容的算法:(value.length << 1) + 2 即 新容量是原來容量的 2 倍 + 2
在這裏插入圖片描述

日期

Date

java.util.Date 是開發中經常用到的日期處理類(注意:不是 java.sql.Date

  • 包含了年、月、日、時、分、秒等信息
// date1 代表當前時間
Date date1 = new Date();
// System.currentTimeMillis 表示 1970-01-01 00:00:00 GMT 到現在時間的毫秒數
// date2 也代表當前時間
Date date2 = new Date(System.currentTimeMillis());
// date3 代表 1970-01-01 00:00:00 GMT 
Date date3 = new Date(0);

// Mon Apr 20 13:44:49 CST 2020
System.out.println(date1);
// Mon Apr 20 13:44:49 CST 2020
System.out.println(date2);
// Thu Jan 01 08:00:00 CST 1970
System.out.println(date3);

System.currentTimeMillis 返回的是從 1970-01-01 00:00:00 GMT 開始到現在經歷的毫秒數

  • 1970-01-01 00:00:00 GMT、1970-01-01 08:00:00 CST 代表的是同一個時間
    • GMT(Greenwich Mean Time):格林尼治時間
    • CST(China Standard Time UT+8:00):中國標準時間

Date 常用方法:

Date d1 = new Date();
Date d2 = new Date();

// 設置毫秒數, d1比d2早(d2經歷的時間比d1大)
d1.setTime(1000);
d2.setTime(2000);

// 獲取毫秒數
d1.getTime(); // 1000
d2.getTime(); // 2000

// 比較時間
d2.after(d1);  // true
d1.before(d2); // true
d1.compareTo(d2); // -1(d2經歷的時間比d1大)

SimpleDateFormat

java.text.SimpleDateFormat 常用來進行日期的格式化處理

SimpleDateFormat fmt = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
// 利用日期對象生成字符串
String str = fmt.format(new Date());
// 2020年04月20日 13:57:13
System.out.println(str); 

// 解析字符串爲日期對象
Date date = fmt.parse(str);
// Mon Apr 20 13:57:13 CST 2020
System.out.println(date);

SimpleDateFormat 的模式字母:
在這裏插入圖片描述

Calendar

java.util.Calendar 也是開發中經常用到的日期處理類

  • 功能比 Date 更加豐富,Date 中很多過期的方法都遷移到了 Calendar

示例:目前是 2020年4月20日 星期一 下午 14:16:33

// 表示當前時間
Calendar c = Calendar.getInstance();
c.getTime(); // Mon Apr 20 14:16:33 CST 2020

c.get(Calendar.YEAR); // 年: 2020

// 月(取值範圍[0, 11], 0是1月, 11是12月)
c.get(Calendar.MONTH); // 3

// 一月中的第幾天(取值範圍[1, 31])
c.get(Calendar.DAY_OF_MONTH); // 20

// 一週中的第幾天(取值範圍[1, 7], 1是星期天, 2是星期一...,7是星期六)
c.get(Calendar.DAY_OF_WEEK); // 2

// 一年中的第幾天(取值範圍[1, 366])
c.get(Calendar.DAY_OF_YEAR); // 111

c.get(Calendar.HOUR);   // 時: 2
c.get(Calendar.MINUTE); // 分: 16
c.get(Calendar.SECOND); // 秒: 33
c.get(Calendar.MILLISECOND); // 毫秒: 330

Calendar 的常用方法:

Calendar c = Calendar.getInstance();
// 設置時間爲 2019年7月6日
c.set(2019, 06, 06);
// 2019年7月11日
c.add(Calendar.DAY_OF_MONTH, 5);
// 2019年9月11日
c.add(Calendar.MONTH, 2);

// 設置Date對象
c.setTime(new Date());
// 獲得Date對象
c.getTime();

// 設置毫秒數
c.setTimeInMillis(System.currentTimeMillis());
// 獲得毫秒數
c.getTimeInMillis();

打印格式化(很少用)

在這裏插入圖片描述

// 獲取當前時間
Calendar c = Calendar.getInstance();
Date date = new Date();

System.out.format("%tB %te, %tY%n", date, date, date); // 四月 20, 2020
System.out.format("%tl:%tM %tp%n", c, c, c); // 2:24 下午
System.out.format("%tD%n", c); // 04/20/20
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章