黑马毕向东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”,就返回-1
			System.out.println("str中包含“dd”");
		else
			System.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<=end
		while(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用于保存获取的最长子串,初始值赋值为null
		boolean 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,再跳出这层循环
				}
				else
					strMax = 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”都是独立的数组,虽然他们存放在常量池中,但是最后会创建多个数组(字符串)。但是现在编译器会优化,直接将全部是字符串值的字符串自动视为一个字符串,既只有一个数组。
黑马毕向东Java课程笔记(day13-1_13-12):String类——特点,常用功能+StringBuilder+StringBuffer_第1张图片
  再下面是StringBuilder的图解
黑马毕向东Java课程笔记(day13-1_13-12):String类——特点,常用功能+StringBuilder+StringBuffer_第2张图片

  字符串常量池的分析——见就业班-day08-03视频。
  从JDK1.7开始,字符串常量池在堆里面,而Class常量池与运行时常量池仍然是在方法区。而且字符串常量池中保存字符串对象也是底层字节数组的地址值。具体图解如下:
黑马毕向东Java课程笔记(day13-1_13-12):String类——特点,常用功能+StringBuilder+StringBuffer_第3张图片

  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")); // 不推荐:报错,空指针异常NullPointerException

public 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资料)