java-u1-day19-正則表達(dá)式05(String里面的split方法)

Day19?字符串和正則表達(dá)式
本章重難點(diǎn)
u?String的創(chuàng)建
u?字符串常量
u?字符串比較
u?字符串常用方法
u?StringBuffer和StringBuilder
u?正則表達(dá)式
1.?
String的創(chuàng)建
1.1.??String的創(chuàng)建方式
1)String s1=”abc”; //字符串常量池
2)String s2=new String(“abc”); //棧區(qū)有一個(gè)字符串引用(地址)指向綁定堆區(qū)開盤的字符串對(duì)象空間
1.2.??以上兩種方式創(chuàng)建字符串,有什么區(qū)別?
這個(gè)問題要說清楚,必須知道字符串和字符串常量。
2.?
字符串常量
2.?
2.1.??什么是字符串常量池,它放在內(nèi)存的哪個(gè)區(qū)?
????就是采用雙引號(hào)引起來的字符串,不是使用new方式構(gòu)建的就是字符串常量。字符串常量就是放在方法區(qū)的常量池中。常量就是不可以改變的量。
2.2.??案例1
畫出兩種創(chuàng)建字符串的方式在棧、堆、方法區(qū)中的內(nèi)存結(jié)構(gòu)圖。
String str; //棧區(qū)有一個(gè)字符串引用(地址)
String?str = “abc”//棧區(qū)有一個(gè)字符串引用(地址)綁定或者指向一個(gè)常量池內(nèi)容為abc
?
過程分析:
1)?第1行代碼,JVM首先在棧中寫入一個(gè)引用s1,判斷常量池中是否存儲(chǔ)abc,如果有,就把a(bǔ)bc的首地址賦值給s1,如果沒有,就在常量池中新建一個(gè)abc,再把首地址賦值給s1.
2)?第2行代碼,JVM首先在棧中寫入一個(gè)引用s2,在堆中通過new String()開辟一塊空間,然后把這個(gè)空間的首地址賦值給s2的引用。最后在常量池中檢查看是否有abc,如果有把a(bǔ)bc的首地址賦值給new String()的空間中,如果沒有先在常量池中創(chuàng)建,然后再把地址賦值給new String()的空間中。
2.3.??結(jié)論
?????字符串常量直接指向常量池的首地址,字符串變量是指向堆空間,堆空間指向常量池。
2.4.?案例2
案例:分析下來代碼在內(nèi)存中的結(jié)構(gòu)
String str1 = "str";//常量池
String str2 = "ing";//常量池
String str3 = "str" + "ing";//常量池
String str4 = str1 + str2;?//在堆中創(chuàng)建新對(duì)象???
String str5 = "string";////常量池
問題:在編碼過程中,如果涉及到多個(gè)字符串用+進(jìn)行拼接,這種方式好不好?如果不是最好的方式,應(yīng)該采用什么方式進(jìn)行?(引出StringBuffer和StringBuilder)
?????不好,他會(huì)產(chǎn)生很多的變量在常量池,效率不高,消耗資源。所以,StringBuffer或者是StringBuilder來做拼接,經(jīng)量少用。
3.?
字符串比較相等
3.?
3.1.??問題1
需求:有如下代碼,分析代碼的結(jié)果。畫出內(nèi)存結(jié)果圖
String s1 = "abc";
String s2 = "abc";
System.out.println(s1==s2);//true
?
3.2.??問題2
需求:有如下代碼,分析代碼的結(jié)果。畫出內(nèi)存結(jié)果圖
String s1 =String( "abc");
String s2 =String( "abc");
System.out.println(s1==s2);//false
?
3.3.??字符串比較的結(jié)論
1)?==在比較字符串對(duì)象的時(shí)候用來比較什么?
????比較地址,只適用于字符串常量池
2)?如果要比較內(nèi)容是否相等,采用什么方式?
???equals():內(nèi)容是否相等,通過源代碼分析,首先比較的是地址是否相等,如果相等就是true,如果地址不相等,就一個(gè)字符一個(gè)字符對(duì)應(yīng)進(jìn)行比較。看是否相等,它是重寫了Object對(duì)象的equals()方法,Object中的equals()比較的是地址。
4.?
字符串對(duì)象的方法
4.?
4.1.? String的相關(guān)方法
l?boolean equals(Object obj):比較字符串的內(nèi)容是否相同
l?boolean equalsIgnoreCase(String str): 比較字符串的內(nèi)容是否相同,忽略大小寫
l?boolean startsWith(String str): 判斷字符串對(duì)象是否以指定的str開頭
l?boolean endsWith(String str): 判斷字符串對(duì)象是否以指定的str結(jié)尾
4.2.??案例3
需求:編寫一個(gè)測(cè)試類,測(cè)試這些方法,加深印象
public class StringTest {
????public static void main(String[] args) {
????????//1、比較字符串的內(nèi)容是否相同
????????String s1="hello";//常量池
????????String s2=new String("hello");//字符串堆內(nèi)容
????????System.out.println(s1.equals(s2));
????????//2、比較字符串的內(nèi)容是否相同,忽略大小寫
????????String s3="HeLLo";
????????System.out.println(s1.equalsIgnoreCase(s3));
????????//3、判斷字符串對(duì)象是否以指定的str開頭
????????String filename="abc_f.txt";
????????System.out.println(filename.startsWith("1abc"));
????????//4、判斷字符串對(duì)象是否以指定的str結(jié)尾
????????System.out.println(filename.endsWith(".tx1t"));
????}
}
l?int length():獲取字符串的長度,其實(shí)也就是字符個(gè)數(shù)
l?char charAt(int index):獲取指定索引處的字符
l?int indexOf(String str):獲取str在字符串對(duì)象中第一次出現(xiàn)的索引
l?String substring(int start):從start開始截取字符串
l?String substring(int start,int end):從start開始,到end結(jié)束截取字符串。包括start,不包括end
l?char[] toCharArray():把字符串轉(zhuǎn)換為字符數(shù)組
l?String toLowerCase():把字符串轉(zhuǎn)換為小寫字符串
l?String toUpperCase():把字符串轉(zhuǎn)換為大寫字符串
4.3.??案例4
需求:編寫一個(gè)測(cè)試類,測(cè)試這些方法,加深學(xué)員印象
public class StringTest1 {
????public static void main(String[] args) {
????????String s1="abcdef";
????????//length():獲取字符串的長度,其實(shí)也就是字符個(gè)數(shù)
????????System.out.println(s1.length());
????????//charAt(int index):獲取指定索引處的字符
????????char c=s1.charAt(1);
????????System.out.println(c);
????????//int indexOf(String str):獲取str在字符串對(duì)象中第一次出現(xiàn)的索引
????????int index=s1.indexOf("deccc");
????????System.out.println(index);
????????//String substring(int start):從start開始截取字符串
????????String ss=s1.substring(3);//def
????????System.out.println(ss);
????????String s2=s1.substring(1,3);
????????System.out.println(s2);//bc
????????//char[] toCharArray():把字符串轉(zhuǎn)換為字符數(shù)組
????????char[] chars = s1.toCharArray();
????????for (int i = 0; i < chars.length; i++) {
????????????System.out.println(chars[i]);
????????}
????????//String toLowerCase():把字符串轉(zhuǎn)換為小寫字符串
????????String v_s1="AvcD45E";
????????System.out.println(v_s1.toLowerCase());
???????// String toUpperCase():把字符串轉(zhuǎn)換為大寫字符串
????????System.out.println(v_s1.toUpperCase());
????}
}
4.4.??案例5
需求:獲取指定字符串中,大寫字母、小寫字母、數(shù)字的個(gè)數(shù)。
大寫字母:一個(gè)字符(char)ch???ch>=’A’ && ch<=’Z’
小寫字母:一個(gè)字符(char)ch ??ch>=’a’ && ch<=’z’
數(shù)字:一個(gè)字符(char)ch?ch>=’0’ && ch<=’9’
1)思路分析和偽代碼
???a、字符如何比較大小,在字母表中的先后順序;字符本身在計(jì)算機(jī)中的內(nèi)存中用數(shù)字來描述的。
???b、可以將字符串轉(zhuǎn)成字符數(shù)組,然后循環(huán)比較它的范圍,如果在'a'-'z',這就是小寫字母;如果在'A'-'Z'這是大寫字母,在'0'-'9'返回就是數(shù)字。外面用幾個(gè)計(jì)數(shù)器來計(jì)數(shù)就可以了
2)編碼實(shí)現(xiàn)
public class StringTest2 {
????public static void main(String[] args) {
????????String s="12CRcyuAdwDF09Km";
????????//1、將字符串轉(zhuǎn)成字符數(shù)組
????????char[] chars = s.toCharArray();
????????//2、定義3個(gè)計(jì)數(shù)器
????????int m=0;//計(jì)數(shù)小寫字母
????????int n=0;//計(jì)數(shù)大寫字母
????????int k=0;//計(jì)數(shù)數(shù)字
????????for (char c:chars){
???????????if(c>='a'&&c<='z'){
???????????????m++;
???????????}
????????????if(c>='A'&&c<='Z'){
????????????????n++;
????????????}
????????????if(c>='0'&&c<='9'){
????????????????k++;
????????????}
????????}
????????System.out.println("小寫字母:"+m+"?大寫字母:"+n+"?數(shù)字:"+k);
????}
}
5.?
StringBuffer和StringBuilder
問題:String作為字符串使用已經(jīng)可以滿足我們的需要,為什么還會(huì)出現(xiàn)現(xiàn)在的這個(gè)兩個(gè)對(duì)象?
因?yàn)楫?dāng)多個(gè)字符串進(jìn)行連接操作,也就是通過+方法進(jìn)行拼接字符串的時(shí)候,會(huì)在常量池中有有過多的臨時(shí)對(duì)象,這樣內(nèi)存中的垃圾很多,我們要解決該問題。所以出現(xiàn)了字符串緩存對(duì)象。
?
?
5.?
5.1.??相關(guān)知識(shí)要點(diǎn)
1)String 是不可變的,StringBuffer、StringBuilder 是可變的;
2)String 、StringBuffer 是線程安全的,StringBuilder 不是線程安全的。
3)StringBuilder 相較于 StringBuffer 有速度優(yōu)勢(shì),所以多數(shù)情況下建議使用 StringBuilder 類。然而在應(yīng)用程序要求線程安全的情況下,則必須使用 StringBuffer 類
5.2.??StringBuilder的相關(guān)方法
????1)append(),追加到字符串的末位
2)insert() 插入到指定位置
3)delete() 刪除字符串
4)reverse() 反轉(zhuǎn)
/*
????要點(diǎn):
????????1、StringBuilder對(duì)象默認(rèn)是將字符串放到它的字符數(shù)組char[]中的,它的初始的長度是16
????????2、該對(duì)象是可變的,追加的時(shí)候不好在常量池放臨時(shí)對(duì)象,而是放在該對(duì)象的字符數(shù)組中。
????????3、當(dāng)追加的時(shí)候,會(huì)計(jì)數(shù)追加字符串的長度,然后將它+16,作為現(xiàn)在char[]數(shù)組的長度
????????4、該對(duì)象不是字符串,要獲得該對(duì)象的字符串表示,可以用toString()方法獲得字符串
?*/
public class StringBuilderTest {
????public static void main(String[] args) {
?
????????StringBuilder sb=new StringBuilder("abc");
????????//1)append(),追加到字符串的末位
????????sb.append("123").append("456").append("yyy");
????????System.out.println(sb.toString());
????????//2)insert() 插入到指定位置,第1個(gè)參數(shù)是偏移量,也就是偏移幾個(gè)字母追加。第2個(gè)參數(shù)是追加的數(shù)據(jù)
????????sb.insert(1,"zz");
????????System.out.println(sb.toString());
????????//3)delete() 刪除字符串,第1個(gè)參數(shù)是開始索引,第2個(gè)參數(shù)是結(jié)束索引
????????sb.delete(1,3);
????????System.out.println(sb.toString());
????????//4)reverse() 反轉(zhuǎn)
????????sb.reverse();
????????System.out.println(sb.toString());
????}
}
6.?
正則表達(dá)式
6.?
6.1.? 為什么要學(xué)習(xí)正則表達(dá)式?
因?yàn)閷?duì)于某些字符串要進(jìn)行格式的匹配,這樣的需求用傳統(tǒng)拆分字符串然后寫業(yè)務(wù)邏輯的方式去處理,業(yè)務(wù) 邏輯的寫法非常復(fù)雜。正則表達(dá)式可以很方便的做到。而且字符串有專門支持正則表達(dá)式進(jìn)行匹配的方法。我們?cè)谑褂玫臅r(shí)候只要寫正則表達(dá)式,然后調(diào)用字符串的匹配方法就可以完成邏輯的驗(yàn)證操作。
Tip:學(xué)習(xí)的目的:解決字符串的個(gè)性化判斷問題,如果沒有正則表達(dá)式,ifelse就會(huì)無窮無盡
6.2.? 什么是正則表達(dá)式?
又稱規(guī)則表達(dá)式。(英語:Regular Expression,在代碼中常簡(jiǎn)寫為regex、regexp或RE),計(jì)算機(jī)科學(xué)的一個(gè)概念。正則表達(dá)式通常被用來檢索、替換那些符合某個(gè)模式(規(guī)則)的文本。
6.3.? 相關(guān)規(guī)則
A、規(guī)定字符(每一個(gè))出現(xiàn)的內(nèi)容
0-9之間的數(shù)字:\d???[0-9]
字母和數(shù)字:??\w??[a-zA-Z0-9]
取反:^????????比如描述非數(shù)字[^0-9]
出現(xiàn)點(diǎn)號(hào)?????\\.?????
?
B、規(guī)定字符串或者字符出現(xiàn)的頻率(次數(shù))
??0次或者1次
+?1次或者1次以上
*?表示0次或者0次以上
{n} 字符串或者字符出現(xiàn)n次
{n,m} 最少出現(xiàn)n次,最多出現(xiàn)m次
{n,} 出現(xiàn)n次以上包括n次,比如密碼長度超過6位:{6,}
6.4.??String字符串的正則表達(dá)式的方法
1)?matches(正則表達(dá)式),返回值是boolean
2)?replaceAll(字符串,正則),用正則替換字符串中的子串
6.5.??案例6
需求:判斷一個(gè)字符串是否是手機(jī)字符串"13533839778",手機(jī)號(hào)的規(guī)則:
???0.手機(jī)號(hào)的長度必須是11位:{11}
???1.手機(jī)號(hào)的第一位必須是1
???2.手機(jī)號(hào)的第二位:3或4或5或7或8
???3.手機(jī)號(hào)的剩余九位的每一位都必須是數(shù)字
public class RegTest1 {
????public static void main(String[] args) {
????????//1、定義字符串存儲(chǔ)手機(jī)號(hào)
????????String phone="13533839778";
????????//2、定義一個(gè)正則表達(dá)式
????????String reg="1[34578]\\d{9}";
????????//3、利用字符串函數(shù)進(jìn)行匹配
????????boolean result = phone.matches(reg);
????????System.out.println(result);
????}
}
6.6.??案例7
案例:將字符串“abcpof67kkk12kkk5sss”中的數(shù)字變成漢字“我們”
1)思路分析
2)編碼實(shí)現(xiàn)
public class RegTest2 {
????public static void main(String[] args) {
????????//1、定義一個(gè)等待檢查的字符串
????????String s = "abcpof67kkk12kkk5sss";
????????//2、定義一個(gè)正則表達(dá)式
????????String reg="\\d";
????????//3、用字符串的替換方法
????????String s1 = s.replaceAll(reg, "我們");
????????//4、輸出結(jié)果
????????System.out.println(s1);
????}
}
?
?
6.7.??案例8
需求:注冊(cè)的時(shí)候要求用戶輸入郵箱,規(guī)則是:
?1)字母開頭,中間可以是字母數(shù)字下劃線或$.
?2)接著是@
?3)是字母長度不超過10位
?4).和字母長度不超過3位
?5)后面還可以接一個(gè).字母,長度不能超過3位
???編碼驗(yàn)證改郵箱yy_y$_222y@sina.com.cn是否合法
public class RegTest3 {
????public static void main(String[] args) {
????????String email="yy_y$_222y@sina.com.cn";
????????String reg="[a-zA-Z][\\w_$]{5,}@[a-zA-Z]{1,10}(\\.[a-zA-Z]{2,3}){1,2}";
????????boolean result = email.matches(reg);
????????System.out.println(result);
????}
}