对于String类的理解

1.首先明确一下变量与常量

(1)变量:地址不变,值可以改变,如int i = 10; i = 9;i指向的那个地址没有改变,但是那个地址的存放的值由10变为了9,从而i的值变成了9(基本数据类型存放的是本身的值

(2)常量:地址若不改变,值就不会改变,若想值改变,则地址需要改变(值一变,就不是同一个地址上的对象了)

2.现在来到正题:String类

需要明确的是String不是基本数据类型,是引用类型,即储存的是Strng对象的地址,不是String的内容值

String类是不可变的,也就是说是一个常量-----地址不变,值也不会变。String的底层实际是final char[](char[]一被初始化,大小就确定下来了,不会再改变

如执行代码 String s ="abc",就会在堆中创建一个对象“abc”,这个对象的地址和内容是不会变的,s引用指向了该对象,若再执行代码 s="123",则在堆中又会创建一个对象,s重新指向了该对象(s指向的地址已经改变了),但是“abc”对象还在,地址也没有改变,只是s不再指向该对象了。(实际上还有String常量池,当某字符串不是第一次出现时,会引用常量池的字符对象,如当执行s="123"时,会先在常量池找是否存在该对象,没有才会创建“123”这个对象,值得一提的是,java8字符串常量池位于jvm运行时数据区的堆区,其他如类静态常量则是位于方法区)

3.那么为什么String要被设计成不可变呢

其实是因为安全问题。比如要在原来的字符串的基础上拼接几个字符,如果是可变的,原来的字符串就会被改变,如果是不可变的,原来的字符串就不会改变,只是创建了一个新的对象而已。假如在HashMap中如果键是可变的字符串,问题就严重了。如键为某个基准字符如“param”上拼装一个增长的字符,如1,2,3,如果"param"是可变的,name拼装第一次是"param1",第二次就是"param12”,第三次就是"param123”......

//使用key去拼接一个新key,结果原来的key改变了

     //使用StringBuilder对象为key(StringBuilder是可变字符串)
		StringBuilder base = new StringBuilder("base");
		HashMap<StringBuilder,String> map = new HashMap<StringBuilder,String>();
		map.put(base,"value");
		//获取key
		Set<StringBuilder> keySet = map.keySet();
		keySet.forEach((item)->{
			//先输出之前map里面的key,打印结果为"base"
			System.out.println(item.toString());
			//以之前的key为标准拼接出一个新的key
			StringBuilder newKey = item.append("B");});
         //输出原本的key,打印结果变成了baseB
		keySet.forEach((item)->{
			System.out.println(item.toString());});
		
 //使用value来拼接一个新的字符串,拼接完后,原来存在map中的value改变了

		StringBuilder stringBuilder = new StringBuilder("base");
		HashMap<String,StringBuilder> map = new HashMap<String,StringBuilder>();
         //使用可变的字符串为value存储一个基值
		map.put("base",stringBuilder);
		System.out.println(map.get("base"));//此时base对应的值为"base"
		StringBuilder base = map.get("base");
		StringBuilder baseId = base.append("Id");//拿出base对应的value值,拼接出baseId
		System.out.println(map.get("base"));//打印原来的base基本值,结果变为了"baseId"
		

4.另外:

StringBuffer与StringBuilder是可变的(底层会拷贝数组,通过数组扩容来实现可变),可以通过append方法拼接字符串,但是前者是线程安全的,因为前者的append方法有synchronized修饰,而后者没有,所以也就造成了前者性能没有后者好,前者适合高并发场景,后者适合单线程(String类是线程安全的,因为是底层char数组是用final修饰的,说明该类是不可变的,也就是相当于多实例,每一次修改都会生成一个新实例,当然线程安全!)

StringBuffer与StringBuilder的默认容量是传入的字符串参数长度+16

最后:附上后端技术交流圈,欢迎各位大佬入圈交流.......(先添加好友后拉群,添加好友时请备注:小白不黑)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值