第3章 - Java 數組 和 字符串
作者:vwFisher
時間:2019-09-04
GitHub代碼:https://github.com/vwFisher/JavaBasicGuide
目錄
1 數組
(basic.array.ArrayDemo)
概念: 同一種數據類型的數據集合, 其實數組就是一個容器
好處: 可以自動給數組中的元素從0開始編號, 方便操作這些元素
說明: 數組作為對象允許使用new關鍵字進行內存分配, 在使用數組之前, 必須首先聲明數組變量所屬的類型
1.1 一維數組
概念: 一組相同類型數據的集合
語法:
1).數組元素類型 數組名字[] = new 數組元素類型[數組元素個數]
2).數組元素類型[] 數組名字 = new 數組元素類型[數組元素個數]
3).數組元素類型[] 數組名 = new 元素類型[]{元素, 元素, ...};
4).數組元素類型[] 數組名 = {元素, 元素, ...};
int arr[] = new int[5];
int[] arr = new int[5];
// 定義并初始化
int[] arr = new int[]{3, 5, 1, 7};
int[] arr = {3, 5, 1, 7};
說明:
- 數組元素類型: 決定數組的數據類型(Java任意數據類型)
- 數組名字: 合法的標識符
- 符號"[]": 指明該變量是一個數組類型變量, 單個"[]"表示要創建的數組是一維數組
- new: 對數組分配空間的關鍵字(因為數組是作為對象允許使用new關鍵字進行內存分配的, 使用new關鍵字時候, 整數類型默認初始化值為0)
- 數組元素的個數: 指定數組中變量的個數, 即數組的長度
一維數組運行內存例子
(basic.demo08.MemoryDiagram1)
public static void main(String[] args) {
int[] arr = new int[3];
arr[0] = 89;
int[] arr2 = arr;
System.out.println(arr[0]);
arr = null;
}
圖示說明:
- 主方法main先壓棧
- int[] arr: arr壓棧
- new int[3]: 放在堆里, 通過new關鍵字在堆中開辟空間, 內存在存儲數據的時候會開辟內存地址(例: 0x0045(16進制)的地址空間, 數組有腳標, 劃分3個格子, 每個格子有對應的下標標號, 并默認初始化設置為0)
- 然后對應arr地址就是0x0045, arr就指向該地址的對象數組(這種就叫做引用數據類型(C就叫指針))
- 修改arr指向地址中的下標0的值為89
- 此處不難理解, 當定義int[] arr2 = arr, 實際上就是將arr的指向地址賦給arr2
- 找到arr指向地址中的下標0的值顯示
- 當想取消arr的指向, 賦值arr=null
- arr=null之后, Java自動回收機制會不定時的回收垃圾數據
1.2 二維數組(多維數組同理)
概念: 如果一維數組中的各個元素仍然是一維數組, 那么它就是一個二維數組, 常用于表, 第一個下標代表行, 第二個下標代表列
語法:
1).int arr[][] = new int[2][4];
int[][] arr = new int[2][4];
{1}.定義了名稱為arr的二維數組
{2}.二維數組中有2個一維數組
{3}.每一個一維數組中有4個元素
{4}.一維數組的名稱分別為arr[0], arr[1]
{5}.給第一個一維數組1腳標位賦值位78寫法是: arr[0][1] = 78
2).int arr[][] = new int[2][];
int[][] arr = new int[2][];
{1}.二維數組中有3個一維數組
{2}.每個一維數組都是默認初始化值null
{3}.可以對這個三個一維數組分別進行初始化
arr[0] = new int[2]; arr[1] = new int[3];
3).int[][] arr = {{3, 1, 7}, {5, 8, 2, 9}, {4, 1}}
二維數組運行內存例子
(basic.array.MemoryDiagram2)
public static void main(String[] args) {
int[][] arr = new int[3][2];
arr[1][1] = 89;
arr[2][2] = 89; // error
// 分別對二維數組中的每一個小數組進行初始化
int[][] arr2 = new int[3][];
arr2[0] = new int[2];
arr2[1] = new int[1];
arr2[2] = new int[3];
}
圖示說明:
- 主方法main先壓棧
- int[][] arr: arr壓棧
- new int[3][2]:進堆, 通過new關鍵字在堆中開辟空間, 如圖, 創建地址0x0034指向賦給arr, 然后因為二維數組中就是小地址, 再開辟3個地址, 對應就是小數組的地址
- arr[1][1]=89, 就是先找0x0034, 在找到下標1, 即地址0x0089的下標1賦值88
- arr[2][2]=89, 找到0x0034, 在找0x0012, 但是不存在下標2的對應位置, 所以這段代碼報錯
1.3 數組-常見操作(詳細見程序的demo)
(basic.array.ArrayDemo)
嘗試自己實現功能:遍歷數組,獲取數組最大/小值,基本下標查找
1.3.3 選擇排序(SelectSort)
每一趟從待排序的數據元素中選出最小(或最大)的一個元素, 順序放在已排好序的數列的最后, 直到全部待排序的數據元素排完。
選擇排序是不穩定的排序方法, n個記錄的文件的直接選擇排序可經過n-1趟直接選擇排序得到有序結果
1.3.4 冒泡排序(BubbleSort)
冒泡排序是交換排序中一種簡單的排序方法. 它的基本思想是對所有相鄰記錄的關鍵字值進行比效, 如果是逆順(a[j]>a[j+1]), 則將其交換, 最終達到有序化. 其處理過程為:
- 將整個待排序的記錄序列劃分成有序區和無序區, 初始狀態有序區為空, 無序區包括所有待排序記錄
- 對無序區從前向后依次將相鄰記錄的關鍵字進行比較, 若逆序將其交換, 從而使得關鍵字值小的記錄向上"飄浮"(左移), 關鍵字值大的記錄好像石塊, 向下"墮落"(右移)
每經過一趟冒泡排序, 都使無序區中關鍵字值最大的記錄進入有序區, 對于n個記錄組成的記錄序列, 最多經過n-1趟冒泡排序, 就可以將這n個記錄重新按關鍵字順序排列
【注: 想象輕(小)的浮在上面(左), 重(大)的落在下面(右)】
1.3.6 折半查找(二分查找 HalfSearch)
優點: 比較次數少, 查找速度快, 平均性能好
缺點: 要求待查表為有序表, 且插入刪除困難
場景: 不經常變動而查找頻繁的有序列表
折半查找法也稱為二分查找法, 它充分利用了元素間的次序關系, 采用分治策略, 可在最壞的情況下用O(log n)完成搜索任務.
它的基本思想是, 將n個元素分成個數大致相同的兩半, 取a[n/2]與欲查找的x作比較, 如果x=a[n/2]則找到x, 算法終止. 如果x<a[n/2], 則我們只要在數組a的左半部繼續搜索x(這里假設數組元素呈升序排列). 如果x>a[n/2], 則我們只要在數組a的右半部繼續搜索x
1.4 byte數組的一些使用
1.4.1 byte數組的編解碼
(basic.array.EncodeDemo)
private static String ENCODING_GBK = "GBK";
private static String ENCODING_UTF8 = "UTF-8";
public static void main(String[] args) throws IOException {
String str = "謝謝";
byte[] encodeGbkByte = encodeDemo(str, ENCODING_GBK);
printBytes(encodeGbkByte);
String decodeUtf8 = decodeDemo(encodeGbkByte, ENCODING_UTF8);
System.out.println(decodeUtf8);
byte[] encodeUtf8Byte = encodeDemo(decodeUtf8, ENCODING_UTF8);
printBytes(encodeUtf8Byte);
String decodeGbk = decodeDemo(encodeUtf8Byte, ENCODING_GBK);
System.out.println(decodeGbk);
}
private static byte[] encodeDemo(String str, String charset) {
try {
return str.getBytes(charset);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
private static String decodeDemo(byte[] byteArray, String charset) {
try {
return new String(byteArray, charset);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
private static void printBytes(byte[] buf) {
for (byte b : buf) {
System.out.print(b + " ");
}
System.out.println();
}
1.5 Arrays(數組工具類)
(basic.demo08.ArraysDemo)
此類包含用來操作數組(比如排序和搜索)的各種方法. 還包含一個允許將數組作為列表來查看的靜態工廠.
除非特別注明, 否則如果指定數組引用為 null, 則此類中的方法都會拋出 NullPointerException.
Arrays常用工具類方法歸類:大部分方法都含有基礎數據的參數,以下省略說明:
- typeAll:byte、short、int、long、float、double、char、Object
- typeBasic:byte、short、int、long、float、double、char
1).排序
void sort(typeAll[] a) // 對指定Object型數組按升序排序
void sort(Object[] a, int fromIndex, int toIndex) // 指定范圍排序
<T> void sort(T[] a, Comparator<? super T> c) // 指定比較器順序排序
<T> void sort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c)
void parallelSort(typeBasic[] a) // 并行排序
void parallelSort(typeBasic[] a, int fromIndex, int toIndex)
<T extends Comparable<? super T>> void parallelSort(T[] a)
<T extends Comparable<? super T>> void parallelSort(T[] a, int fromIndex, int toIndex)
<T> void parallelSort(T[] a, Comparator<? super T> cmp) // 指定比較器順序并行排序
<T> void parallelSort(T[] a, int fromIndex, int toIndex, Comparator<? super T> cmp)
2).搜索
int binarySearch(typeAll[] a, typeAll key) // 使用二分搜索法來搜索指定的下標值
int binarySearch(typeAll[] a, int fromIndex, int toIndex, typeAll key)
<T> int binarySearch(T[] a, T key, Comparator<? super T> c)
<T> int binarySearch(T[] a, int fromIndex, int toIndex, T key, Comparator<? super T> c)
3).比較
boolean equals(typeAll[] a, typeAll [] a2) // 如果兩個指定的數組彼此相等,則返回 true
4).賦值
void fill(typeAll[] a, typeAll val) // 將指定的值賦值給數組所有元素
void fill(typeAll[] a, int fromIndex, int toIndex, typeAll val)
5).復制
<T> T[] copyOf(T[] original, int newLength) 復制指定的數組, 截取或用null填充(如有必要), 以使副本具有指定的長度
<T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) 復制指定的數組, 截取或用null填充(如有必要), 以使副本具有指定的長度
<T> T[] copyOfRange(T[] original, int from, int to) 將指定數組的指定范圍復制到一個新數組
<T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType)
typeBasic[] copyOf(typeBasic[] original, int newLength) // 復制指定的數組, 截取或用0[注:boolean用false, char用null, 其余用0]填充(如有必要), 以使副本具有指定的長度
typeBasic[] copyOf(typeBasic[] original, int from, int to)
6).Array -> List
<T> List<T> asList(T... a) // 返回一個受指定數組支持的固定大小的列表
7).獲取
int hashCode(typeAll[] a) // 基于指定數組的內容返回哈希碼
int deepHashCode(Object a[]) // 基于指定數組的"深層內容"返回哈希碼
boolean deepEquals(Object[] a1, Object[] a2) // 如果兩個指定數組彼此是深層相等的, 則返回true
String toString(typeAll[] a) // 返回指定數組內容的字符串表示形式
String deepToString(Object[] a) 返回指定數組"深層內容"的字符串表示形式
8).其他
<T> void legacyMergeSort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c)
<T> void parallelPrefix(T[] array, BinaryOperator<T> op)
<T> void parallelPrefix(T[] array, int fromIndex, int toIndex, BinaryOperator<T> op)
void parallelPrefix(long[] array, LongBinaryOperator op)
void parallelPrefix(long[] array, int fromIndex, int toIndex, LongBinaryOperator op)
void parallelPrefix(double[] array, DoubleBinaryOperator op)
void parallelPrefix(double[] array, int fromIndex, int toIndex, DoubleBinaryOperator op)
void parallelPrefix(int[] array, IntBinaryOperator op)
void parallelPrefix(int[] array, int fromIndex, int toIndex, IntBinaryOperator op)
<T> void setAll(T[] array, IntFunction<? extends T> generator)
<T> void parallelSetAll(T[] array, IntFunction<? extends T> generator)
void setAll(int[] array, IntUnaryOperator generator)
void parallelSetAll(long[] array, IntToLongFunction generator)
void setAll(double[] array, IntToDoubleFunction generator)
void parallelSetAll(double[] array, IntToDoubleFunction generator)
<T> Spliterator<T> spliterator(T[] array)
<T> Spliterator<T> spliterator(T[] array, int startInclusive, int endExclusive)
Spliterator.OfInt spliterator(int[] array)
Spliterator.OfInt spliterator(int[] array, int startInclusive, int endExclusive)
Spliterator.OfLong spliterator(long[] array)
Spliterator.OfLong spliterator(long[] array, int startInclusive, int endExclusive)
Spliterator.OfDouble spliterator(double[] array)
Spliterator.OfDouble spliterator(double[] array, int startInclusive, int endExclusive)
<T> Stream<T> stream(T[] array)
<T> Stream<T> stream(T[] array, int startInclusive, int endExclusive)
IntStream stream(int[] array)
IntStream stream(int[] array, int startInclusive, int endExclusive)
LongStream stream(long[] array)
LongStream stream(long[] array, int startInclusive, int endExclusive)
DoubleStream stream(double[] array)
DoubleStream stream(double[] array, int startInclusive, int endExclusive)
2 字符串
2.1 String類
String類即字符串類型(不可變類), 并不是Java的基本數據類型, 但可以像基本數據類型一樣使用, 用雙引號括起來進行聲明. 在Java中用String類的構造方法來創建字符串變量
特點:
- 字符串是一個特殊的對象
- 字符串對象一旦被初始化就不會被改變, 查看源碼可以看到定義:
public final class String
- 不可變原因,在 String 類中使用 final 關鍵字修飾字符數組來保存字符串:
private final char value[]
2.2 String的方法
(basic.str.StringDemo, StringMethod)
底層實現: char value[]; 用類型是char的數組來存儲數據
String主要方法如下:
1).構造函數
public String() // 初始化一個新創建的String對象, 默認為:""
public String(String original)
public String(char value[])
public String(char value[], int offset, int count)
public String(int[] codePoints, int offset, int count)
public String(byte bytes[], String charsetName) 使用指定的charset解碼指定的byte數組
public String(byte bytes[], int offset, int length, String charsetName)
public String(byte bytes[], int offset, int length, Charset charset)
public String(byte bytes[], Charset charset)
public String(byte bytes[], int offset, int length)
public String(byte bytes[])
public String(StringBuffer buffer)
public String(StringBuilder builder)
過時的構造函數:該方法無法將字節正確地轉換為字符.從JDK1.1開始, 完成該轉換的首選方法是使用帶有Charset、字符集名稱, 或使用平臺默認字符集的String構造方法
public String(byte ascii[], int hibyte, int offset, int count)
public String(byte ascii[], int hibyte)
2).判斷
boolean isEmpty() // 當且僅當length()為 0 時返回true
boolean startsWith(String prefix) // 測試此字符串是否以指定的前綴開始
boolean startsWith(String prefix, int toffset) // 同上,區別:從指定索引開始的字符串
boolean endsWith(String suffix) // 測試此字符串是否以指定的后綴結束
boolean matches(String regex) // 測試此字符串是否匹配給定的正則表達式
boolean contains(CharSequence s) // 當且僅當此字符串包含指定的 char 值序列時,返回 true
3).比較
int compareTo(String anotherString) // 按字典順序比較兩個字符串。如:"abc".compareTo("acz") 結果為-1, b與c比,為-1
int compareToIgnoreCase(String str) // 按字典順序比較兩個字符串, 不考慮大小寫
boolean equals(Object anObject) // 將此字符串與指定的對象比較(內容)
boolean equalsIgnoreCase(String anotherString) // 忽略大小寫比較
boolean contentEquals(StringBuffer sb) // 將此字符串與指定的StringBuffer比較
boolean contentEquals(CharSequence cs) // 將此字符串與指定的CharSequence比較
boolean regionMatches(int toffset, String other, int ooffset, int len) // 測試兩個字符串區域是否相等
boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) // 測試兩個字符串區域是否相等
4).獲取
int length() 返回此字符串的長度
char charAt(int index) 返回指定索引處的char值
int codePointAt(int index) 返回指定索引處的字符(Unicode代碼點)
int codePointBefore(int index) 返回指定索引之前的字符(Unicode代碼點)
int codePointCount(int beginIndex, int endIndex) 返回此String的指定文本范圍中的Unicode代碼點數
int offsetByCodePoints(int index, int codePointOffset) 返回此String中從給定的index處偏移codePointOffset個代碼點的索引
void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) 將字符從此字符串復制到目標字符數組
void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) 已過時, 該方法無法將字符正確轉換為字節. 從JDK 1.1起, 完成該轉換的首選方法是通過getBytes()方法, 該方法使用平臺的默認字符集
byte[] getBytes(String charsetName) 使用指定的字符集將此 String 編碼為 byte 序列,并將結果存儲到一個新的 byte 數組中
byte[] getBytes(Charset charset) 使用給定的 charset 將此 String 編碼到 byte 序列, 并將結果存儲到新的 byte 數組
byte[] getBytes() 使用平臺的默認字符集將此 String 編碼為 byte 序列, 并將結果存儲到一個新的 byte 數組中
int hashCode() // 返回此字符串的哈希碼
int indexOf(int ch) // 返回指定字符在此字符串中第一次出現處的索引
int indexOf(int ch, int fromIndex) // 從指定的索引開始搜索
int indexOf(String str)
int indexOf(String str, int fromIndex)
int lastIndexOf(int ch) 返回指定字符在此字符串中最后一次出現處的索引
int lastIndexOf(int ch, int fromIndex)
int lastIndexOf(String str)
int lastIndexOf(String str, int fromIndex)
String substring(int beginIndex) 返回一個新的字符串, 它是此字符串的一個子字符串
String substring(int beginIndex, int endIndex) 返回一個新字符串, 它是此字符串的一個子字符串
CharSequence subSequence(int beginIndex, int endIndex) 返回一個新的字符序列, 它是此序列的一個子序列
String concat(String str) 將指定字符串連接到此字符串的結尾
String replace(char oldChar, char newChar) 返回一個新的字符串, 它是通過用 newChar 替換此字符串中出現的所有 oldChar 得到的
String replaceFirst(String regex, String replacement) 使用給定的 replacement 替換此字符串匹配給定的正則表達式的第一個子字符串
String replaceAll(String regex, String replacement) 使用給定的 replacement 替換此字符串所有匹配給定的正則表達式的子字符串
String replace(CharSequence target, CharSequence replacement) 使用指定的字面值替換序列替換此字符串所有匹配字面值目標序列的子字符串
String[] split(String regex, int limit) 根據匹配給定的正則表達式來拆分此字符串
String[] split(String regex) 根據給定正則表達式的匹配拆分此字符串
String toLowerCase(Locale locale) 使用給定 Locale 的規則將此 String 中的所有字符都轉換為小寫
String toLowerCase() // 使用默認語言環境的規則將此 String 中的所有字符都轉換為小寫
String toUpperCase(Locale locale) // 使用給定Locale的規則將所有字符都轉換為大寫
String toUpperCase() // 使用默認語言環境的規則將此 String 中的所有字符都轉換為大寫
String trim() 返回字符串的副本,忽略前導空白和尾部空白
String toString() 返回此對象本身(它已經是一個字符串!)
char[] toCharArray() 將此字符串轉換為一個新的字符數組
native String intern() 返回字符串對象的規范化表示形式
5).靜態方法
static String format(String format, Object... args) 使用指定的格式字符串和參數返回一個格式化字符串
static String format(Locale l, String format, Object... args) 使用指定的語言環境、格式字符串和參數返回一個格式化字符串
static String valueOf(boolean/char/int/long/float/double b) // 返回指定類型參數的字符串表示形式
static String valueOf(Object obj) 返回 Object 參數的字符串表示形式
static String valueOf(char data[]) 返回 char 數組參數的字符串表示形式
static String valueOf(char data[], int offset, int count) // 返回 char 數組參數的特定子數組的字符串表示形式
static String copyValueOf(char data[], int offset, int count) // 返回指定數組中表示該字符序列的 String
static String copyValueOf(char data[]) 返回指定數組中表示該字符序列的 String
static String join(CharSequence delimiter, CharSequence... elements)
static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements)
2.2.1 字符串連接說明
連接多個字符串, 兩個連接的字符串之間用 +
(連接符) 相連, 連接之后生成一個新的字符串。
Java中的字符串不能分開兩行中寫, 如果一個字符串太長, 需要將這個字符串分在兩行上書寫, 此時可以使用"+"將兩個字符串連起來, 并在加號處換行
在字符串和其他數據類型連接時, 同樣使用 +
連接符, 連接之后的返回值是字符串。只要用 +
連接其中一個操作類型是字符串,那么編譯器就會將另外的操作類型轉換成字符串形式, 所以應謹慎地將其他數據類型與字符串相連
2.2.2 String類intern方法
(basic.str.StringDemo)
如果池中包含一個等于此String對象的字符串, 則返回池中的字符串, 否則將此String對象添加到池中, 并返回此String對象的引用
/**
* public String intern()返回字符串對象的規范化表示形式。
* 如果池中包含一個等于此String對象的字符串,則返回池中的字符串
* 否則將此String對象添加到池中,并返回此String對象的引用
*/
public static void main(String[] args) {
String s0 = "kvill";
String s1 = new String("kvill");
String s2 = new String("kvill");
System.out.println(s0 == s1); //false
s1.intern();
s2 = s2.intern();
System.out.println(s0 == s1); //false
System.out.println(s0 == s1.intern()); //true
System.out.println(s0 == s2); //true
}
2.3 格式化字符串
(示例: basic.str.format.DataFormat, TimeFormat, DateAndTimeFormat, GeneralFormat, SystemOutPrintf)
格式化字符串: 主要包括日期格式化、時間格式化、日期/時間組合的格式化和常規類型格式化
2.3.1 格式化方法
語法:
format(String format, Object... args)
format(Locale locale, String format, Object... args)
- locale:格式化過程要應用的語言環境, 如果l位null, 則不進行本地化
- format: 格式化轉換符
- args: 格式化字符串格式說明符引用的參數, 如果還有格式說明符以外的參數, 則忽略這些額外的參數
- 返回值: 一個格式化的字符串
2.3.2 日期格式化
常見的日期格式化轉換符
轉換符 | 說明 | 示例 |
---|---|---|
%te | 一個月中的某一天 | 6 |
%tb | 指定語言環境的月份簡稱 | Feb(英文), 二月(中文) |
%tB | 指定語言環境的月份全稱 | February(英), 二月(中) |
%ta | 指定語言環境的星期幾簡稱 | Mon(英), 星期一(中) |
%tA | 指定語言環境的星期幾全稱 | Monday(英), 星期一(中) |
%tc | 包括全部日期和時間信息 | 星期二 三月 25 13:37:22 CST 2008 |
%tY | 4位年份 | 2008 |
%ty | 2位年份 | 08 |
%tm | 月份 | 03 |
%td | 一個月中的第幾天(0~31) | 02 |
%tj | 一年中的第幾天(001~366) | 085 |
2.3.3 時間格式化
常見的時間格式化轉換符
轉換符 | 說明 | 示例 |
---|---|---|
%tH | 2位數字的24時制小時(00~23 | 14 |
%tI | 2位數字的12時制小時(01~12) | 05 |
%tk | 2位數字的24時制小時(0~23) | 5 |
%tl | 2位數字的12時制小時(1~12) | 10 |
%tM | 2位數字的分鐘(00~59) | 05 |
%tS | 2位數字的秒數(00~60) | 12 |
%tL | 3位數字的毫秒數(000~999) | 920 |
%tN | 9位數字的微秒數(000000000~999999999) | 062000000 |
%tp | 指定語言環境下上午或下午標記 | 下午(中), pm(英) |
%tz | 相對于GMT RFC82格式的數字時區偏移量 | +0800 |
%tZ | 時區縮寫形式的字符串 | CST |
%ts | 1970-01-01 00:00:00至現在經過的秒數 | 1206426737 |
%tQ | 1970-01-01 00:00:00至現在經過的毫秒數 | 1206426737453 |
2.3.4 日期時間組合格式化
常見的時間格式化轉換符
轉換符 | 說明 | 示例 |
---|---|---|
%tF | "年-月-日"格式(4位年份) | 2008-03-25 |
%tD | "月/日/年"格式(2位年份) | 03/25/08 |
%tc | 全部日期和時間信息 | 星期二 三月 25 15:20:00 CST 2008 |
%tr | "時:分:秒 PM(AM)"格式(12時制) | 03:22:06 下午 |
%tT | "時:分:秒"格式(24時制) | 15:25:50 |
%tR | "時:分"格式(24時制) | 15:25 |
2.3.5 常規類型格式化
常見的類型格式化轉換符
轉換符 | 說明 | 示例 |
---|---|---|
%b, %B | 結果被格式化為布爾值 | true |
%h, %H | 結果被格式化為散列碼 | A05A5198 |
%s, %S | 結果被格式化為字符串類型 | "abcd" |
%c, %C | 結果被格式化為字符類型 | 'a' |
%d | 結果被格式化為十進制整數 | 40 |
%o | 結果被格式化為八進制整數 | 11 |
%x, %X | 結果被格式化為十六進制整數 | 4b1 |
%e | 結果被格式化為用計算機科學計數法表示的十進制數 | 1.700000e+01 |
%a | 結果被格式化為帶有效位數和指數的十六進制浮點值 | 0X1.C0000000000001P4 |
%n | 結果為特定平臺的行分隔符 | |
%% | 結果為字面值'%' | % |
%h, %H | 哈希值 | cd |
2.3.5 System.out.printf
printf格式控制的說明
轉換符 | 說明 |
---|---|
% | 表示格式說明的起始符號, 不可缺少 |
- | 有-表示左對齊輸出, 如省略表示右對齊輸出 |
0 | 有0表示指定空位置0, 如省略表示指定空位不填 |
m.n | m指域寬, 即對應的輸出項在輸出設備上所占的字符串 n指精度, 用于說明輸出的實型數的小數位數, 缺省n=6 |
<strong> d格式: 用來輸出十進制整數 </strong> | |
%d | 按整型數據的實際長度輸出 |
%md | m為指定的輸出字段的寬度, 如果數據位數小于m, 左端補空格, 若大于m, 按實際位數輸出, 如: printf("%5d\n", 123) |
%-md | -代表左對齊, 如果數據位數小于m, 右端補空格, 若大于m, 按實際位數輸出, 如: printf("%-5d\n", 123) |
%05d | 0代表有空位置顯示0 如: printf("%05d\n", 123) |
<strong> o格式: 用來輸出八進制整數 </strong> | |
%o | 按整型數據的實際長度輸出 |
%mo | m為指定的輸出字段的寬度, 如果數據位數小于m, 左端補空格, 若大于m, 按實際位數輸出, 如: printf("%5o\n", 123) |
%-mo | -代表左對齊, 如果數據位數小于m, 右端補空格, 若大于m, 按實際位數輸出, 如: printf("%-5o\n", 123) |
%05o | 0代表有空位置顯示0 如: printf("%05o\n", 123) |
<strong> x格式: 用來輸出十六進制整數 </strong> | |
%x | 按整型數據的實際長度輸出 |
%mx | m為指定的輸出字段的寬度, 如果數據位數小于m, 左端補空格, 若大于m, 按實際位數輸出, 如: printf("%5x\n", 123) |
%-mx | -代表左對齊, 如果數據位數小于m, 右端補空格, 若大于m, 按實際位數輸出, 如: printf("%-5x\n", 123) |
%05x | 0代表有空位置顯示0 如: printf("%05x\n", 123) |
<strong> c格式: 用來輸出字符 </strong> | |
%c | 輸出字符, 如: printf("%c\n", 97) |
<strong> f格式: 用來輸出浮點數 </strong> | |
%f | 按浮點數據的輸出, 小數默認精確到6位 |
%m.nf | m為指定的整數部分輸出位數,m沒啥影響 n為指定的小數部分的輸出位數, 四舍五入到精確的位數 |
%-m.nf | -代表左對齊 |
<strong> e格式: 用來輸出浮點數 </strong> | |
%e | 按浮點數據的輸出, 小數默認精確到6位 |
%m.ne | m為指定的整數部分輸出位數,m沒啥影響 n為指定的小數部分的輸出位數, 四舍五入到精確的位數 |
%-m.ne | -代表左對齊 |
<strong> s格式: 用來輸出浮點數 </strong> | |
%s | |
%ms | |
%-ms | |
%m.nf | n代表要輸出的長度, 從左到右 |
%-m.nf | |
<strong> g格式: 用來輸出浮點數 </strong> | |
%g | |
%mg | |
%-mg | |
%m.ng | n代表要輸出的長度, 從左到右 |
%-m.ng |
2.4 正則表達式
(basic.str.regex.RegexDemo, RegexCrawler)
2.4.1 判斷是否符合正則表達式的方法
為了檢查輸入的數據是否滿足某種格式, 從JDK1.4開始可以使用String類的matches()方法進行判斷
語法:boolean matches(String regex)
- regex: 指定的正則表達式
- 返回值: 返回boolean類型
該方法用于告知當前字符串是否匹配參數regex指定的正則表達式, 返回值是boolean類型, 如果當前字符串與正則表達式匹配, 則該方法返回true, 否則返回false
2.4.2 正則表達式的元字符
正則表達式是由一些含有特殊意義的字符組成的字符串, 這些含有特殊意義的字符串稱為元字符
元字符 正則表達式中的寫法 含義
. "." 代表任意一個字符
\d "\\d" 代表0~9的任何一個數字
\D "\\D" 代表任何一個非數字字符
\s "\\s" 代表空白字符, 如'\t','\n'
\S "\\S" 代表非空白字符
\w "\\w" 代表可用作標識符的字符, 但不包括"$"
\W "\\W" 代表不可用于標識符的字符
\p{Lower} \\p{Lower} 代表小寫字母{a~z}
\p{Upper} \\p{Upper} 代表小寫字母{A~Z}
\p{ASCII} \\p{ASCII} ASCII字符
\p{Aplha} \\p{Aplha} 字母字符
\p{Digit} \\p{Digit} 十進制數組,即[0~9]
\p{Alnum} \\p{Alnum} 數字或字母字符
\p{Punct} \\p{Punct} 標點符號: !#$%&'()*+,-./:;<=>?@[\]^_`{|}~
\p{Graph} \\p{Graph} 可見字符: [\p{Alnum}\p{Punct}]
\p{Print} \\p{Print} 可打印字符: [\p{Graph}\x20]
\p{Blank} \\p{Blank} 空格或制表符: [\t]
\p{Cntrl} \\p{Cntrl} 控制字符: [\x00~\x1F\x7F]
2.4.3 正則表達式的限定符
在使用正則表達式時, 如果需要某一個類型元字符多次輸出, 逐個輸入就相當麻煩, 這時可以使用正則表達式的限定元字符來重復次數
限定修飾符 意義 示例
? 0次或1次 A?
(.?) 非貪婪匹配 (.?)
* 0次或多次 A*
+ 1次或多次 A+
{n} 正好出現n次 A{2}
{n,} 至少出現n次 A{3,}
{n,m} 出現n~m次 A{2,6}
2.4.4 方括號中元字符的含義
字符 含義
[abc] 表示 a, b 或 c
[^abc] 表示 a, b, c 之外的任何字符
[a-zA-Z] a~z 或 A~Z 的任何字符
[a-d[m-p]] a~d 或 m~p 的任何字符
[a-z&&[def]] d, e 或 f
[a-z&&[^bc]] a~z 之間不含 b 和 c 的所有字符
[a-z&&[^m-p]] a~z 之間不含 m~p 的所有字符
正則表達式對字符串的常見操作:
- 匹配: 其實使用的就是String類中的matches方法.
- 切割: 其實使用的就是String類中的split方法. 組:((A)(B(C)))
- 替換: 其實使用的就是String類中的replaceAll()方法.
- 獲取: 案例: 網頁爬蟲
將正則規則進行對象的封裝
Pattern p = Pattern.compile("a*b");
// 通過正則對象的matcher方法字符串相關聯。獲取要對字符串操作的匹配器對象Matcher .
Matcher m = p.matcher("aaaaab");
// 通過Matcher匹配器對象的方法對字符串進行操作。
boolean b = m.matches();
String priceStr = "匹配字符串:滿 2999 元減 100 元";
Pattern pricePattern = Pattern.compile("[^0-9]+([0-9]+?)[^0-9]+([0-9]+?)[^0-9]+"); // 結果:group(1) = 2999,group(2) = 100
Matcher priceMatcher = pricePattern.matcher(priceStr);
if (priceMatcher.find()) {
System.out.println(priceMatcher.group(1));
System.out.println(priceMatcher.group(2));
}
2.5 StringBuffer 和 StringBuilder
(basic.str.StringBufferDemo, StringBuilderDemo)
StringBuilder 與 StringBuffer 都繼承自 AbstractStringBuilder 類
在 AbstractStringBuilder 中也是使用字符數組保存字符串 char[] value,但是沒有用 final 關鍵字修飾,所以這兩種對象都是可變的。
StringBuilder 與 StringBuffer 的構造方法都是調用父類構造方法也就是 AbstractStringBuilder 實現的,大家可以自行查閱源碼。
AbstractStringBuilder.java
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
StringBuffer 和 StringBuilder,常用于 。
特點:
- 長度的可變
- 可以存儲不同類型的數據
- 最終要轉成字符串進行使用
- 可以對字符串進行修改
- 一般作為 字符串緩沖區。存儲數據的容器,具備CRUD功能 C(create) U(update) R(read) D(delete)
1).添加
StringBuffer append(data);
StringBuffer append(StringBuffer sb)
StringBuffer insert(index, data);
2).刪除
StringBuffer delete(start, end); // 包含頭, 不包含尾
StringBuffer deleteCharAt(int index); // 刪除指定位置的元素
3).查找
char charAt(index);
int indexOf(string);
int lastIndexOf(string);
4).修改
StringBuffer replace(start, end, string);
void setCharAt(index, char);
5).其他
length(); // 獲取長度
setLength(int length); // 設置長度
reverse(); // 反轉顯示
toString(); // 字符串格式
StringBuilder 和 StringBuffer 的區別:
- StringBuffer是線程同步的. 通常用于多線程。(源碼中可以發現方法帶有synchronized關鍵字)
- StringBuilder是線程不同步的. 通常用于單線程. 它的出現提高效率.
- 在字符串緩存被單個線程使用時要比StringBuffer類快
線程安全性
String 中的對象是不可變的,也就可以理解為常量,線程安全。
AbstractStringBuilder 是 StringBuilder 與 StringBuffer 的公共父類,定義了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。
StringBuffer 對方法加了同步鎖或者對調用的方法加了同步鎖,所以是線程安全的。StringBuilder 并沒有對方法進行加同步鎖,所以是非線程安全的。
性能
- 每次對 String 類型進行改變的時候,都會生成一個新的 String 對象,然后將指針指向新的 String 對象。
- StringBuffer 每次都會對 StringBuffer 對象本身進行操作,而不是生成新的對象并改變對象引用。
- 相同情況下使用 StringBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的風險。
對于三者使用的總結:
- 操作少量的數據: 適用String
- 單線程操作字符串緩沖區下操作大量數據: 適用StringBuilder
- 多線程操作字符串緩沖區下操作大量數據: 適用StringBuffer