Java字符串String剖析

在Java中关于字符串的处理可以说是五花八门,也是在使用Java过程中一个非常重要的基础知识。
字符串一共有此几类:StringStringBuilderStringBuffer,还有极少用的StringJoiner。接下来介绍一下String。

String算是最基础的引用数据类型的字符串格式,初始化常用的方式有:

1. 
String s = “abc”;
2. 
char[] charArray = {'H', 'e', 'l', 'l', 'o'};
String str = new String(charArray); 	// "Hello"
3. 
char[] charArray = {'H', 'e', 'l', 'l', 'o'};
String str = new String(charArray, 0, 2); 	// "He"
4. 
byte[] byteArray = {72, 101, 108, 108, 111}; // 对应 ASCII 码的 "Hello"
String str = new String(byteArray); // "Hello" 
5. 
byte[] byteArray = {72, 101, 108, 108, 111}; // 对应 ASCII 码的 "Hello"
String str = new String(byteArray, 0, 3); // "Hel"
6. 
StringBuilder stringBuilder = new StringBuilder("Hello");
String str = new String(stringBuilder); // "Hello"

分点开讲吧:

字符串的创建

String不是基本数据类型,他是java.lang包下的一个类,属于引用数据类型,并且String中的数据是不可变的。

String的创建:

要明白在Java中,String的创建会储存在堆内存的“串池”中,在创建String时,首先会检测在“串池”中有没有已存在的相同的字符串,如果存在,则会直接指向这个地址值,代码演示是这样的:

String a = “abc”;
String b = “abc”;
System.out.println(a == b);		// 此时是true

有没有想过为什么?这不是理所应当?但是看下面的:

String a = “abc”;
String b = new String(“abc”);
System.out.println(a == b);		// 此时是false

心理活动:为什么呢?这两种内容不都是abc嘛?
答:我们首先要明白一点, == 在java中如果对于引用数据类型使用,比较的是地址值,String正是引用数据类型,此时第二个案例的false充分说明了这一点,对比的是地址而不是内容。
其中的重点就是第二行的字符串b是new出来的,(知识点:new出来的对象会独立在堆内存中开辟一份内存空间)此时并不是在“串池”中,所以此时两个地址自然不一样。所以我们在比较String时一定要使用equals()进行比较。当然,如果你真的想比较地址值那就用 == 。

再看这里:

String a = new String("abc")

问:会创建几个对象?
答案是:1个或2个。
答:因为刚刚说过new是在堆内存中开辟一份新的内存空间,所以自然会有一个对象,但是在new的过程中,是要从“串池”拿数据的。
问:所以为什么从“串池”拿?
答:仔细看,你最后的小括号里是不是有一个字符串”abc”,这个字符串给你做有参构造可不是白做的,你既然写出来了“abc”他就是一个引用数据类型了,会直接在“串池“创建一份存储,再进行有参构造的,所以就是1个或者两个了。当”串池”存在 “abc”直接用,不存在新创一个对象。

字符串的拼接

接下来这里:

String a = “abc”;
String b = “a” + “bc”;
System.out.println(a == b);	// 此时是true

在字符串的拼接过程中的创建原理:
a的初始化就是直接在”串池”里创建一个abc字符串,
当b进行拼接创建时,系统在编译为.class文件时,其实会直接讲第二行变换成:

String b = “abc”;

所以接下来不就明了了,一样的字符串进行创建不会直接创建,而是回去”串池”找有没有相同的,找到了直接指向,所以在这里便是true。
继续:

String a = “abc”;
String b = “a”;
String c = b + “bc”;
System.out.println(a == c);	// 此时是false

内心:刚刚还说拼接就是直接变成”abc”指向“串池”现在咋是false了?
答:注意看,这里是有变量参与了,在拼接过程中如果有变量参与,在Java中String的变量拼接的底层原理中,其实是基于StringBuilder实现的,(这里如果不清除Stringbuilder的可以先去了解一下),此时在源码中会直接在堆内存new一块独立的存储空间进行拼接,所以就解释了为什么这里是false。因为在拼接过程中基于StringBuilder,但是拼接过程中是new出来的,所以又回到上一点了,便是false。

字符串的拼接原理

刚刚说到,String的变量拼接是基于StringBuilder的,所以是将字符串先拆解成一个char[]数组,这样成了基本数据类型,再进行拼接。
在JDK8之前,在拼接时设这样的,看代码:

String a = “a”;
String b = “b”;
String c = “c”;
String d = a + b + c;		// 这里最少创建4个对象
System.out.println(d);

为什么会创建4个对象呢?
首先a + b , a和b各是一个对象, 在第一次拼接时:基于StringBuilder创建出第三个对象S1,这样就是三个对象,此时又进行一次拼接操作,将S1和c进行拼接,这不就又生成一个对象S2存放最终的变量。
但是在JDK8之后,做了一个小优化,就是在拼接之前会对变量进行预估,预估一个大小相符的字符数组用来存储拼接,但是如果拼接数量庞大,那在预估过程中岂不是也会浪费很多时间。所以建议在大量使用拼接操作时直接使用StringBuilder。

  • 17
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值