String,StringBuffer,StringBuilder

String,StringBuffer,StringBuilder

String是final修饰的,不可变得,每次操作都会产生新的对象

String这个类是被final修饰的,里面存的东西不能变,变了的话就会产生新的对对象。

 

jdk9之前是char数组,jdk9之后就是byte数组,这里写的都是关于jdk8的

StringBuffer,和StringBuilder都是在原对象上操作。

StringBuffer是线程安全的StringBuilder线程是不安全的

StringBuffer的方法都是synchronized修饰的。

这俩扩容都是当存的容量大于原来的容量时,才会扩容为原来的2倍加二,是通过Arrays.copyOf

进行复制扩容的;他们俩都是继承AbstractStringBuilder这个类,一char数组存储

 

传进来的minCapacity是原字符串长度加现需要追加的字符串长度,即(当前追加需要改变后的容量)。

为啥每次扩容是2倍,而且还要加2?

传入参数为int,这里万一传入的参数为零,<<相当于乘以2,结果还是零,此时如果初始化数组的时候必然报错,所以为了安全考虑,此处加2,加2避免左移一位还是0这样的问题,还有就是当开始传入的字符串长度较小时,j加2可以提高扩容效率,减少扩容次数。如果扩容后大小还不计划改变后的容量小,那么直接将要改变后的大小的值给给现在需要扩容的。

扩容左移一位的(*2),底层都是2进制的,左移一位是因为位运算比较快

append方法会去判断是否需要扩容,如果字符串的长度大于扩容后的,那么这个新扩容的字符串大小为传进来的字符串大小。

为啥默认容量是16?

Stringbuilder的有参构造:

 

父类的有参构造:

 

次时容量为我们传入的字符串长度+16

但是输出此时存有字符串长度时,我们输出的是已存数据的长度

子类中

public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }
public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

父类中

public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

此时若输出字符长度的话,输出的是count(原来数组长度)+len(传进来的数组长度),及所存字符串的长度,

StringBuilder 和StringBuffer 一样的只是StringBuffer 里面的方法加锁了

字符串的拼接采用的都是append方法

性能:**StringBuilder > StringBuffer > String

使用场景:经常需要改变字符串内容时使用StringBuilder,StringBuffer

优先使用 StringBuilder,多线程使用共享变量时使用StringBuffer


==和equals的区别

==对比的是栈的的值,基本数据类型是变量值,引用类型是堆中内存对象的地址。

equals:object中默认也是采用==比较,通常会重写(String中已经帮我们重写了quals方法,将字符串中的每一个字符取出来取对比,看是否相等)

堆中有特殊的区域叫常量池,String s1="hello" hello会在常量池中去分配内存。通过new 来创建的对象是会分配在堆中 s1在栈中存的是内存地址。String s2=s1;赋值赋的是引用地址。 字符串==比较比的就是栈的的值,

都是在java内存(ram)中存储数据的地方

堆区(heap):存储的全部是对象,每一个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令):jvm只有一个heap区,被所有线程共享,不存放基本数据类型(byte,short,int,long,folat,double,char,bolean)和对象引用(String s1=new String()此时对象引用为s1),只存放对象本身。

堆得优劣势

优势:堆可以动态的分配内存大小,生存期也不必事先告诉编译器,java中的垃圾收集器会自动收取这些不在使用的数据。

缺点: 由于运行时动态分配内存,读取速度慢。

栈区(stack):每一个线程包含一个stack区,只保存基本数据类型的对象和自定义对象的引用(不是对象),对象都存放在共享heap中;每个栈中的数据(基本数据类型和对象引用)都是私有的,其他栈不能访问; 栈分为3部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)

栈的优势劣势:存取速度比堆要快,仅次于直接位于CPU的寄存器,但必须确定的是存在stack中的数据大小与生存期必须是确定的,缺乏灵活性。单个stack的数据可以共享。

stack:是一个先进后出的数据结构,通常保存方法中的参数,局部变量。在java中,所有基本类型和引用类型都在stack中储存,栈中数据的生存空间一般在当前scopes内

栈的用法:

栈本身没有add,peek这些都是继承父类vector的。

栈自己有push,和pop,

栈的pop和peek,都是弹出,但是pop弹出后会删除栈顶的元素,而peek不会改变栈的值(不会删除栈顶元素)

栈的push在压入成功后会返回当前压入的对象,而add成功后会返回ture。

 

方法区:

1.又叫静态区,根堆一样,被所有的线程共享。方法去包含多有的class和static变量;

2.方法去中包含的都是在程序中唯一的元素。

java中流中不同存储数据的地方

1.寄存器

2.栈

3.堆

4.静态存储

5.常量存储

6.非RAM存储。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值