String的不可变误区???String,StringBuilder和StringBuffer 如何完成对字符串的操作?

前言
字符串就是一连串的字符序列, Java 提供 String,StringBuffer,StringBuilder 3个类来封装字符串,并提供了一系列方法来操作字符串对象。
Java9改进了字符串(包括String. StringBuffer. StringBuilder) 的实现。在Java9以前字符串底层采用char[]数组来保存字符,因此字符串的每个字符占2字节;而Java 9的字符串采用byte[]数组再加一个encoding-flag(编码标识)字段来保存字符,因此字符串的每个字符只占1字节。所以Java9的字符串更加节省空间,但字符串的功能方法没有受到任何影响。.源码截图如下:
在这里插入图片描述
String,StringBuilder,StringBuffer区别

  • String是不可变的
  • StringBuilder,StringBuffer是可变的字符串
  • StringBuilder是线程不安全的
  • StringBuffer是线程安全的

String类
1.final修饰,不可以有子类。源码截图:
在这里插入图片描述
2.“hello” 直接量和 newString(“hello”) 有什么区别呢?
当 Java 程序直接使用形如"hello" 的字符串直接量( 包括可以在编译时就计算出来的字符串值)时,JVM 将会使用常量池来管理这些字符串;当使用 new String(“hello”) 时,JVM 会先使用常量池来管理"hello" 直接量 ,再调用String 类的构造器来创建一个新的 String 对象,新创建的 String 对象被保存在堆内存中。换句话说,new String(“hello”) 共产生了两个字符串对象。

3.字符串不可变

底层代码:final char[] value;

String 类是不可变的, String 的实例一旦生成就不会再改变了,例如如下代码。

  //字符串不可变
	String str5 = new String("hello");
	str5 = str5.concat("!!!");//字符串连接
	System.out.println(str5);//结果为 hello!!!

这里的不可变是指String对象不可变。区分对象和对象的引用:从上述的打印结果看,str5的值确实变了,那怎么还说String对象是不可变的呢?其实这存在一个误区:str5只是一个String对象的引用,并不是对象本身。对象在内存中是一块内存区,成员变量越多,这块内存占的空间就越大。引用只是存放了地址。
也就是说,str5只是一个引用,它指向一个具体的对象,当str5 = str5.concat("!!!");这句代码执行后,又创建了一个新的对象hello!!! ,而str5重新指向了这个对象,原来的对象“hello”还在内存中,并没有改变。内存结构如下图所示:
在这里插入图片描述

4.StringBuilder StringBuffer
char[] value;
5.方法
构造方法

//构造方法
	public static void test1(){
		String str1 = new String();
		byte[] b = {97,98,99};
		//将每个数转成对应的字符,再连接成字符串
		String str2 = new String(b);
		System.out.println(str2);     //abc
		char[] c = {'a','b','c'};
		//字符串底层使用的是char类型数组实现的字符串
		//打印时,自动转成字符串
		System.out.println(new String(c));     //abc
		System.out.println(b);        //[B@15db9742
		System.out.println(c);        //abc
	}

常用方法

		//返回字符串的长度
		//数组使用的是属性,字符串使用的是length()方法
		System.out.println("hello".length());
		//去掉字符串的前后空格
		//trim()方法可用于用户名,密码校验
		System.out.println("  hel  lo ".trim());
		//int compareTo(String anotherString):比较两个字符串的大小。如果两个字符串的字符序列相等,则返回0;不相等时,从两个字符串第0个字符开始比较,返回第一一个不相等的字符差。另一种情况,较长字符串的前面部分恰巧是较短的字符串,则返回它们的长度差。
String s1 = new String( "abcdefghijklmn");
String s2 = new String( "abcdefghij ");
String s3 = new String( "abcdefghijalmn ");
System .out .println( "sl. compareTo(s2) : " + sl.compareTo(s2) ) // 返回长度差
System .out .println( "sl. compareTo(s3): " + sl.compareTo(s3) ) // 返回'k'-'a'的差
        //boolean equalsIgnoreCase(String str):比较字符序列,只是忽略字符的大小写
		System.out.println("abc".equalsIgnoreCase("Abc"));
		// char charAt(int index): 获取字符串中指定位置的字符。
		System.out.println("hello".charAt(2));
		//int indexOf(int ch): 找出 ch 字符在该字符串中第一次出现的位置
		System.out.println("hello".indexOf('e'));
		System.out.println("hello".indexOf("elle"));  //-1
		System.out.println("hello".indexOf("ello"));  //1
		System.out.println("hello".indexOf("l"));
		// int indexOf(String str, int fromIndex): 找出str子字符串在该字符串中从 fromIndex 开始后第一次出现的位置
		System.out.println("helelo".indexOf("l",3));
		//int lastIndexOf(int ch): 找出 ch 字符在该字符串中最后一次出现的位置。
		System.out.println("hello".lastIndexOf("l"));
