常用API(一)——String、StringBuffer與基本型別包裝類
String
關於String這個特殊類,我到現在都還沒搞明白,我覺得可能主要是由於沒有搞懂JVM的記憶體結構引起的,但還是對其進行以下記錄。
- 字串是一個特殊的物件。
字串一旦初始化就不可以被改變。
String str = "abcd";
以上這句程式碼的意思就是——JVM一啟動,字串就已經開始儲存了,儲存在了方法區中的常量池當中。
這裡還有一個說爛了的面試題:對於以下程式碼
String str = "abcd"; // str是一個類型別變數,"abcd"是一個物件
String str1 = new String("abcd");
str和str1有什麼區別?
答:str在記憶體中只有一個物件,str1在記憶體中有兩個物件。
下面我們再來看以下程式碼會輸出什麼?
System.out.println(str == str1);
System.out.println(str.equals(str1));
會發現第一句輸出false
,第二句輸出true
,得出結論:String類複寫了Object類中的equals(),該方法用於判斷字串的內容是否相同。
String類的常用方法
String類是用於描述字串事物的,那麼它就提供了多個方法對字串進行操作。常見的操作有哪些呢?
獲取
- 字串中包含的字元數,也就是字串的長度
int length();----獲取長度
- 根據位置獲取位置上某個字元
char charAt(int index);
- 根據字元獲取該字元在字串中的位置
int indexOf(int ch);
返回的是ch在字串中第一次出現的位置
int indexOf(int ch, int fromIndex);
從fromIndex指定位置開始,獲取ch在字串中出現的位置int indexOf(String str);
返回的是str在字串中第一次出現的位置int indexOf(String str, int fromIndex);
從fromIndex指定位置開始,獲取str在字串中出現的位置int lastIndexOf(int ch);
反向索引一個字元出現的位置
例,
public static void
- 字串中包含的字元數,也就是字串的長度
判斷
- 字串中是否包含某一個子串
boolean contains(str);
- 特殊之處:
indexOf(str)
:可以索引str第一次出現的位置,如果返回-1,表示該str不在字串中存在,所以,也可以用於對指定字串判斷是否包含,而且該方法既可以判斷,又可以獲取出現的位置。
- 字串是否有內容
boolean isEmpty();
原理就是判斷長度是否為0
- 字串是否是以指定內容開頭
boolean startsWith(str);
- 字串是否是以指定內容結尾
boolean endsWith(str);
- 判斷字串的內容是否相同,複寫了Object類中的equals()
boolean equals(str);
- 判斷內容是否相同,並忽略大小寫
boolean equalsIgnoreCase(str);
例,
public static void sop(Object obj) { System.out.println(obj); } public static void method_is() { String str = "ArrayDemo.java"; // 判斷檔名稱是否是以Array單詞開頭 sop(str.startsWith("Array")); // 判斷檔名稱是否是.java檔案 sop(str.endsWith(".java")); // 判斷檔名稱是否包含Demo sop(str.contains("Demo")); }
- 字串中是否包含某一個子串
轉換
- 將字元陣列轉成字串
- 建構函式:
String(char[])
String(char[], offset, count);
將字元陣列中的一部分轉成字串 ,count是個數 - 靜態方法:
static String copyValueOf(char[]);
static String copyValueOf(char[] data, int offset, int count);
static String valueOf(char[]);
- 建構函式:
- 將字串轉成字元陣列
char[] toCharArray();
- 將位元組陣列轉成字串
String(byte[]);
String(byte[], offset, count);
將位元組陣列中的一部分轉成字串
- 將字串轉成位元組陣列
byte[] getBytes();
將基本資料型別轉成字串
static String valueOf(int);
static String valueOf(double);
將基本資料型別轉成字串有一個更簡單的方法,那就是:
3+""; // String.valueOf(3); int--->String
例,
public static void sop(Object obj) { System.out.println(obj); } public static void method_trans() { char[] arr = {'a','b','c','d','e','f'}; String s = new String(arr,1,3); sop("s="+s); String s1 = "zxcvbnm"; char[] chs = s1.toCharArray(); for (int x = 0; x < chs.length; x++) { sop("chs="+chs[x]); } }
特殊:字串和位元組陣列在轉換過程中,是可以指定編碼表的。
- 將字元陣列轉成字串
替換
String replace(oldchar, newchar);
例,
public static void sop(Object obj) { System.out.println(obj); } public static void method_replace() { String s = "hello java"; // String s1 = s.replace('q', 'n'); // 如果要替換的字元不存在,返回的還是原串 String s1 = s.replace("java", "world"); sop("s="+s); sop("s1="+s1); }
切割
String[] split(regex);
例,
public static void sop(Object obj) { System.out.println(obj); } public static void method_split() { String s = "zhangsan,lisi,wangwu"; String[] arr = s.split(","); for (int x = 0; x < arr.length; x++) { sop(arr[x]); } }
子串。獲取字串中的一部分
String substring(begin);
String substring(begin, end);
例,
public static void sop(Object obj) { System.out.println(obj); } public static void method_sub() { String s = "abcdef"; sop(s.substring(20)); //從指定位置開始到結尾,如果角標不存在,會出現字串角標越界異常 sop(s.substring(2,4));//包含頭,不包含尾。獲取整個字串:s.substring(0, s.length()); }
轉換,去除空格,比較
- 將字串轉成大寫或小寫
String toUpperCase();
String toLowerCase();
- 去除字串兩端的空白
String trim();
- 對兩個字串進行自然順序的比較
int compareTo(String);
例,
public static void sop(Object obj) { System.out.println(obj); } public static void method_7() { String s = " Hello Java "; sop(s.toLowerCase()); sop(s.toUpperCase()); sop(s.trim()); String s1 = "a1c"; String s2 = "aaa"; sop(s1.compareTo(s2)); }
- 將字串轉成大寫或小寫
有關String類的練習題
練習一、模擬一個trim()方法,去除字串兩端的空格。
解:
思路:
1. 判斷字串第一個位置是否是空格,如果是繼續向下判斷,直到不是空格為止。結尾處判斷空格也是如此
2. 當開始和結尾都判斷到不是空格時,就是要獲取的字串
public class StringTest {
public static void sop(String str) {
System.out.println(str);
}
public static String myTrim(String str) {
int start = 0, end = str.length()-1;
while(start <= end && str.charAt(start) == ' ')
start++;
while(start <= end && str.charAt(end) == ' ')
end--;
return str.substring(start, end+1);
}
public static void main(String[] args) {
String s = " ab cd ";
sop("("+s+")");
s = myTrim(s);
sop("("+s+")");
}
}
練習二、將字串中指定的部分進行反轉,"abcdefg"--->"abfedcg"
。
解:
思路:
1. 將字串變成陣列
2. 對陣列反轉
3. 將陣列變成字串
class StringTest {
public static void sop(String str) {
System.out.println(str);
}
public static String reverseString(String s, int start, int end) {
// 字串變成陣列
char[] chs = s.toCharArray();
// 反轉陣列
reverse(chs, start, end);
// 將陣列變成字串
return new String(chs);
}
public static String reverseString(String s) {
return reverseString(s, 0, s.length());
}
private static void reverse(char[] arr, int x, int y) {
for (int start = x, end = y - 1; start < end; start++, end--) {
swap(arr, start, end);
}
}
private static void swap(char[] arr, int x, int y) {
char temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
public static void main(String[] args) {
String s = "ab cd ";
sop("("+s+")");
sop("("+reverseString(s)+")");
sop("("+reverseString(s, 0, 3)+")");
}
}
練習三、獲取一個字串在另一個字串中出現的次數。例如,”kk”在”abkkcdkkefkkskk”出現的次數。
解:
思路:
1. 定義一個計數器
2. 獲取”kk”第一次出現的位置
3. 從第一次出現的位置後剩餘的字串中繼續獲取”kk”出現的位置,每獲取一次就計數一次
4. 當獲取不到時,計數完成
public class StringTest {
public static void main(String[] args) {
String str = "nbadfnbaghjnbaklnba";
String key = "nba";
int count = getKeyCount(str, key);
System.out.println("count = " + count);
}
public static int getKeyCount(String str, String key) {
// 1,定義變數計數
int count = 0;
// 2,定義變數,記錄每次找到的角標
int index = 0;
// 2,迴圈。條件是indexOf查詢方法返回的結果不是-1,而且要明確下次查詢的位置,indexOf(String, fromIndex);
while ((index = str.indexOf(key, index)) != -1) {
count++;
// 每找完一次,都要確定下次要找的起始位置。上次位置+key的長度
index += key.length();
}
return count;
}
}
練習四、獲取兩個字串中最大相同子串。例如,”abcwerthelloyuiodef”和”cvhellobnm”。
解:
思路:
1. 以短的字串為主,到長的字串中去判斷是否存在,如果存在,已找到。
2. 如果沒有找到,將短的字串的長度遞減,獲取子串,繼續到長的串中查詢,只要找到就結束。
3. 沒有找到,說明沒有相同的
public class StringTest {
public static void main(String[] args) {
String s1 = "sadfcctvghjkl";
String s2 = "zxcctvcv";
String maxSub = getMaxSubString(s1, s2);
System.out.println("maxSub = " + maxSub);
}
public static String getMaxSubString(String s1, String s2) {
// 確定哪個是長的哪個是短的
String longStr, shortStr;
longStr = s1.length() > s2.length() ? s1 : s2;
shortStr = s1.equals(longStr) ? s2 : s1;
// System.out.println("long:" + longStr);
// System.out.println("short:" + shortStr);
// 對短的字串操作,從短串中取子串,到長字串中判斷,是否存在
for (int x = 0; x < shortStr.length(); x++) {
for (int y = 0, z = shortStr.length() - x; z <= shortStr.length(); y++, z++) {
// 根據y、z獲取子串
String temp = shortStr.substring(y, z);
// System.out.println(temp);
if (longStr.contains(temp)) {
return temp;
}
}
}
return null;
}
}
練習五、字串可以比較大小嗎?如果有!將字串陣列排序。
解:基本型別數值可以通過比較運算子(>、==、<)比較大小和相等。物件亦可以比較是否相等,誰大誰小,都是通過方法完成的。物件比較相同用的是Object類的equals()方法,子類一般情況下都會複寫,建立自己判斷相同的依據。物件比大小,用的也是方法,該功能有3種情況,所以使用int型別——正數、負數、0。前者大於後者返回正數,前者小於後者返回負數,前者等於後者返回零。
示例程式碼如下:
public class StringTest {
public static void main(String[] args) {
String[] strs = {"haha", "nba", "abc", "cba", "haha", "qq", "hiahia"};
printArray(strs);
// 對字串陣列排序
sort(strs);
printArray(strs);
}
public static void sort(String[] strs) {
for (int x = 0; x < strs.length - 1; x++) {
for (int y = x + 1; y < strs.length; y++) {
if (strs[x].compareTo(strs[y]) > 0) {
swap(strs, x, y);
}
}
}
}
private static void swap(String[] strs, int x, int y) {
String temp = strs[x];
strs[x] = strs[y];
strs[y] = temp;
}
public static void printArray(String[] strs) {
for (int i = 0; i < strs.length; i++) {
if (i != strs.length - 1) {
System.out.print(strs[i] + ",");
} else {
System.out.println(strs[i]);
}
}
}
}
練習六、對字串中的字元進行自然排序。
解:
思路:
1. 要排序,我會!但是隻會陣列排序。
2. 怎麼能把字串轉成陣列呢?
3. 到字串中找方法
4. 排序我熟
5. 將排序後的陣列變成字串
public class StringTest {
public static void main(String[] args) {
String str = "jbdsakncv";
String sortString = sortChar(str);
System.out.println(sortString);
}
/**
* 對給定的字串中的字元進行自然排序,並返回排序後的字串
* @param str
* @return
*/
public static String sortChar(String str) {
// 1,將字串轉成字元陣列
char[] chs = stringToArray(str);
// 2,對陣列排序
sort(chs);
// 3,將陣列轉成字串
return toString(chs);
}
/*
* 將字元陣列轉成字串
*/
private static String toString(char[] chs) {
return new String(chs);
}
/*
* 對字元陣列進行升序排序
*/
private static void sort(char[] chs) {
Arrays.sort(chs);
}
/*
* 將字串轉成字元陣列
*/
private static char[] stringToArray(String str) {
return str.toCharArray();
}
}
StringBuffer
StringBuffer是字串緩衝區,是一個容器。特點有:
- 長度可以變化
- 可以對內容通過指定的方法進行修改
- 容器物件一般都會具備對容器中的元素進行操作的功能,比如增刪改查
- 緩衝區中可以儲存不同型別的資料
- 最終緩衝區儲存完的資料都會變成字串
試看以下程式碼:
String str = "a" + 4 + "c";
如果我們分析以上程式碼在記憶體中的變化情況,可得出以下結論:
- 先建立一個字串緩衝區容器
- 將要組成字串的元素先儲存起來
- 最後將緩衝區中填充的資料變成字串
用程式碼來表示就是:
str = new StringBuffer().append("a").append(4).append("c").toString();
StringBuffer類的常用方法
儲存
StringBuffer append(data);
—將指定的資料作為引數新增到已有資料的結尾處StringBuffer insert(index, data);
—可以將資料插入到指定index位置
例,
public static void sop(String str) { System.out.println(str); } public static void method_add() { StringBuffer sb = new StringBuffer(); sb.append("abc").append(true).append(34); // 方法呼叫鏈 // StringBuffer sb1 = sb.append(34); // sop("sb==sb1:"+(sb == sb1)); sb.insert(1, "qq"); sop(sb.toString()); // aqqbctrue34 // sop(sb1.toString()); }
關於輸出列印
println()
和print()
方法,我們應注意:它倆會將所有要列印的資料先轉成字串再輸出,對於物件會自動呼叫toString()方法。刪除
StringBuffer delete(start, end);
—刪除緩衝區中的資料,包含start,不包含endStringBuffer deleteCharAt(index);
—刪除指定位置的字元
例,
public static void sop(String str) { System.out.println(str); } public static void method_delete() { StringBuffer sb = new StringBuffer("abcde"); // sb.delete(1, 3); // 清空緩衝區 // sb.delete(0, sb.length()); // sb.delete(2, 3); sb.deleteCharAt(2); sop(sb.toString()); }
- 獲取
char charAt(int index);
int indexOf(String str);
int lastIndexOf(String str);
int length();
String substring(int start, int end);
修改
StringBuffer replace(start, end, string);
void setCharAt(int index, char ch);
例,
public static void sop(String str) { System.out.println(str); } public static void method_update() { StringBuffer sb = new StringBuffer("abcde"); // sb.replace(1, 4, "java"); sb.setCharAt(2, 'k'); sop(sb.toString()); }
- 反轉
StringBuffer reverse();
將緩衝區中的指定資料儲存到指定字元陣列中
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin);
例,
public static void main(String[] args) { StringBuffer sb = new StringBuffer("abcdef"); char[] chs = new char[6]; sb.getChars(1, 4, chs, 1); for (int x = 0; x < chs.length; x++) { sop("chs["+x+"]="+chs[x]+";"); } } public static void sop(String str) { System.out.println(str); }
可變長度的陣列
檢視API幫助文件,我們發現StringBuffer類有一個空參構造方法,如下:
- StringBuffer()
API幫助文件對其的解釋是:
構造一個其中不帶字元的字串緩衝區,其初始容量為16個字元。
我的理解是:字串緩衝區中維護了一個”可變長度的陣列”,所謂”可變長度的陣列”其實就是超出內部陣列長度後,新建陣列長度要是原陣列的1.x(1.5或者1.75等)倍數,並將原陣列的資料複製到新陣列中,並將新的元素也新增到新陣列中。
有關StringBuffer類的練習題
練習一、通過緩衝區,將要列印的矩形組成元素*進行儲存後,一次性返回,並輸出。
解:題目比較簡單,直接貼出程式碼。
public class StringBufferTest {
public static void main(String[] args) {
String rec = draw(8, 5);
System.out.println(rec);
}
/*
* 畫矩形的功能
* 將需要組成矩形的元素進行臨時儲存
*/
public static String draw(int row, int col) {
// 定義一個臨時容器
StringBuffer sb = new StringBuffer();
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
sb.append("*");
}
sb.append("\n");
}
return sb.toString();
}
}
練習二、將int陣列的元素轉成字串,格式為:[34, 12, 67]。
解:此題也比較簡單,我們直接貼出程式碼。
public class StringBufferTest {
public static void main(String[] args) {
int[] arr = {34, 12, 67, 43, 69};
String s = toString(arr);
System.out.println(s);
}
/*
* int陣列轉成字串,通過StringBuffer
*/
public static String toString(int[] arr) {
StringBuffer sb = new StringBuffer();
sb.append("[");
for (int i = 0; i < arr.length; i++) {
if (i != arr.length - 1)
sb.append(arr[i] + ",");
else
sb.append(arr[i] + "]");
}
return sb.toString();
}
}
練習三、以下程式碼,會列印輸出什麼?
public class StringBufferTest {
public static void main(String[] args) {
StringBuffer buf1 = new StringBuffer("hello");
StringBuffer buf2 = new StringBuffer("java");
test(buf1, buf2);
System.out.println(buf1 + "..." + buf2);
}
public static void test(StringBuffer buf1, StringBuffer buf2) {
buf1.append(buf2);
buf1 = buf2;
}
}
解:好久都沒分析物件記憶體結構圖了,瞬間就懵逼了,畫了如下的一張圖之後,才醒悟過來,慚愧!!!
所以,以上程式碼執行會在控制檯中輸出:
hellojava…java
StringBuilder
JDK1.5版本之後,出現了StringBuilder
,它和StringBuffer
用法一樣,所以就不再過多講解了。
StringBuffer
與StringBuilder
的區別:
StringBuffer
是執行緒同步的StringBuilder
是執行緒不同步的
一般可以建議選擇StringBuilder
,因為其速度快。但是將StringBuilder
的例項用於多個執行緒時是不安全的。如果需要這樣的同步,則建議使用StringBuffer
。
JDK版本升級的三個要素
JDK版本升級的要素無非就是:
- 提高效率
- 簡化書寫
- 提高安全
基本資料型別物件包裝類
將基本資料值封裝成了物件,帶來的好處就是可以在物件中定義更多的屬性和行為對基本資料型別進行操作。
基本資料型別包裝類的最常見作用:就是用於基本資料型別和字串型別之間做轉換。
- 基本資料型別轉成字串:
- 基本資料型別+”“;
- 專業做法:
基本資料型別的包裝類.toString(基本資料型別值)
如:Integer.toString(34);// 將整數34變成字串"34";
字串轉成基本資料型別:
- 應用:文字框獲取的資料都是字串
xxx a = Xxx.parseXxx(String);
例,
int a = Integer.parseInt("123"); double b = Double.parseDouble("12.23"); boolean b = Boolean.parseBoolean("true"); // 還有一種形式: Integer i = new Integer("123"); int num = i.intValue();
// 將一個字串轉成整數 int num = Integer.parseInt("a123");//NumberFormatException,必須傳入數字格式的字串 System.out.println("num="+(num+4));
十進位制轉成其他進位制
toBinaryString();
toHexString();
toOctalString();
例,
System.out.println(Integer.toBinaryString(6)); System.out.println(Integer.toBinaryString(-6)); System.out.println(Integer.toHexString(60));
其他進位制轉成十進位制
parseInt(String, radix);
例,
int x = Integer.parseInt("3c", 16); System.out.println("x="+x);
JDK1.5版本以後出現的新特性——自動裝箱與自動拆箱。
JDK1.5以後,簡化了定義方式:如
Integer i = new Integer(4);
可以直接寫成:
Integer i = 4; // 自動裝箱。Integer.valueOf(4);
接著自動拆箱:
i = i + 6; // 右邊的i自動拆箱了。i.intValue() + 6,運算完的結果又一次裝箱賦值給i。
需要注意:在使用時,Integer x = null;
上面的程式碼就會出現NullPointerException
。
一個面試題
執行以下程式碼,看會輸出什麼?
class IntegerDemo {
public static void sop(String str) {
System.out.println(str);
}
public static void main(String[] args) {
Integer m = 128;
Integer n = 128;
sop("m==n:"+(m==n));
Integer a = 127;
Integer b = 127;
sop("a==b:"+(a==b));
}
}
答案是:false
和true
。以下是解析:
Integer m = 128;
Integer n = 128;
sop("m==n:"+(m==n)); // false,因為m和n指向了不同Integer物件,
Integer a = 127;
Integer b = 127;
// 結果為true。因為a和b指向了同一個Integer物件,
// 因為當數值在byte範圍內時,對於新特性,如果該數值已經存在則不會再開闢新的空間
sop("a==b:"+(a==b));
得出結論:
JDK1.5以後,自動裝箱的值如果在byte範圍之內,相同的值不會單獨開闢空間,而是重複使用。
一個練習題
練習:有這樣一個字串:”23 10 -8 0 3 7 108”,請對字串中的數值進行升序排序後,生成一個數值有序的字串——”-8 0 3 7 10 23 108”。
解:
思路:
1. 排序,而且對整數數值排序。
2. 排序的元素都在字串中,如何取出?
3. 找String類的功能,而且我發現,數字之間的間隔都是相同的空格,有規律。如果有這個功能,結果是返回多個字串,找到方法:String[] split(String)
4. 將獲取到的數字格式的字串轉成數字儲存到陣列中
5. 對陣列排序
6. 將陣列轉成字串
public class Test {
private static final String SEPARATOR = " ";
public static void main(String[] args) {
String numStr = "23 10 -8 0 3 7 108";
String sortStr = sortNumberString(numStr);
System.out.println(sortStr);
}
/**
* 對一個有多個數值的字串,進行數值的排序
* @param numStr
* @return
*/
public static String sortNumberString(String numStr) {
// 1,將給定的字串分解成多個數字格式的字串
String[] numStrs = toStringArray(numStr);
// 2,將字串陣列轉成int陣列
int[] nums = toIntArray(numStrs);
// 3,對陣列排序
sort(nums);
// 4,將int陣列轉成字串
return toString(nums);
}
/*
* 將int陣列轉成字串
*/
private static String toString(int[] nums) {
// 1,定義一個StringBuilder字串緩衝區
StringBuilder sb = new StringBuilder();
for (int i = 0; i < nums.length; i++) {
if (i != nums.length)
sb.append(nums[i] + SEPARATOR);
else
sb.append(nums[i]);
}
return sb.toString();
}
/*
* 對int陣列進行升序排序
*/
private static void sort(int[] nums) {
Arrays.sort(nums);
}
/*
* 將字串陣列轉成int型別陣列
*/
private static int[] toIntArray(String[] numStrs) {
// 1,建立一個int型別的陣列,長度和字串陣列的長度一致
int[] nums = new int[numStrs.length];
// 2,對字串陣列進行遍歷
for (int i = 0; i < numStrs.length; i++) {
// 3,將字串陣列中的元素通過parseInt()方法轉換後,賦值給int型別的陣列
nums[i] = Integer.parseInt(numStrs[i]);
}
return nums;
}
/*
* 將字串按照指定的分隔,轉成字串陣列
*/
private static String[] toStringArray(String numStr) {
// 使用字串的split(regex)
return numStr.split(SEPARATOR);
}
}