本文主要是介绍黑马毕向东Java课程笔记(day13-1_13-12):String类——特点,常用功能+StringBuilder+StringBuffer,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1、String类特点
String类是final类,因此其没有子类,不能继承。之前提到的方法区,里面包含了方法的代码、静态数据,常量池也在方法区里面(JDK1.7后常量池移到堆中)。常量池的数据是固定不变的,字符串就在常量池中。
class StringDemo
{public static void main(String[] args) {/*//String有一个空参数的构造方法String(),下面2种创建String类对象的方法是一样的,都是创建一个空的String对象String s = new String();String s1 = "";//s2是一个(String)类类型变量, "abc"是一个对象。字符串是一个特殊的对象!//字符串最大特点:一旦被初始化就不可以被改变。字符串既是一个常量,也是一个对象。String s2 = "abc";s2 = "lll";System.out.println(s2);//结果是“lll”//这种情况下,字符串“abc”并没有变化,还是在内存中,而s2指向了内存中的另一块区域“lll”。s2指向的地址变了,而“abc”对象的内容没有变化。*///这一段参考文章:https://blog.csdn.net/zp357252539/article/details/82758877//视频是10分50秒处的解释//这种形式的赋值存放在常量池中而不是存放在堆中,下一次创建内容相同的String对象s3,仍然会指向该常量池中的内存。s1与s3指向同一个对象。String s1 = "abc";String s2 = new String("abc");String s3 = "abc"; System.out.println(s1==s2);//"=="比较的是内存地址值是否相同(false)System.out.println(s1.equals(s2));//String类复写了Object类中equals方法,该方法用于判断字符串内容是否相同。(true)//s1和s2有什么区别?(见视频13-1,7分钟开始处解释):s1在内存中有一个对象,s2在内存中有2个对象System.out.println(s1==s3);//true}
}
2、String常见功能——获取和
String类适用于描述字符串事物,那么它就提供了多个方法对字符串进行操作。常见的操作如下:
1、获取。1.1 字符串中的包含的字符数,也就是字符串的长度。int length():获取长度。1.2 根据位置获取位置上某个字符。char charAt(int index):1.3 根据字符获取该字符在字符串中位置。int indexOf(int ch):返回的是ch在字符串中第一次出现的位置。(注意,这个方法接受的是我们想获取字符的ASCII码,所以使用int类型)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) :反向索引字符出现的位置。2、判断。2.1 字符串中是否包含某一个子串。boolean contains(str):indexOf(str):可以索引str第一次出现位置,如果返回-1.表示该str不在字符串中存在,所以,也可以用于对指定判断是否包含:if(str.indexOf("aa")!=-1)。 而且该方法即可以判断,又可以获取出现的位置。2.2 字符中是否有内容。boolean isEmpty(): 原理就是判断长度是否为0. 2.3 字符串是否是以指定内容开头。boolean startsWith(str);2.4 字符串是否是以指定内容结尾。boolean endsWith(str);2.5 判断字符串内容是否相同。复写了Object类中的equals方法。boolean equals(str);2.6 判断内容是否相同,并忽略大小写。boolean equalsIgnoreCase();3、转换3.1 将字符数组转成字符串。构造函数:String(char[])String(char[],offset,count):将字符数组中的一部分转成字符串。静态方法:static String copyValueOf(char[]);static String copyValueOf(char[] data, int offset, int count) static String valueOf(char[]):3.2 将字符串转成字符数组。char[] toCharArray():3.3 将字节数组转成字符串。String(byte[])String(byte[],offset,count):将字节数组中的一部分转成字符串。3.4 将字符串转成字节数组。byte[] getBytes():3.5 将基本数据类型转成字符串。static String valueOf(int)static String valueOf(double)//3+"";//String.valueOf(3);这两种方法是一样的,都是将int数据类型转换为String数据类型特殊:字符串和字节数组在转换过程中,是可以指定编码表的。4、替换String replace(oldchar,newchar);5、切割String[] split(regex); 6、子串。获取字符串中的一部分。String substring(begin);String substring(begin,end);//注意end不包含在获取的字段7、转换,去除空格,比较。7.1 将字符串转成大写或则小写。String toUpperCase();String toLowerCase();7.2 将字符串两端的多个空格去除。String trim();7.3 对两个字符串进行自然顺序的比较。int compareTo(string);
相应的测试代码如下:
package pack;
class StringDemo
{public static void main(String[] args) {
// StringDemo.method_get();
// StringDemo.method_is();
// StringDemo.string_trans();
// StringDemo.method_replace();
// StringDemo.method_split();
// StringDemo.method_sub();StringDemo.method_7();}//获取public static void method_get(){String str = "abcdefabcdef";//获取字符串长度
//"字符串str的长度为"+str.length():这一部分相当于一个String类的对象,我们在sop方法里面直接打印obj对象即可打印出相应的内容sop("字符串str的长度为:"+str.length());//获取某个位置上的字符sop("字符串str第3位置上的字符为:"+str.charAt(3));//获取字符与字符串在字符中第一次的位置sop("字符“c”在字符串中第一次出现的位置是:"+str.indexOf('c'));sop("字符串“cd”在字符串中第一次出现的位置是:"+str.indexOf("cde"));//从某个位置开始,获取字符与字符串在字符中的位置sop("从位置3开始,字符“c”在字符串中第一次出现的位置是:"+str.indexOf('c',3));//反向索引字符出现的位置。sop("字符“c”,反向索引字符出现的位置是:"+str.lastIndexOf('c'));}//判断public static void method_is(){String str = "abcdefabcdef";String str1 = "ABCDEFABCDEF";//字符串中是否包含某一个子串sop("str中包含“dd”?"+str.contains("dd"));if(str.indexOf("dd")!=-1)//如果没有查找到“dd”,就返回-1System.out.println("str中包含“dd”");elseSystem.out.println("str中不包含“dd”");//字符中是否有内容sop("str是空的?"+str.isEmpty());//字符串以指定内容开始或者结尾sop("str以ab开头?"+str.startsWith("ab"));sop("str以ab结尾?"+str.endsWith("ab"));//内容是否相等sop(str.equals(str1));sop(str.equalsIgnoreCase(str1));//忽略大小写}//转换public static void string_trans(){char[] arr = {'a','b','c','d','f','g'};//通过构造方法创建字符数组的String对象String s1 = new String(arr);String s2 = new String(arr,2,3);//通过普通方法创建字符数组的String对象String s3 = String.copyValueOf(arr);String s4 = String.copyValueOf(arr, 2, 3);sop(s1);sop(s2);sop(s3);sop(s4);// 将基本数据类型转成字符串String s5 = String.valueOf(2);String s6 = String.valueOf(2.456d);sop(s5);sop(s6);sop(2.5+"");//同样是将int数据类型转换为字符串//将字符串转成字符数组char[] arr2 = s1.toCharArray();//将字符串转成字节数组byte[] arr3 = s1.getBytes();for(int x=0;x<arr3.length;x++){System.out.print(arr3[x]+" ");//97 98 99 100 102 103 :打印abcdef的ASCII码} }//替换public static void method_replace(){String s1 = "hello java";String s2 = s1.replace('l', 'w');//如果要替换的字符不存在,返回的还是原串。sop(s2);//替换字符串String s3 = s1.replace("java", "world");sop(s3);}//切割public static void method_split(){String s = "zhagnsa,lisi,wangwu";String[] arr = s.split(",");//按照“,”将字符串切割为字符串数组,切割后“,”不会存在for(int x = 0; x<arr.length; x++){sop(arr[x]);}}//子串public static void method_sub(){String s1 = "abcdefg";sop(s1.subSequence(2, 5));//从指定位置开始到结尾。如果角标不存在,会出现字符串角标越界异常。(注意这里5位置不包含在子串中)sop(s1.substring(3));sop(s1.substring(0,s1.length()));//获取整个字符串//获取子串也可以实现上面切割的功能,但是要先获取“,”的位置,再一部分一部分获取子串,比较麻烦}//转换,去除空格,比较public static void method_7(){String s1 = " HELLO java ";//大小写转换sop(s1.toLowerCase());sop(s1.toUpperCase());//去除两边空格sop(s1.trim());//对两个字符串进行自然顺序的比较String s2 = "a1c";String s3 = "aaa";//该比较基于字符串中各个字符的 Unicode 值,既ASCII码值sop(s2.compareTo(s3));//-48:第二个字符1的ASCII值是49,a的ASCII值是97,49-97=-48}//我们发现每一次打印都需要写那么多打印的代码,我们干脆将打印的功能封装成方法//由于基本数据类型都有其包装类(除了String),他们都是继承Object类,//因此我们可以使用Object类的对象来表示基本数据类型的对象,这是基本数据类型的向上类型转换public static void sop(Object obj){System.out.println(obj);}
}
3、字符串练习
练习1:实现trim()方法
/*
1、模拟一个trim方法,去除字符串两端的空格。
思路:1)判断字符串第一个位置是否是空格,如果是继续向下判断,直到不是空格为止。结尾处判断空格也是如此;2)当开始和结尾都判断到不是空格时,就是要获取的字符串。*/
package pack;
class StringDemo
{public static void main(String[] args) { String s1 = " hello world ";sop("("+s1+")");sop("("+myTrim(s1)+")");}public static String myTrim(String str){//答案与我的思路是一样的,不过这里使用while循环会比for循环好int start = 0 , end = str.length()-1;//开头结尾用start与end表示更加好//首先start不得小于end否则说明整个str都是空格,那么trim方法也就没有意义。其次判断每一个字符是否为空格,用charAt获取字符while(start<=end && str.charAt(start) == ' ')//我们其实也可以写start++,但是这样while循环没有语句,因此将++设为while循环语句start++;//去除结尾空格也是一样的方法,从结尾判断过来。同样判断start<=endwhile(start<=end && str.charAt(end) == ' ')end--;//我们已经获取到了字符不为空段开头与结尾的下标,用获取子串方法substring(begin,end)return str.substring(start,end+1);//这里end记得+1,因为substring的最后一位不包含在获取的字段}public static void sop(Object obj){System.out.println(obj);}
}
练习2:实现字符串反转与字符串指定部分的反转.
先贴上自己的实现
/*
/*
2、将一个字符串进行反转;将字符串中指定部分进行反转,"abcdefg";abfedcg
思路:1)曾经学习过对数组的元素进行反转。2)将字符串变成数组,对数组反转。3)将反转后的数组变成字符串。4)只要将或反转的部分的开始和结束位置作为参数传递即可。
*/
package pack;
class StringDemo
{public static void main(String[] args) { String s = "abcdefg";sop(s+"部分反转后的结果是:"+reverseString(s,1,4));sop(s+"全部反转后的结果是:"+reverseString(s));}//字符串指定内容反转方法public static String reverseString(String str , int start , int end){char[] arr = str.toCharArray();//将字符串转换为字符串数组arr = arrayReverse(arr,start,end);
// return String.copyValueOf(arr);//当然这里也可以利用构造方法将字符串数组转换为字符串return new String(arr);}//整个字符串反转的方法。这个方法我们可以重载指定内容反转的方法,这样比较方便!注意这种技巧!public static String reverseString(String str){return reverseString(str,0,str.length()-1);//调用字符串指定内容反转方法来实现全部反转的方法。}//数组内容反转的方法(该方法不需要暴露给外面,直接私有)private static char[] arrayReverse(char[] arr , int start , int end){
//(end-start)/2的结果必然是int类型(2个int类型的变量做运算),因此如果start与end的差是1,(end-start)/2结果就是0,因此要加“=”,否则不会转换for(int x=0; x<=(end-start)/2 ; x++){char temp = arr[start+x];arr[start+x] = arr[end-x];arr[end-x] = temp;} //for循环部分不再引入多余变量x,而是直接用start与end表示for(; start<end ; start++,end--){swap(arr,start,end);} return arr;}//交换的方法private static void swap(char[] arr,int x,int y){char temp = arr[x];arr[x] = arr[y];arr[y] = temp;}public static void sop(Object obj){System.out.println(obj);}
}
下面是答案的实现:参考StringTest.java文件,和我的答案差不多!只要注意一般end不算在反转范围内即可。
练习3:取两个字符串中最大相同子串(这一题比较有意思),先上自己的答案:
/*
4、取两个字符串中最大相同子串。第一个动作:将短的那个串进行长度一次递减的子串打印。"abcwerthelloyuiodef""cvhellobnm"思路:1,将短的那个子串按照长度递减的方式获取到。(我们操作长度较小的字符串,这样操作的次数少一点)2,将每获取到的子串去长串中判断是否包含,如果包含,已经找到!。
*/
package pack;
class StringDemo
{public static void main(String[] args) { String s1 = "cdlobn";String s2 = "abcdlobnm";sop("s1与s2的最大相同子串为:"+getMaxSubString(s1,s2));}public static String getMaxSubString(String str1 , String str2){String strMax = null;//创建变量strMax用于保存获取的最长子串,初始值赋值为nullboolean breakSign = false;//设置跳出循环的标志//先取得str1与str2中长度较小者String shorterStr = str1.length()<=str2.length()? str1 : str2 ;//同样的方式取得str1与str2中长度较大者String longerStr = str1.length()>str2.length()? str1 : str2 ;//首先,用外循环的变量x控制每一轮判断的最长子串的长度:x的最大值为shorterStr.length(),最小值应该大于0,x若小于0,判断的最长子串长度为零,便没有意义for(int x = shorterStr.length() ; x>0 ; x--){//接下来,用内存循环变量y控制子串最开始取的位置,y从0开始,而每一次比较的最长子串长度为y+x//y+x的最大值必须小于等于shorterStr.length()for(int y = 0; y+x <= shorterStr.length() ; y++){strMax = shorterStr.substring(y,y+x);if(longerStr.contains(strMax)){
// break;注意!!!因为break只跳出一层循环,因此错误,我们设置一个跳出循环的标志来跳出外层循环breakSign = true;break;//先将跳出循环标记置true,再跳出这层循环}elsestrMax = null;//如果不存在我们必须将strMax重新置null,否则最后比较到不能比较的时候,strMax会变成shorterStr的最后一个字符}if(breakSign == true)break;//当breakSign为true的时候,跳出外层循环}return strMax;}public static void sop(Object obj){System.out.println(obj);}
}
答案的方法
/*
注意:2种方法的区别不大,除了一些小技巧,最大的区别就是在2个for循环的时候变量设置不一样,可以试用答案的方法
*/class StringTest3
{/*练习四。*/public static String getMaxSubString(String s1,String s2){String max = "",min = "";max = (s1.length()>s2.length())?s1: s2;min = (max==s1)?s2: s1;//这里取得最短子串的方法可以参考// sop("max="+max+"...min="+min);for(int x=0; x<min.length(); x++)//这里同样用x来控制每一轮比较子串的长度{//注意这里的技巧:设置一个y用来控制子串开头,而设置一个z用来控制子串的结尾。y与z是同增的,那么每一轮获得的子串长度都是一样的//当z增加到max.length()+1的时候,说明这一轮比较完毕。这里max.length()可以取到,因为下面的substring方法不会取到max.length()的点。for(int y=0,z=min.length()-x; z!=max.length()+1; y++,z++){String temp = min.substring(y,z);sop(temp);if(max.contains(temp))//if(s1.indexOf(temp)!=-1)return temp;//获得最长子串则自接返回。不用break,用break还比较麻烦!}}return "";//没获得子串则返回空字符串,上面的连续break的方法跳出循环太麻烦了,找到直接return,最后没找到就return null就可以。}public static void main(String[] args) {String s1 = "ab";String s2 = "cvhellobnm";sop(getMaxSubString(s2,s1));}public static void sop(String str){System.out.println(str);}
}
4、StringBuffer类
StringBuffer的特点如下:
StringBuffer是字符串缓冲区,是一个容器,长度可变化。因此其可以C create U update R read D delete(增删改查)(CURD)
特点:
1、长度是可变化的,既StringBuffer类字符串可以修改(修改内存中对象的内容),通过append(),insert()等方法修改这块内存区域的内容,对比String,String的对象一当创建便不可以修改,因此String没有这些方法。
2、可以直接操作多个数据类型。(数组一次只能操作一个类型)
3、最终会通过toString方法变成字符串。什么时候使用:当我们要操作的数据类型不确定,数据个数不确定,最后要变成字符串,那么StringBuffer缓冲区是最方便的!1、存储。StringBuffer append():将指定数据作为参数添加到已有数据结尾处。StringBuffer insert(index,数据):可以将数据插入到指定index位置。2、删除。StringBuffer delete(start,end):删除缓冲区中的数据,包含start,不包含end。StringBuffer deleteCharAt(index):删除指定位置的字符。3、获取。char charAt(int index) int indexOf(String str) int lastIndexOf(String str) int length() String substring(int start, int end) 4、修改。StringBuffer replace(start,end,string);void setCharAt(int index, char ch) ;5、反转。StringBuffer reverse();6、 将缓冲区中指定数据存储到指定字符数组中。void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) JDK1.5 版本之后出现了StringBuilder.StringBuffer是线程同步。
StringBuilder是线程不同步。以后开发,建议使用StringBuilder升级三个因素:
1,提高效率。
2,简化书写。
3,提高安全性。
添加功能
package pack;
class StringDemo
{public static void main(String[] args) { StringBuffer sb1 = new StringBuffer();StringBuffer sb2 = sb1.append("def");sop(sb1.toString());//我们可以通过toString()方法将StringBuffer对象变为字符串String,打印的时候其实也可以直接输出sop(sb2.toString());sop(sb1==sb2);//true//2个的结果都是:def。sb1与sb2指向的是同一个对象(同一块内存)//也就是说,我们不需要再创建一个变量sb2来表示(因为只有一块内存),如下,如果我们想给sb3添加内容,直接调用append添加即可StringBuffer sb3 = new StringBuffer();sop(sb3.append("abc").append("acvdas").append("cdasv"));//调用链:对象调用一个方法还是返回哪个对象,就可以使用这种调用链(也叫做链式编程)//insert()方法StringBuffer sb4 = new StringBuffer("lkjlkj");sop(sb4.insert(3,"hhh"));//insert将第三位置及其以后的内容向后推,将“hhh”从第三位开始插入}public static void sop(Object obj){System.out.println(obj);}
}
删除、获取、修改、反转功能
package pack;
class StringDemo
{public static void main(String[] args) { //删除StringBuffer sb1 = new StringBuffer("abcdefg");
// sb1.delete(1, 4);
// sb1.deleteCharAt(2);//清空缓冲区sb1.delete(0, sb1.length());sop(sb1.toString());//一般都是用StringBuffer的方法先操作内存,再用toString()方法打印//获取较为简单,与String内容类型不多说//修改StringBuffer sb2 = new StringBuffer("abcdefg");sb2.replace(1, 4, "hhh").append('a');//返回StringBuffer类,可以使用调用链sb2.setCharAt(3, 'k');//返回void,不可以使用调用链sop(sb2.toString());//对于使用完还返回StringBuffer类的方法,他们并不会新增一块内存区域,还是操作原来的对象,那么他们就可以使用调用链//反转StringBuffer sb3 = new StringBuffer("abcdefg");sb3.reverse();sop(sb3.toString());//将缓冲区中指定数据存储到指定字符数组中StringBuffer sb4 = new StringBuffer("abcdefg");char[] arr = {'1','2','3','4','5','6','7','8','9'};sb4.getChars(1, 4, arr, 6);//获取sb4的1,2,3位的字符,并将其存储到字符串数组arr的6角标开始的位置for(int x=0; x<arr.length; x++){sop(arr[x]);}}public static void sop(Object obj){System.out.println(obj);}
}
5、StringBuilder类
一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。
一般单线程我们使用StringBuilder类,多线程使用StringBuffer,多线程也可以使用StringBuilder,我们自己加锁。
Java的升级围绕3个部分:提高效率、简化书写、提高安全性
6、字符串相关重要知识补充
关于String字符串2种创建方法所创建对象在内存中的分配方式,见如下文章:文章1
需要注意的一点是jdk7之前是常量池是在方法区(永久代)中,之后的版本常量池(包括字符串池)则移到了堆中。
另外,假如说的有String m = “abc”; ,这时的abc常量被保存在常量池中,如果我要在后面继续拼接一个d,也就是 m = m+“d”; 拼接成一个新的字符串常量,这时候就会在常量池中创建三个字符串常量,也就是说,这三个字符串常量就是adc、和我们拼接的d,和拼接之后adcd,所以说非常消耗内存的,我刚刚说的显示的字符常量存在于常量池里,而new 出来的String对象则存在于堆中。
关于字符串的拼接,还可以参考如下文章:
文章2
String常量池与运行时常量池
字符串常量池,Class常量池、运行时常量池
注意下面图片,“a”、“b”、“c”、“ab”、“abc”都是独立的数组,虽然他们存放在常量池中,但是最后会创建多个数组(字符串)。但是现在编译器会优化,直接将全部是字符串值的字符串自动视为一个字符串,既只有一个数组。
再下面是StringBuilder的图解
字符串常量池的分析——见就业班-day08-03视频。
从JDK1.7开始,字符串常量池在堆里面,而Class常量池与运行时常量池仍然是在方法区。而且字符串常量池中保存字符串对象也是底层字节数组的地址值。具体图解如下:
String类的相关方法说明
首先是String方法
public boolean equals(Object obj):参数可以是任何对象,只有参数是一个字符串并且内容相同的才会给true;否则返回false。
注意事项:
1. 任何对象都能用Object进行接收。
2. equals方法具有对称性,也就是a.equals(b)和b.equals(a)效果一样。
3. 如果比较双方一个常量一个变量,推荐把常量字符串写在前面。
推荐:"abc".equals(str) 不推荐:str.equals("abc"),原因如下代码:String str5 = null;
System.out.println("abc".equals(str5)); // 推荐:false
//System.out.println(str5.equals("abc")); // 不推荐:报错,空指针异常NullPointerExceptionpublic boolean equalsIgnoreCase(String str):忽略大小写,进行内容比较。
其次是split()方法分割字符串的方法:
public String[] split(String regex):按照参数的规则,将字符串切分成为若干部分。注意事项:
split方法的参数其实是一个“正则表达式”,今后学习。
今天要注意:如果按照英文句点“.”进行切分,必须写"\\."(两个反斜杠)
这个"\\."在正则表达式中表示".",如果只加一个"\",就会被认为是转义字符,再加一个"\",2个"\"加一个"."就表示是一个"."String str3 = "XXX.YYY.ZZZ";
String[] array3 = str3.split(".");//应该写"\\."
System.out.println(array3.length); // 0
for (int i = 0; i < array3.length; i++) {System.out.println(array3[i]);
}
这篇关于黑马毕向东Java课程笔记(day13-1_13-12):String类——特点,常用功能+StringBuilder+StringBuffer的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!