說在前面的話:java
String類是我我的認爲是Java設計當中一個特殊的,雖然String自己特殊引用數據類型 可是她卻能夠想基本數據類型那樣直接賦值!!!面試
String類之因此特殊,主要緣由在於其有兩種不一樣的對象的實例化方式.數組
採用直接賦值字符串的形式爲String類對象實例化(推薦使用的寫法)安全
package com.shxt.demo01;
public class StringDemo01 {
public static void main(String[] args) {
String str = "直接方式實例化方式";//使用頻率特別高
System.out.println(str);
}
}
複製代碼
採用String類的構造方法爲String類進行實例化,String類重載了構造方法,在Java EE中咱們會使用到字符串轉碼問題等會使用到app
package com.shxt.demo01;
public class StringDemo02 {
public static void main(String[] args) {
String str = new String("構造函數實例化String字符串");
System.out.println(str);
}
}
複製代碼
對下面的代碼進行分析說明函數
package com.shxt.demo01;
public class StringDemo03 {
public static void main(String[] args) {
String s = "abcd";
s = "dbcdel";
}
}
複製代碼
String不可變很簡單,咱們給一個已有的s字符串變量賦值爲"abcd",第二次賦值成"abcdel",不是在原內存地址上修改,而是從新執行一個新對象,行地址.學習
爲何String就是不可變的呢? 我須要知道緣由測試
開JDK源碼,java.lang.String類起手前三行,是這樣寫的:ui
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
/* String的本質是一個char數組,而且使用了final關鍵修飾*/
/** The value is used for character storage. */
private final char value[];
... ...
... ...
}
複製代碼
代碼分析:this
1.String類是用final關鍵字修飾,這說明String不可繼承
2.String類的主要成員字段value是個char[ ]數組,並且是用 final 修飾的。
final修飾的字段建立之後就不可改變。
String類在java.lang包中,java使用String類建立一個字符串變量,字符串變量屬於對象。java把String類聲明的final類,不能有子類。String類對象建立後不能修改,由0或多個字符組成,包含在一對雙引號之間,下面簡單的熟悉一下其經常使用的API
java.lang.String char charAt (int index) 返回index所指定的字符 String concat(String str) 將兩字符串鏈接 boolean endsWith(String str) 測試字符串是否以str結尾 boolean equals(Object obj) 比較兩對象 char[] getBytes 將字符串轉換成字符數組返回 char[] getBytes(String str) 將指定的字符串轉成制服數組返回 boolean startsWith(String str) 測試字符串是否以str開始 int length() 返回字符串的長度 String replace(char old ,char new) 將old用new替代 char[] toCharArray 將字符串轉換成字符數組 String toLowerCase() 將字符串內的字符改寫成小寫 String toUpperCase() 將字符串內的字符改寫成大寫 String valueOf(Boolean b) 將布爾方法b的內容用字符串表示 String valueOf(char ch) 將字符ch的內容用字符串表示 String valueOf(int index) 將數字index的內容用字符串表示 String valueOf(long l) 將長整數字l的內容用字符串表示 String substring(int1,int2) 取出字符串內第int1位置到int2的字符串 複製代碼
A.字符串上使用"=="比較
實際開發中字符的比較不會使用"=="進行比較,請回顧咱們以前學習的內存地址方面的知識
package com.shxt.demo01;
public class StringDemo04 {
public static void main(String[] args) {
String str1 = "hanpang" ; //直接賦值實例化對象
String str2 = new String("hanpang"); //構造方法實例化對象
String str3 = str2; //引用傳遞
System.out.println(str1==str2); // false
System.out.println(str1==str3); // false
System.out.println(str2==str3); // true
}
}
複製代碼
內存分析圖以下:
代碼分析:
使用"=="的確完成了相等的判斷,可是最終判斷的是兩個對象是否相等,屬於數值判斷--判斷兩個對象的內存地址的數值,並無判斷起內容
若是想完成字符串內從的判斷,必需要使用String類的操做方法
public boolean equals(String str) 複製代碼
B.使用equals()方法進行比較
package com.shxt.demo01;
public class StringDemo05 {
public static void main(String[] args) {
String str1 = "hanpang" ; //直接賦值實例化對象
String str2 = new String("hanpang"); //構造方法實例化對象
String str3 = str2; //引用傳遞
System.out.println(str1.equals(str2)); //true
System.out.println(str1.equals(str3)); //true
System.out.println(str2.equals(str3)); //true
}
}
複製代碼
C.使用equals()方法的陷阱
之後要注意如何使用equals方法
package com.shxt.demo01;
public class StringDemo06 {
public static void main(String[] args) {
String str1 = null ;
if(str1.equals("Hello")){
System.out.println("成功");
}
}
}
複製代碼
運行後會在控制檯報空指針的異常信息
Exception in thread "main" java.lang.NullPointerException
at com.shxt.demo01.StringDemo06.main(StringDemo06.java:6) //錯誤的位置
複製代碼
修改後的代碼爲[重點!重點!重點]
package com.shxt.demo01;
public class StringDemo06 {
public static void main(String[] args) {
String str1 = null ;
if("Hello".equals(str1)){ //修改後的代碼
System.out.println("成功");
}
}
}
複製代碼
常見面試題分析,請解釋String類中"=="和"equals()"的區別?
- == : 比較兩個字符串內存地址的數值是否相等,屬於數值比較
- equals() : 比較兩個字符串的內容,屬於內容比較
簡單的面試,這個屬於常識
編號 | 方法名稱 | 類型 | 描述 |
---|---|---|---|
1 | public String(char[] value) | 構造方法 | 將字符數組內容變成字符串 |
2 | public String(char[] value,int offset,int count) | 構造方法 | 將部分字符數組變爲字符串 offset表示開始點 count標識操做的長度 |
3 | public char charAt(int index) | 普通方法 | 取得指定索引位置的字符串, 索引從0開始 |
4 | public char[] toCharArray() | 普通方法 | 將字符串轉換爲字符數組 |
驗證charAt()方法
package com.shxt.demo01;
public class StringDemo07 {
public static void main(String[] args) {
String str = "welcomeshxt" ;
char c = str.charAt(0);
System.out.println(c);
}
}
複製代碼
驗證toCharArray()方法
package com.shxt.demo01;
public class StringDemo08 {
public static void main(String[] args) {
String str = "welcomeshxt" ;
char[] data = str.toCharArray();
for (int i = 0; i < data.length; i++) {
System.out.print(data[i]+",");
}
}
}
複製代碼
練習題
將全小寫的英文字符串"welcomeshxt",變成大寫的字符串,在控制檯輸出的內容爲WELCOMESHXT 和 SHXT 兩個字符串
package com.shxt.demo01;
public class StringDemo09 {
public static void main(String[] args) {
String str = "welcomeshxt" ;
}
}
複製代碼
編號 | 方法名稱 | 類型 | 描述 |
---|---|---|---|
1 | public String(byte[] bytes) | 構造方法 | 將字節數組內容變成字符串 |
2 | public String(byte[] bytes,int offset,int length) | 構造方法 | 將部分字節數組變爲字符串 |
3 | public byte[] getBytes() | 普通方法 | 將字符串變爲字節數組 |
4 | public byte[] getBytes(String charsetName) throws UnsupportedEncodingException |
普通方法 | 字符串轉碼操做[重點] |
package com.shxt.demo01;
public class StringDemo09 {
public static void main(String[] args) {
String str = "welcomeshxt" ;
byte[] data = str.getBytes();
for (int i = 0; i < data.length; i++) {
System.out.print(data[i]+",");
data[i] -=32;//擴展賦值運算符,不會改變類型
}
System.out.println();
System.out.println("所有字節轉爲字符串:"+new String(data));
System.out.println("所有部分字節轉爲字符串:"+new String(data,7,4));
}
}
複製代碼
在String類中提供了從一個字符串查找指定字符串是否存在的操做,下面提供的說明必需要牢記
編號 | 方法名稱 | 類型 | 描述 |
---|---|---|---|
1 | public boolean contains(String s) | 普通方法 | 查找指定的字符串是否存在 |
2 | public int indexOf(String s) | 普通方法 | 從頭查找指定的字符串位置, 找不到返回-1 |
3 | public int indexOf(String s,int fromIndex) | 普通方法 | 由指定位置向後查找字符串的位置, 找不到返回-1 |
4 | public int lastIndexOf(String s) | 普通方法 | 從後查找指定的字符串位置, 找不到返回-1 |
5 | public int lastIndexOf(String s,int fromIndex) | 普通方法 | 從指定的位置由後向前查找 |
6 | public boolean startsWith(String prefix) | 普通方法 | 判斷是否以指定的字符串開頭 |
7 | public boolean startsWith(String prefix,int offset) | 普通方法 | 從指定的位置判斷是否以指定的字符串開頭 |
8 | public boolean endsWith(String suffix) | 普通方法 | 判斷是否以指定字符串結尾 |
package com.shxt.demo01;
public class StringDemo10 {
public static void main(String[] args) {
String str = "##pang@@sir**" ; //定義一個字符串
System.out.println(str.startsWith("##")); //判斷開頭
System.out.println(str.startsWith("sir",5)); // 從指定的位置開始判斷開頭
System.out.println(str.endsWith("**")); // 判斷結尾
System.out.println(str.contains("sir")); //查找字符串是否存在
System.out.println(str.contains("AA"));
System.out.println(str.indexOf("sir"));//查找字符串的位置
System.out.println(str.indexOf("AA"));
System.out.println(str.lastIndexOf("sir"));//查找字符串的位置
System.out.println(str.lastIndexOf("AA"));
}
}
複製代碼
編號 | 方法名稱 | 類型 | 描述 |
---|---|---|---|
1 | public String substring(int beginIndex) | 普通方法 | 從指定位置截取到結尾 |
2 | public String substring(int beginIndex,int endIndex) | 普通方法 | 截取部分字符串 |
package com.shxt.demo01;
public class StringDemo12 {
public static void main(String[] args) {
String str = "Hello World" ;
System.out.println(str.substring(2));
System.out.println(str.substring(2,8)); // [2,8)
}
}
複製代碼
練習題
編號 | 方法名稱 | 類型 | 描述 |
---|---|---|---|
1 | public String replace(char oldChar,char newChar) | 普通方法 | 字符替換,不經常使用 |
2 | public String replaceAll(String regex,String s) | 普通方法 | 所有替換 |
3 | public String replaceFirst(String regex,String s) | 普通方法 | 替換首個 |
package com.shxt.demo01;
public class StringDemo11 {
public static void main(String[] args) {
String str = "pangpang" ;
System.out.println(str.replace('n','X'));
System.out.println(str.replaceAll("an","*"));
System.out.println(str.replaceFirst("an","#"));
}
}
/** 運行結果 paXgpaXg p*gp*g p#gpang */
複製代碼
編號 | 方法名稱 | 類型 | 描述 |
---|---|---|---|
1 | public String[] split(String regx) | 普通方法 | 按照指定的字符串全拆分 |
2 | public String[] split(String regx,int limit) | 普通方法 | 拆分爲指定的長度 |
package com.shxt.demo01;
public class StringDemo13 {
public static void main(String[] args) {
String str = "Hello#World#!!!" ;
String[] result = str.split("#");
for (int i = 0; i < result.length; i++) {
System.out.println(result[i]);
}
}
}
複製代碼
練習題:(進行拆分時也會出翔一些字符沒法進行拆分,此時須要使用\\(表示一個\)
)進行轉義
編號 | 方法名稱 | 類型 | 描述 |
---|---|---|---|
1 | public boolean isEmpty() | 普通方法 | 判斷是否爲空的字符串("") 沒法進行null的判斷 |
2 | public int length() | 普通方法 | 取得字符串長度 |
3 | public String trim() | 普通方法 | 去掉左右空格 |
4 | public String toLowerCase() | 普通方法 | 將所有字母轉小寫 |
5 | public String toUpperCase() | 普通方法 | 將所有字母轉大寫 |
6 | public String concat(String s) | 普通方法 | 字符串鏈接(+) |
package com.shxt.demo01;
public class StringDemo14 {
public static void main(String[] args) {
String str = "Hello World" ;
System.out.println(str.isEmpty());//false
System.out.println("".isEmpty());//true
System.out.println(str.length());//獲取長度
System.out.println(" HAHA ".length());
System.out.println(" HAHA ".trim().length());//去空格的長度
System.out.println(str.toLowerCase());
System.out.println(str.toUpperCase());
System.out.println(str.concat("HAHA").concat("WOWO"));
}
}
複製代碼
練習題
user_name
→ User_name
A.基本數據類型轉字符串
String類中提供了String valueOf()放法,用做基本類型轉換爲字符串類型
static String valueOf(char data[]) static String valueOf(char data[], int offset, int count) static String valueOf(boolean b) static String valueOf(char c) static String valueOf(int i) static String valueOf(long l) static String valueOf(float f) static String valueOf(double d) 複製代碼
package com.shxt.demo01;
public class StringDemo15 {
public static void main(String[] args) {
int num = 100;
String s1 = String.valueOf(num);
String s2 = ""+100;
}
}
複製代碼
B.字符串轉基本數據類型
java.lang包中有Byte、Short、Integer、Float、Double類的調用方法:
public static byte parseByte(String s) public static short parseShort(String s) public static short parseInt(String s) public static long parseLong(String s) public static float parseFloat(String s) public static double parseDouble(String s) 複製代碼
package com.shxt.demo01;
public class StringDemo16 {
public static void main(String[] args) {
String s = "999";
int num1 = Integer.parseInt(s);
long num2 = Long.parseLong(s);
float num3 = Float.parseFloat(s);
System.out.println(num1+"-"+num2+"-"+num3);
}
}
複製代碼
咱們來分析一下字符串的程序代碼,看看這段代碼爲何要在實際開發中儘可能避免呢?
package com.shxt.demo02;
public class Demo01 {
public static void main(String[] args) {
String str = "";
for (int i = 0; i < 10000; i++) {
str += i; //字符串拼接
}
System.out.println(str);
}
}
複製代碼
代碼分析:
咱們說過String是不可變的,上面的代碼須要"斷開-鏈接"String對象10000次,會產生大量垃圾,因此不推薦這種方式,那麼咱們如何改進代碼呢?
StringBuffer字符串變量(線程安全)是一個容器,最終會經過toString方法變成字符串;
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, Appendable, CharSequence {
/** * Constructs a string buffer with no characters in it and an * initial capacity of 16 characters. */
public StringBuffer() {
super(16);
}
public synchronized StringBuffer append(int i) {
super.append(i);
return this;
}
public synchronized StringBuffer delete(int start, int end) {
super.delete(start, end);
return this;
}
}
複製代碼
代碼分析:
super(16)調用AbstractStringBuilder的抽象類的構造函數,對字符數組進行初識化操做
abstract class AbstractStringBuilder implements Appendable, CharSequence { char[] value; AbstractStringBuilder(int capacity) { value = new char[capacity]; } } 複製代碼
咱們發現字符數組不是final修飾,意味着是可變的!
A.StringBuffer的內容是能夠改變的,引用傳遞
package com.shxt.demo02;
public class Demo02 {
public static void main(String[] args) {
StringBuffer buf = new StringBuffer(); //定義StringBuffer對象
buf.append("Han ").append(" Pang"); //鏈接字符串
fun(buf); //引用傳遞
System.out.println(buf.toString()); //將buf轉爲字符串
}
public static void fun(StringBuffer temp){
temp.append(" Welcome ").append("shxt");
}
}
複製代碼
編號 | 方法名稱 | 類型 | 描述 |
---|---|---|---|
1 | public StringBuffer append(數據類型 b) | 普通方法 | 追加內容到當前StringBuffer對象的末尾, 相似於字符串的鏈接。 調用該方法之後, StringBuffer對象的內容也發生改變 |
2 | public StringBuffer deleteCharAt(int index) | 普通方法 | 刪除指定位置的字符, 而後將剩餘的內容造成新的字符串 |
3 | public StringBuffer insert(int offset, 數據類型 b) | 普通方法 | 插入內容,而後造成新的字符串 |
4 | public StringBuffer reverse() | 普通方法 | 內容反轉 |
5 | public void setCharAt(int index, char ch) | 普通方法 | 修改對象中索引值爲index位置的字符爲新的字符ch |
6 | public void trimToSize() | 普通方法 | 將StringBuffer對象的中存儲空間縮小到和 字符串長度同樣的長度,減小空間的浪費 |
package com.shxt.demo02;
public class Demo03 {
public static void main(String[] args) {
StringBuffer buf = new StringBuffer("西遊記"); //定義StringBuffer對象,並初始化數據
buf.append(",悟空").append(999); //append追加內容
System.out.println("結果1"+buf.toString());
//刪除數據
buf = buf.deleteCharAt(buf.length()-1);
buf = buf.deleteCharAt(buf.length()-1);
buf = buf.deleteCharAt(buf.length()-1);
System.out.println("刪除後的結果:"+buf.toString());
//插入數據
buf.insert(3,"====>");
System.out.println("插入後的結果:"+buf.toString());
buf.replace(3,8,"");//替換數據
System.out.println("替換後的結果:"+buf.toString());
//反轉數據
buf.reverse();
System.out.println("反轉的數據爲:"+buf.toString());
}
}
/* 結果1西遊記,悟空999 刪除後的結果:西遊記,悟空 插入後的結果:西遊記====>,悟空 替換後的結果:西遊記,悟空 反轉的數據爲:空悟,記遊西 */
複製代碼
StringBuffer sb=new StringBuffer();
sb.delete(0, sb.length());
sb.setLength(0);
StringBuffer經過使用sb.setLength(0)來清空StringBuffer對象中的內容效率最高
StringBuilder 字符串變量(非線程安全),使用方式跟StringBuffer同樣
String
繼承於CharSequence
,也就是說String
也是CharSequence
類型StringBuilder
和 StringBuffer
都是可變的字符序列。它們都繼承於AbstractStringBuilder
,實現了CharSequence
接口String
是不可變的,StringBuffer
、StringBuilder
是可變的StringBuilder
是非線程安全的,而String
(不可變對象)、StringBuffer
(對方法加了同步鎖或者對調用的方法加了同步鎖)是線程安全的StringBuilder
適用於單線程環境,StringBuffer
適用於多個線程操做同一個字符串StringBuilder
> StringBuffer
> String
參考資料: https://juejin.im/entry/59082ab5a0bb9f006510683a