Java中String、StringBuffer和StringBuilder

浅析Java中的String、StringBuffer和StringBuilder


一、String

String类是final类,即不能被继承,且其成员方法默认为final方法;

String类的方法都不是在原有的字符串上进行操作,而是重新生成一个新的字符串对象,即进行这些操作后原始的字符串没有改变;


二、String、StringBuffer、StringBuilder

1 String str = "hello"; 和 String str = new String("hello"); 的区别

public class Main {
    public static void main(String[] args) {
        String str1 = "hello world";
        String str2 = new String("hello world");
        String str3 = "hello world";
        String str4 = new String("hello world");
         
        System.out.println(str1==str2); // false
        System.out.println(str1==str3); // true
        System.out.println(str2==str4); // false
    }
}

在JVM内存机制中的class文件中有一部分存储编译期间生成的字面常量和符号引用,称为class文件常量池;在运行期间对应着方法区的运行时常量池;

上述代码中String str1 = "hello world"; 和 String str3 = "hello world"; 都在编译期间生成字面常量和符号引用,在运行期间字面常量""hello world"被存储在运行时常量池(只保存一份);通过该方式将String对象跟引用绑定,JVM执行引擎先在运行时常量池中查找是否存在相同的字面常量,若存在则直接将引用指向已存在的字面常量;否则在运行时常量池开辟一个空间来存储字面常量,并将引用指向该字面常量;

通过new关键字生成的对象是在堆内存进行的,而在堆内存进行对象生成的过程是不会检测该对象是否已存在,因此通过new创建对象一定是不同的对象,即使字符串的内容是相同的;


2 String、StringBuffer、StringBuilder

2.1 String和StringBuffer

public class Main {
    public static void main(String[] args) {
        String string = "";
        for(int i=0;i<10000;i++){
            string += "hello";
        }
    }
}

string += "hello";的过程相当于将原有的string变量指向的对象内容取出与"hello"作字符串相加操作,再存入另一个新的String对象当中,再让string变量指向新生成的对象;

该循环结束后new了10000个对象;

public class Main {
    public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder();
        for(int i=0;i<10000;i++){
            stringBuilder.append("hello");
        }
    }
}

该循环结束后只new了1个对象;


2.2 StringBuffer和StringBuilder

StringBuffer和StringBuilder区别在于StringBuffer类的成员方法前有synchronized关键字,在多线程访问时起到安全保护作用,即StringBuffer是线程安全的;


2.3 使用场景

String、StringBuffer和StringBuilder的执行效率是StringBuffer > StringBuilder > String(相对地);

当字符串相加操作或改动较少时,建议使用String;

当字符串相加操作或改动较多时,建议使用StringBuilder;

若采用多线程,建议使用StringBuffer;


三、常见面试题

1 下面这段代码的输出结果?

String a = "hello2";   String b = "hello" + 2;   System.out.println((a == b));

输出为true,因为"hello"+2在编译期间优化成"hello2",因此在运行期间变量a和b指向的是同一对象;


2 下面这段代码的输出结果?

String a = "hello2";    String b = "hello";       String c = b + 2;       System.out.println((a == c));

输出为false,因为有符号引用存在,String c  = b + 2;不会在编译期间优化,即不会将b + 2当作字面常量处理,这种方式生成的的对象保存在堆上,因此a和c指向不同对象;


3 下面这段代码的输出结果?

String a = "hello2";     final String b = "hello";       String c = b + 2;       System.out.println((a == c));

输出为true,因为被final修饰的变量在class文件常量池中保存一个副本,对final变量的访问在编译期间直接替换成真实的值,因此String c = b + 2;在编译期间优化成String c = "hello" + 2;;


4 下面这段代码的输出结果?

public class Main {
    public static void main(String[] args) {
        String a = "hello2";
        final String b = getHello();
        String c = b + 2;
        System.out.println((a == c));
    }
    public static String getHello() {
        return "hello";
    }
}

输出为false,因为虽然b用final修饰,但其赋值是通过方法调用返回的,其值只能在运行期间确定,因此a和c指向不是同一个对象;


5 下面这段代码的输出结果?

public class Main {
    public static void main(String[] args) {
        String a = "hello";
        String b =  new String("hello");
        String c =  new String("hello");
        String d = b.intern();
         
        System.out.println(a==b);
        System.out.println(b==c);
        System.out.println(b==d);
        System.out.println(a==d);
    }
}

输出为false false false true,因为String类的intern方法是本地方法,在Java SE6之前,intern方法在运行时常量池中查找是否存在内容相同的字符串,若存在则返回指向该字符串的引用,若不存在则将字符串入池,返回一个指向该字符串的引用;


6 String str = new String("abc");涉及几个String对象?

2个,因为在类加载过程中,在运行时常量池中创建一个"abc"对象;在执行过程中,在堆上创建一个"abc"对象;


7 下面这段代码1>和2>的区别?

public class Main {
    public static void main(String[] args) {
        String str1 = "I";
        //str1 += "love"+"java";        1>
        str1 = str1+"love"+"java";      //2>
    }
}

1>比2>效率高,因为1>中的"love"+"java"在编译器期间优化成"lovejava",而2>中的不会优化;

在命令行窗口键入"javap -c Main",发现1>中只进行1次append操作,2>中进行2次append操作;




注明:此文章是转载海子的博文,详情见:http://www.cnblogs.com/dolphin0520/p/3778589.html


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源
StringStringBufferStringBuilder都是Java用于处理字符串的类。 String是一个不可变的字符串类,也就是说一旦创建了一个String对象,它的值就不能被修改。每次对String进行修改操作时,都会创建一个新的String对象,这样会浪费内存空间和时间。因此,当需要频繁地对字符串进行修改时,使用String并不高效。 StringBufferStringBuilder是可变的字符串类,它们可以被用来进行字符串的修改操作。StringBufferStringBuilder的主要区别在于StringBuffer是线程安全的,而StringBuilder是非线程安全的。这意味着在多线程环境下,如果有多个线程同时访问一个StringBuffer对象,它们是安全的;而多个线程同时访问一个StringBuilder对象时,可能会导致数据错乱。 使用StringBufferStringBuilder的场景通常是在需要频繁地对字符串进行修改的情况下。例如,在循环拼接字符串、在递归函数修改字符串等情况下,使用StringBufferStringBuilder可以提高性能。 如果需要将StringBufferStringBuilder转换为String对象,可以使用两种方式。一种是调用它们的toString()方法,将其转换为String对象。另一种是使用String的构造器String(StringBuffer buffer)来创建一个新的String对象,将StringBufferStringBuilder的内容复制到新的String对象。 总结起来,String是不可变的字符串类,而StringBufferStringBuilder是可变的字符串类,适用于需要频繁修改字符串的场景。转换为String对象可以通过调用toString()方法或使用String的构造器来实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值