Java基础之神奇String类(二)

目录

(三)字符串常量池

(1)常量池思想

(2)直接使用字符串常量进行赋值

(3)通过new创建对象

(4)intern()方法

(四)字符串的不可变性

(1)定义

(2)设置String不可变性的原因

(3)经典面试题

(五)StringBuilder类和StringBuffer类

(1)String->StringBuilder对象转换

(2)StringBuilder->String对象转换

(3) String StringBuilder StringBuffer区别

(4)StringBuilder和StringBuffer的方法


(三)字符串常量池

(1)常量池思想

        "池化"思路:是程序设计中的常用思路,节省内存,提高效率。字符串字面量经常会被重复使用,因此放入常量池,当再次使用该内容时,省去了创建对象,开辟内存的时间,直接复用已有对象。

(2)直接使用字符串常量进行赋值

        存储一系列的字符串对象,当字符串常量第一次出现,且常量池中没有该值字符串对象,就会将该对象置入常量池。

String str="hello";
String str1="hello";

str指向的'"hello"第一次出现,JVM产生该对象并置入常量池。

此时常量池已经有了"hello"的字符对象,JVM直接将池中对象地址赋值给str1,不在产生新对象。

(3)通过new创建对象

        若采用直接赋值的方式申明字符串引用,若常量中存在该对象,则直接返回常量池的字符对象,不会创建新对象。

String str=new String("hello");

这行代码背后的逻辑:每一个字符串字面量都是一个字符串常量,也就是一个字符串对象 。

在堆中开辟一个String类对象的地址空间,并在字符串常量池中开辟一段地址空间,将字面量"hello"放入字符串常量池(上文已经说过字符串字面量经常被重复使用,因此放入常量池)。str1、str2都是直接调用常量池的"hello"。

补充:String str;这个str就是字符串。str="hello"这个就是用字符串字面量初始化字符串str。

(4)intern()方法

        关于intern方法,字符串的intern方法是一个本地方法尝试当前字符串对象置入常量池,若常量池没有该值,则将当前对象置入常量池。若常量池已经包含了该值的对象,则不会将对象置入常量池,intern方法直接返回常量池对应的对象。

实例演练:

public class StringTheory {
    public static void main(String[] args) {
        char []ch=new char[]{'a','b','c'};//堆中开辟空间存放'a','b','c'(0x400)
        String s1=new String(ch);//字符数组不是字符串!!!此处ch不是字面量不会放入字符串常量池
        s1.intern();//此时常量池中没有"abc"这个字符串对象,就会将s1指向的字符串放入常量池(0x100)
        String s2="abc";//此时常量池中有"abc"(0x100)
        //true
        System.out.println(s1==s2);//(0x100==0x100)
    }
}

  关于intern()方法是否接收带来的问题:0x100、0x300表示自定义的对象地址

public class StringTheory {
    public static void main(String[] args) {
        String str="hello";//在字符串常量池中开辟空间,将"hello"(0X100)置入常量池
        String str1="hello";//str1直接引用常量池中的"hello"(0x100)
        String str2=new String("hello");//常量池已经包含了"hello"(0x100),则不会将对象(0x300)置入常量池
        str2=str2.intern();//intern方法直接返回常量池对应的对象(0x100),,用str2接收intern的返回值。指向常量池中的"hello"(0x100)
        System.out.println(str==str1);//true   (0x100==0x100)
        System.out.println(str==str2);//true   (0x100==0x100)
    }
}
public class StringTheory {
    public static void main(String[] args) {
        String str="hello";//在字符串常量池中开辟空间,将"hello"(0X100)置入常量池
        String str1="hello";//str1直接引用常量池中的"hello"(0x100)
        String str2=new String("hello");//常量池已经包含了"hello"(0x100),则不会将对象(0x300)置入常量池
        str2.intern();//intern方法直接返回常量池对应的对象(0x100),但str2(0x300)没有接收
        System.out.println(str==str1);//true   (0x100==0x100)
        System.out.println(str==str2);//flase  (0x100==0x300)
    }
}

(四)字符串的不可变性

(1)定义

        当一个字符串的对象产生之后,他的内容就无法修改,这称之为字符串对象的不可变性

//不可变的变量,就叫常量

final int a=10;

//这里指的是不可变性是指内容不可变,而不是字符串的引用

String str="hello";

str+="world";//+表示字符串的拼接,字符串的引用(指向)发生改变

System.out.println(str);

(2)设置String不可变性的原因

1.方便实现字符串对象池,如果String可变,那么对象池就需要考虑写时拷贝的问题了
2.不可变对象是
线程安全
3.不可变对象更方便缓存hash code,作为key时可以更高效的保存到HashMap

(3)经典面试题

        怎么理解字符串不可变,如何做到内容不可修改?

public final class String
private final char value[];//value字符数组是真正保存字符串内容的

         final修饰引用的数据类型的变量,不能改变的是这个引用的指向不变,至于引用的对象内部如何变化,是可以的。因此字符串对象内容不可变与final修饰没啥关系,final只能确保value的指向不变!字符串对象的内容不可变,本质在于private封装,出了String这个类,外部是无法接触到value的,要想操作这个属性只能使用该类提供的getter()setter()方法。

(补充:被final修饰的变量天然线程安全)

(五)StringBuilder类和StringBuffer类

(1)String->StringBuilder对象转换

        a.通过StringBuilder类的构造方法
        b.通过StringBuilder类的append()方法,调用append方法在当前对象的后面追加任何数据类型
        (javac编译器其实也会将String+=操作优化为StringBuilder类的append操作!)

(2)StringBuilder->String对象转换

        a.调用toString()方法
        b.String ret =sb1.toString()

代码实例:

public class StringBuilderTest {
    public static void main(String[] args) {
        String str="abc";
        //String类变为StringBuilder类
        //方法一
        StringBuilder sb=new StringBuilder(str);
        //方法二
        StringBuilder sb1=new StringBuilder();
        sb1.append(str);
        //StringBuilder类变为String
        sb1.append("123");//append类似于+=
        String ret =sb1.toString();//将StringBuilder类转换成String类
        System.out.println(ret);//abc123
    }
}

(3) String StringBuilder StringBuffer区别

        a.String的内容不无法修改,StringBuilder StringBuffer的对象可以修改,因此我们一般在字符串对象频繁修改的时候使用StringBuilder或StringBuffer类,后两个内容可变,因此提供的方法都是在同一个对象上进行修改。
        b.StringBuilder StringBuffer的用法完全一致,StringBuffer采用同步处理,线程安全,效率低。
        c.StringBuilder采用异步处理,线程不安全,效率高,开发中若不考虑线程安全问题,一般推荐使用StringBuilder类

(4)StringBuilder和StringBuffer的方法

StringBuilder

 

 

 StringBuffer

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小熊爱吃软糖吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值