//int lastIndexOf(String str, int fromIndex): 找找出 str 子字符串在该字符串中从 fromlndex 开始后最后一次出现的位置
		System.out.println("he3llo".lastIndexOf("l",2));
		//> String substring(int beginlndex): 获取从 beginlndex 位置开始到结束的子字符串。
		System.out.println("hello123".substring(2));
		//[2,4)
		System.out.println("hello123".substring(2,4));
		//判断前缀和后缀
		System.out.println("1234566".startsWith("123"));
		System.out.println("afbsdf".endsWith("X"));
		//大小写字符
		System.out.println("aBc".toUpperCase());
		System.out.println("SDad".toLowerCase());
		System.out.println("abcde".contains("cd"));
		//valueOf:用于将基本类型值转换为 String 对象的方法
		System.out.println(String.valueOf(123));
		//char[] toCharArrayO: 将该 String 对象转换成 char 数组。
		char[] c = "abc".toCharArray();
		
		String str2 = new String(" ");
		System.out.println(str2.isEmpty());
	

String类重写了equals,hashCode,toString,以下是String类的源码截图。
在这里插入图片描述

在这里插入图片描述
可见,重写的equals比较的是相同的字符序列

练习题:

 //11.判断回文(回文,从中间开始两边对称)
    String s3="上海自来水来自海上";
    if(isHuiWen(s3)) {
    	System.out.println("是回文");
    }else {
    	System.out.println("不是回文");
    }
   static boolean isHuiWen(String s) {
		int j=s.length()-1;
	 for(int i=0;i<j;i++,j--)
	    {
	    	if(s.charAt(i)!=s.charAt(j)) 
	    		return false;
	    }
	return true;
	}
 //12. 输入一个字符串,统计字符串中字母、数字和其他符号的个数
	public static void test1(){
		int a=0,b=0,d=0;
		Scanner sc = new Scanner(System.in);
		System.out.println("input:");
		String str = sc.next();
		for(int i = 0;i<str.length();i++){
			char c = str.charAt(i);
			if(c>='a'&&c<='z'||c>='A'&c<='Z'){
				a++;
			}else if(c>='0'&&c<='9'){
				b++;
			}else{
				d++;
			}
		}
		System.out.println("字符:"+a+",数字:"+b+",其他 :"+d);
	}
	//13. 输入一个字符串,将其中的数字提取出来并求和
	//adfd1234dfdf56ae2==1,2,3,4,5,6,2 
	//'1'+'2'
	//'1'49-'0' =1
	//'2'50-'0'48=2
	public static void test2(){
		String str = "adfd1234dfdf56ae2";
		int sum = 0;
		for(int i = 0;i<str.length();i++){
			char c = str.charAt(i);
			if(c>='0'&c<='9'){
				sum += c-'0';
			}
		}
		System.out.println(sum);
	}
	//14. 输入一个字符串,将其中的数字提取出来并进行升序排序
	//dsho353sdhiha89dnso4 -> 353894 -> 334589
	public static void test3(){
		
		String str = "dsho353sdhiha89dnso4";
		int index = 0;//表示array数组的索引
		char array[] = new char[str.length()];
		for(int i = 0;i<str.length();i++){
			char c = str.charAt(i);
			if(c>='0'&&c<='9'){
				array[index++] = c;
			}
		}
		array = Arrays.copyOf(array, index);//数组缩容
		Arrays.sort(array);//数组排序
		System.out.println(Arrays.toString(array));
	}
	//15. 输入一个字符串,统计其中每一个字符出现的次数
	//     sdhaofnaadsg -> s:2 d:2 h:1 a:3 o:1 f:1 n:1 g:1
	//        a      a  b     c     d   d
	//boolean{true,true,false,true,true,true}	        
	public static void test4(){
		String str = "sdhaofnaadsg";
		boolean[] b = new boolean[str.length()];
		for(int i = 0;i<b.length;i++){
			if(b[i]){
				continue;//如果记过数的字符,不重复计数
			}
			char c = str.charAt(i);
			int count = 0;
			for(int j = i;j<str.length();j++){
				if(str.charAt(j)==c){
					b[j]=true;//标识元素已经记过数
					count++;//字符的计数器
				}
			}
			System.out.println(c+":"+count);
		}
		
	}
	//16.输入2个字符串,打印第二个字符串在第一个字符串中出现的所有的位置
	//vagaophgao a -> 1 3 8
	//index = indexOf("",index)
	//index++
	public static void test5(){
		String str1 = "vagaophgao";
		String str2 = "a";
		int index = 0;//索引
		while(index<str1.length()){
			
			index = str1.indexOf(str2,index);
			if(index!=-1){
				System.out.println(index);
				index++;
			}else{
				break;
			}
		}
	}
	

StringBuffer对象则代表一个字符序列可变的字符串,当一个StringBuffer 被创建以后,通过StringBuffer提供的append()、insert()、reverse()、setCharAt()、setLength()等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString0方法将其转换为一个String对象。

StringBuilder builder  = new StringBuilder("hello");
		String str = builder.insert(1, "a")
				    .append("123")
		            .delete(1, 3)
		            .reverse()
		            .toString();

StringBuilder类(可变字符串类):字符串内容改变频率高,建议使用此对象

  //不同对象的代码执行效率
		String str = "a";
		long start = System.currentTimeMillis();
		for(int i = 1;i<=10000;i++){
			str+="b";
		}
		long end = System.currentTimeMillis();
        System.out.println(end-start);
        
        start = System.currentTimeMillis();
		StringBuilder str2 = new StringBuilder("a");
		for(int i = 1;i<=10000;i++){
			str2.append("b");
		}
		end = System.currentTimeMillis();
        System.out.println(end-start);

结果:

43
2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值