一、String 類
1、定義:
1、從概念上講,java字符串就是Unicode字符序列。每個用雙引號括起來的字符串都是String類的一個實例。
Java字符串由char序列組成,也就是說,String的最小單位是char類型的字符。字符數據類型是一個采用UTF-16的編碼表示Unicode代碼點的代碼單元。(大多數的常用Unicode字符使用一個代碼單元就可以表示,而付諸字符需要一對代碼單元表示。具體內容,請自行查閱相關資料或者百度,本人不在此贅述了。)
2、格式:
//方式一、存儲在StringPool中
String str1 = "java";?
//方式二、存儲在堆內存中
String str2 = new String("java");
- 說明:兩種方式的區別
方式二進行實例化string
對象時,實際上是開辟了兩個內存空間,因此一般開發中都采用直接賦值的方式。
3、StringPool(字符串池):
在java的內存分配中,存在著一個方法區,這里有一個常量池,是存放那些常量等不變的值,StringPool即字符串池就是存在于這里,它是一個存放字符串的公共存儲池。字符變量指向存儲池中的相應位置。如果是通過復制一個字符串變量,原始的字符串和復制的字符串將共享這個相同的字符串。
2、特點:
1、String是一種特殊的數據類型,可創建對象。
2、通過String創建的對象分別可存在于字符串池(StringPool)和堆內存中
3、String是一個final的類型,即不可被繼承修改,一經初始化就終生不可改變。(要改變也是改變的引用變量)
4、StringPool中的數據可共享,即兩個引用變量可指向同一個字符串池中的字符串
5、Java中的任何對象都可寫成字符串的形式。
注:字符串不可變的原因:
a. 可以想得出,每種固定的東西是不會改變的,1就是1,也就是說你若想改變,只得改變這個引用變量所指向的地址。
b. 編譯器可以讓字符串共享數據。所以不必改變字符串,直接改變變量即可。
c. java的開發者認為共享數據的效率要遠遠勝于提取、拼接字符串的效率。程序中對字符串的修改操作很少,更多的是對字符串進行比較。
(例外:將源自于文件或鍵盤的單個字符或較短的字符串匯集成字符串。具體在下面會說到。)
3、String類相關方法:
String類適用于描述字符串事物,它提供了多個方法對字符串進行操作,下面給大家介紹幾個比較常用的關于字符串的方法;如果還想了解更多關于String類的方法,可以查看String的相關API。
一)字符串的獲取:
以 String str = "Hellow java";
為例
1、int length()
length方法返回給定字符串的長度:
例如:
str.length();//值為11
2、char charAt(int index)
根據位置獲取某個字符串
例如:
char c = str.charAt(4);//結果為 o
2、int indexOf(int ch)
根據字符串獲取該字符在字符串中的位置。返回字符串中第一次出現的位置。
例如:
int x = str.indexOf('j');//結果為7
int indexOf(int ch,int fromIndex)
從fromIndex指定位置開始。獲取在字符串中的位置。
例如:
int x = str.indexOf("w",3);//結果為5
int y = str.indexOf("f",3);//結果為-1,沒有找到
注:
int indexOf(String str)和int indexOf(String str,int fromIndex)同上,只是接收的是String類型的數據。(方法重載)
當訪問到字符串中不存在的角標時,會發生StringIndexOutOfBoundsException的角標越界的錯誤。如果未找到則返回-1,下同。
3、int lastIndexOf(int ch)
反向索引一個字符出現的位置,此位置的角標仍為從左數的角標。
例如:
int m = str.lastIndexOf("v");//結果為9
二)字符串的判斷:
以下面為例:
String str = "StringDemo.java";
String s = "StringDemo.java";
1、 boolean contains(str)
判斷字符串中是否包含一個子串
例如:
boolean b1 = str.contains("Demo");//結果為true
2、boolean isEmpty()
判斷字符串中是否有內容,原理就是判斷字符串長度是否為0:
例如:
boolean b2 = str.isEmpty();//結果為true
3、 boolean startWith()
判斷字符串是否以指定內容開頭:
例如:
boolean b3 = str.startWith("String");//結果為true
4、 boolean endWith()
判斷字符串是否以指定內容結尾:
例如:
boolean b4 = str.endWith(".java");//結果為true
5、 boolean equals()
判斷兩個字符串的內容是否相同:
例如:
boolean b5 = str.equals(s);//結果為true
注:
判斷字符串內容是否相同,是復寫了Object類中的equals的方法,是區分大小寫的。
6、 boolean equalsIgnoreCase()
判斷兩個字符串的內容是否相同,忽略大小寫:
例如:
boolean b5 = str.equalsIgnoreCase("STRINGdEmo.JAVA");//結果為true
三)字符串的轉換:
例子:
char[] arr = {'a','b','c','d','e','f','g','h'};
String str = "Hello java";
1、將字符數組轉化成字符串:
構造函數:String(char[]) 及 String(char[] ch,int offset,int count)
例如:
String s = new String(arr);//結果為:s = abcdefgh
String st = new String(arr,1,3);//結果為:st = bcd
2 、char[] toCharArray()
將字符串轉化成數組:
例如:
char[] ch = str.toCharArray();//結果為:ch = {'H','e','l','l','o',' ','j','a','v','a'}
3、字符串和字節數組間的轉換,同1和2,參數為byte[]型值。
String(byte[] b);和String(byte[] b,int offset,int count)
byte[] getByte[]:byte[] b = str.getByte();
4、static String valueOf(3)
專業寫法:將基本數據類型轉換成字符串:
String.valueOf(3);//結果為:"3"
非專業寫法:
3+""
四)字符串的“更改”:
例子:
String s = " Hello Java ";
1、String replace(oldchar,newchar):
字符串的替換
例如:
str.replace("Java","World");//結果為:s1 = " Hello World "
str.replace('a','n');//結果為:s1 = " Hello Jnvn "
注:如果要替換的字符不存在,則返回原串。
2、String toUpperCase() 和 String toLowerCase()
將字符串轉為大寫或小寫:
例如:
str.toUpperCase();//結果為:" HELLO JAVA "
str.toLowerCase();//結果為:" hello java "
3、String trim()
將字符串兩端的多個空格去掉:
例如:
str.trim();//結果為:"Hello Java"
4、String[] split(regex)
字符串的切割:
例子:
String str = "zhangsan,wangwu,lisi,xiaohei";
例如:
String[] s = str.split(",");//結果為:s = {"zhangsan","wangwu","lisi","xiaohei"}
5、int compareTo(String str)
對兩個字符進行自然順序的比較:
例如:
String s1 = "abc"; String s2 = "aaa";
int n = s1.compareTo(s2);//結果為:n = 1
五)字符串的截取:
substring(int a,int b)
獲得字符串的子串:
String類的方法substring可以從一個較大的字符串提取出一個子串。
方法的中a和b分別代表獲取的字符串的起始位置(從哪個位置開始獲取,包含此位置)和終止位置(不包括b),獲得s.substring(a,b)的長度是b-a。
例如:
String s = "adflkwefnkl";
獲取子串--從指定位置到結尾:
s.substring(2)//結果為:"flkwefnkl"
獲取從指定位置到另一位置:
s.substring(2,4));//結果為:"fl" --->包含頭,不包含尾
六)返回字符串對象的規范化表示形式
intern()
該方法返回是始終都是StringPool中的對象。
該方法和String m = ”Hello”聲明代碼的效果實際上是一樣的,使用intern返回的始終是StringPool中的對象。
比如你首先使用String s = new String("abc")聲明一個變量,然后判斷s == s.intern()的話,那么會得到一個false,原因就是因為s是分配在堆中的一個新對象。
4、字符串的比較:
在這里,我重點說一下關于字符串之間的比較,因為這個問題很常見,也很容易讓人混淆:
1、概述:
在Object這個根類中,存在一個equals(Ojectobj)的方法,指示其他某個對象是否與此對象“相等”。但是在String的方法中也有一個equals的方法,你查看API文檔就會發現:根類Object中的equals方法被String中的equals方法覆蓋了,它是將此字符串與指定的對象比較。當且僅當該參數不為null,并且是與此對象表示相同字符序列的String對象時,結果才為true。
表達式為:x.equals(y)
如果字符串x和字符串y相等,則返回true,否則返回false。需要注意的是,x和y可以使字符串變量,也可以是字符串常量,如這樣的寫法也是合法的:”Hello”.equals(str)
2、檢測兩字符串是否相等:
- equalsIgnoreCase方法:
要想檢測兩個字符串是否相等,而且不區分大小寫,則可以使用此方法。
使用==運算符,檢測的是指向字符串池中同一個字符串的兩個引用變量是否相等。可以思考一下,只有字符串常量是真正實現共享的,如果用+或者substring這樣的拼接等操作產生的結果并不是共享的。而是在StringPool又創建了一個新的字符串對象。
2)比較:
第一、String s ="abc”;
在執行這句代碼的時候,JVM會首先查詢StringPool,如果在該StringPool中已經存在相應的String實例了,那么將不會在堆中分配相應的內存來生成一個String對象,所以在代碼中多次使用上面的聲明來聲明的變量實際指向的是同一個對象(那么當然就是相同的數據了)。
現在來說一下JVM查找的時候沒有找到相應的String對象的情況,這時JVM會在StringPool中生成相應的對象,但是并不會在堆中生成相應的對象,所以只要使用上面的代碼聲明,堆中將始終不會生成新的String對象。
第二、String str= new String(”abc”)
要是比較這樣定義格式的字符串,就需要使用equals方法了,上面也說到了,String類對Object的equals進行了覆蓋了,所以String類是有自己比較字符串的方法的。
只有使用new創建一個對象,那么就會在堆內存中開辟一塊空間存放這個數據。看下面的代碼:
String s1 = "abc";
String s2 = new String("abc");
String s3 = new String("abc");
String s4= s2;
s1==s2;//false,不是同一個對象
//下面都是比較的字符串這個值,即數據
s1.equals(s2);// true
s2.equals(s3);//true
s2.equals(s4);//true
第三、需要補充一點:
String s1 = "abc";
String s2 = new String("abc");
對于上面的代碼,有一點要說的:就是無論String s2 = new String("abc")
在s1前面寫還是后面寫,s2都會檢查StringPool中是否有"abc",若有,就直接在堆內存中創建一個對象;若沒有,則要先在StringPool中創建"abc"后,再在堆內存中創建一個對象。
注意:
選擇用==運算符比較兩個字符串總不是太好的方法,否則String的API文檔也不會覆蓋Object中的equals方法了。所以最好不要使用==運算符檢測兩個字符串是否相等,因為這個運算符只能確定兩個字符串是否放在同一個位置(內存地址是否相同)上。對于兩個對象,==運算符檢測的結果當然為false了。也就是說一般檢測下面所定義格式的字符串:
String greet = "Hello";
System.out.println(greet == "Hello");//true
System.out.println(greet.substring(0,3) == "Hel");//false
5、構造字符串
在這里以StringBuilder為例,在穿插著說一下StringBuffer。
1、概述:
上面也提到了:按鍵或者來自文件中的單詞。采用字符串連接的方式達到此目的的效率是十分低的,每次連接字符串,都會構建一個新的String對象,既降低了效率,又占用大量的空間。通過使用StringBuilder類局可以避免這個問題。另外,在構建字符串時就調用toString方法,可以得到一個String對象。
StringBuilder作為一個容器,是被final修飾的,它是字符串緩沖區,可以對這個“容器”進行“CURD”操作,即存儲(creat),修改(update),獲取(read),刪除(delete)。
這里需要說明的一點是:StringBuilder是在JDK1.5之后才出來的,相對于StringBuffer的效率要高。因為可以不用每次判斷鎖。雖然不安全,但是效率更高,建議開發使用StringBuilder。
StringBuilder和StringBuffer的對比:
----StringBuilder:是線程不同步的,相對效率更高,但是不安全
----StringBuffer: 是線程同步的,相對效率較低,但安全。
2、構建格式:
StringBuilder bul = new StringBuilder();
3、特點:
第一、StringBuilder的長度是可變的,也可以通過length()的方法求當前對象的長度。
第二、可以直接操作多個數據類型。可將如int、double、char、boolean等類型的數據作為字符串相連接存入容器中。
第三、最終會通過toString方法變為字符串。
4、StringBuilder的操作方法:
4.1 append():存儲
StringBuilder append();
如果要在字符串中“添加”一些內容,則可以使用append方法。可以將制定數據作為參數添加到已有數據的結尾處。
例子:
StringBuilder result = new StringBuilder();
for (int i = 0; i < 5; i++)
{
result.append("a");
result.append(" ");
}
System.out.println(result.toString());//結果為:"a a a a a "
注:方法調用連 -----> 一連調用方法,返回的還是對象。
如:
str.append("abc").append(true).append(123).append(20.6);//值為:“abctrue12320.6”
StringBuilder insert(index,數據)
將數據插入到指定index位置
例如:
StringBuilder bul = new StringBuilder("adflkwefnkl");
bul.insert(1,"qq");//結果為:"aqqdflkwefnkl"
3.2 delete()
刪除
*StringBuilder delete(start,end) *:刪除緩沖區中的數據,包含start,不包含end
例如:
StringBuilder bul = new StringBuilder("adflkwefnkl");
bul.delete(1,3);//結果為:"alkwefnkl"
bul.delete(0,bul.length());//清空緩存區,bul為""
bul.deleteCharAt(2);//結果為:"adlkwefnkl"
3.3 獲取:
char charAt(int index)---> 獲取指定位置index上的字符
int indexOf(String str)---> 獲取指定字符串的位置
int lastIndexOf(String str)---> 反向獲取指定字符串的位置
int length()---> 獲取字符串的長度
*String substring(int start,int end):在Stringbuilder中比較特殊,返回的是String類型。
例如:
StringBuilder bul = new StringBuilder("adflkwefnkl");
bul.charAt(1);//結果為:"d"
bul.indexOf("a");//結果為:0
bul.lastIndexOf("n");//結果為:8
bul.length();//結果為:10
bul.substring(1,3)//結果為:"df"
3.4修改:
StringBuilder replace(start,end,string)---> 將start到end(不包含end)位置上的字符串更改為指定字符串string
void setCharAt(int index,char ch)---> 替換指定位置上的字符為指定字符
例如
StringBuilder bul = new StringBuilder("adflkwefnkl");
bul.replace(1,3,"JAVA");//結果為:"aJAVAlkwefnkl"
bul.replace(2,'M');//結果為:"adMlkwefnkl"
3.5 反轉
StringBuilder setreverse() ---> 替換指定位置上的字符為指定字符
例如:
StringBuilder bul = new StringBuilder("ABCD");
bul.reverse();//結果為:"DCBA"
關于StringBuilder的內容,我找了一些資料,如果想了解更多,可以參閱:
Java中的StringBuilder類功能詳解
總結:
對于String這個比較特殊的類,使用是十分頻繁的,對于她在內存中的分配,字符串間的操作,如比較,以及如何優化String中的數據等等,這些問題還需要在以后慢慢積累。
在此,我也將一篇別人的文章分享給大家,是關于一個經常苦惱人的問題的(String s = "a" + "b" + "c" + "d"創建了幾個對象的問題)。希望對大家有所幫助
文章地址:
String s = "a" + "b" + "c" + "d"創建了幾個對象的問題
二、包裝類
1、概述:
1、有時候,需要將int這樣的基本類型轉換為對象,以便可以使用一些方法。所有的基本類型都有一個相對應的類。這些類就稱之為包裝類。
2、基本數據類型對應的包裝類:
基本數據類型 | 引用數據類型(包裝類) |
---|---|
byte | Byte |
short | Short |
int | Integeter |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
char | Character |
2、常見操作:
用于基本數據類型和字符串類型間的轉換
1、轉換:
1)基本數據類型轉換為字符串
基本數據類型 + "" ---> 直接轉換成字符串
基本數據類型.toString(基本數據類型值) ---> 如:Integer.toString(34);//將整數34變為"34"
2)字符串轉換為基本數據類型:
基本數據類型名 變量名 = 包裝類名.pase包裝類名(String)
如:int a = Integer.paseInt("123");//結果為123
2、轉二進制:
Integer.toBinaryString(int a);
十進制 -----> 其他進制
1)轉為二進制:toBinaryString();
2)轉為八進制:toOctalString();
3)轉為十六進制:toHexString();
其他進制 -----> 十進制
parseInt(String,radix);
class IntegerDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
//整數類型的最大值
sop("int max --Integer.MAX_VALUE:" + Integer.MAX_VALUE);
sop("------------------");
//將一個字符串轉換成整數
//靜態
int x = Integer.parseInt("123");
long y = Long.parseLong("123");
sop("字符串轉換成整數Integer.parseInt(”123“):x = " + (x + 4));
//非靜態
Integer i = new Integer("123");
int num = i.intValue();
sop("非靜態:" + num);
sop("------------------");
sop("十進制轉為二進制Integer.toBinaryString(6):" + Integer.toBinaryString(6));
sop("十進制轉為十六進制Integer.toHexString(60):" + Integer.toHexString(60));
sop("------------------");
int x1 = Integer.parseInt("110",10);
int y1 = Integer.parseInt("3c",16);
sop("其他進制轉為十進制 Integer.parseInt(”進制值”,被轉的進制):" + x + "--" + y1);
}
}
3、比較
先看段小程序:
class IntegerDemo
{
public static void main(String[] args)
{
Integer m = 128;
Integer n = 128;
System.out.println("128--m==n :" + (m==n));
Integer a = 127;
Integer b = 127;
System.out.println("127--a==b :" + (a==b));
}
}
其實說起來,這個Integer和int的關系有點像String和StringBuilder的關系。
java為了優化內存,提高性能,就單開了一片內存池(pool),也就是說,在這里共享了那些固定不變的數據(我個人理解),如數字和字符串等等,這也是一種對象。
重點說Integer和int,在內存池中定義他們的范圍是 -128 ~ 127,這里的數是共享的,其實共享的是地址,就是變量指向的地址。(題外話:變量其實都是指向的地址,地址才是代表一塊內存的空間的。)java為了提高效率,初始化了-128--127之間的整數對象,所以,如果寫Integer a =100的話,是在內存池中創建了一個變量為a的對象,再寫b=100,就共享了100這個數據,其實是指向了相同地址。但是如果超過了這個范圍的話,這數據就不是共享的了,指向的不是相同地址。所以就不相等了。
具體參閱:Java Integer值范圍問題
4、打包和拆包:
class IntegerDemo
{
public static void main(String [] args)
{
Integer x = 4;
x = x + 2;
System.out.println("x" + x);
}
}
以上面的小程序為例:
自動封箱:其中Integer x = 4;就是自動封箱的過程,即Integer x = new Integer(4);
自動拆箱:其中x+2就是進行了自動拆箱的過程,將x變為int類型,再和2進行加法運算,在拆箱的時候,要先進行 x.intValue()的判斷,是否x為null,不可為null,否則編譯失敗
自動封箱:再將求的和進行封裝,賦值給x