String类中你不知道的知识

直接量创建对象更高效

在Java中,创建一个字符串有两种方法:

//第一种方法
String str1 = "字符串1";
//第二种方法
String str2 = new String("字符串2");

这两种方式创建的字符串在使用上并无区别,但在内存分配方式上完全不同,而且效率大相径庭。下面详细阐述:

第一种方式:

这种方式创建的字符串对象在堆内存中只需要一块存储空间。系统只需在字符串缓冲池中创建该字符串,并将str1指向该字符串对象。

第二种方式:

首先创建String类型的对象,再在字符串缓冲池中创建“字符串2”,并将String类型对象指向“字符串2”,再将str2指向String类型对象。

因此,第一种方式只在堆内存中开辟了一个存储空间,第二种方式在堆内存中开辟了两块存储空间。因此,第一种方式更高效。

在Java中,所有基本数据类型和String类型都有这两种创建对象的方式,我们把第一种方式称为“使用直接量创建对象”。因此,在Java中,使用直接量创建对象更高效!

字符串缓冲池是什么?

它存在于堆内存中,用于存储JVM运行以来所有出现过的字符串对象。

当系统需要创建字符串时,首先判断该字符串是否存在于缓冲池中,若存在则无需创建直接引用,否则创建该字符串。因此,采用直接量方式创建的两个字符串对象是相同的:

String str1 = "字符串";
String str2 = "字符串";
System.out.println(str1==str2);//结果为true!str1和str2均引用字符串缓冲池中的同一个对象

字符串经典面试题

问:下面程序输出结果是什么?

String str1 = "我是个大好人6";
String str2 = "我是个"+"大好人"+6;
System.out.println(str1==str2);

输出结果为true!

等号右侧的两个值均在编译时确定下来,因此它们均引用字符串缓冲池中的同一个对象。

问:下面程序输出结果是什么?

String str1 = "我是个大好人6";
String str2 = "我是个大好人"+"我是个大好人".length();
int len = 6;
String str3 = "我是个大好人"+len;
System.out.println(str1==str2);
System.out.println(str1==str3);

结果均为false!

由于str2和str3中含有变量或调用了函数,所以str2、str3等号右侧的值在运行阶段才能阶段确定下来,因此它们无法利用字符串缓冲池中的“我是个大好人6”。

问:下面程序输出结果是什么?

String str1 = "我是个大好人6";
final int len = 6;
String str2 = "我是个大好人"+len;
System.out.println(str1==str2);

结果为true!

此时len被final修饰,len的值固定为6不会发生变化,因此在编译时可以确定str2等号右侧的值为“我是个大好人6”,因此仍然可以沿用字符串池中的“我是个大好人6”。

问:下列程序在字符串缓冲池中创建了几个常量?

String str = "我是个"+"大好人"+6;

答案为1个!

该字符串中不包含变量和方法,因此在编译时即可确定,编译器看来就是一个完整的常量“我是个大好人6”

问:下列程序在字符串缓冲池中创建了几个常量?

String str = "我是个";
str = str + "大好人";

答案为2个!

在执行第一行代码时,常量池中创建“我是个”,执行第二行代码时,常量池中再创建“我是个大好人”,并切断str与“我是个”的引用,指向“我是个大好人”,而常量“我是个”继续留在常量池中。

    由于缓冲池中的字符串一般不会被垃圾回收,因此通过这种拼接的方式创建的字符串将会在常量池产生很多碎片,而StringBuffer和StringBuilder就是为了这种问题而诞生的!

    如果一个字符串需要不断发生修改,则使用StringBuffer和StringBuilder比String更加高效。

    StringBuilder是线程安全的,因为在其绝大多数方法都是同步方法,但因此其效率较低;

    综上所述,若程序涉及多线程,应选用StringBuilder;若单线程,则选择StringBuffer效率更高。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏JetpropelledSnake

Python入门之装饰器九步学习入门

第一步:最简单的函数,准备附加额外功能 '''示例1: 最简单的函数,表示调用了两次''' def myfunc(): print("myfunc(...

2398
来自专栏about云

spark中 map和reduce理解及与hadoop的map、reduce区别

问题导读 1.你认为map函数可以做哪些事情? 2.hadoop中map函数与Scala中函数功能是否一致? 3.Scala中reduce函数与hadoop中...

2678
来自专栏学海无涯

13.函数

743
来自专栏青枫的专栏

java中驼峰命名和下划线命名互转方法(代码实现)

1453
来自专栏Java学习网

Java面试题系列之基础部分(五)——每天学5个问题

Java基础部分学习的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io的语法,虚拟机方面的语法,这些都是最基...

19710
来自专栏hbbliyong

[Java]读取文件方法大全

1、按字节读取文件内容 2、按字符读取文件内容 3、按行读取文件内容 4、随机读取文件内容  public class ReadFromFile {     /...

3426
来自专栏noteless

[二十一]JavaIO之BufferedReader 与 BufferedWriter

BufferedReader  从字符输入流中读取文本,内部缓冲各个字符,从而实现字符、数组和行的高效读取

831
来自专栏技术与生活

设计模式-迭代子模式

多个对象聚集在一起形成集合的概念,所以集合对象也叫容器,包含 n 多对象的池子一样。集合对象需要提供一些方法,使得可以顺序访问内部对象。集合对象常见的问题分为两...

643
来自专栏Jack的Android之旅

疯狂Java笔记之表达式中的陷阱

上面创建了两个字符串对象,其中一个是“HelloJack”这个直接量对应的字符串对象,另一个是由new String()构造器返回的字符串对象。

441
来自专栏idba

了解Python装饰器

一 装饰器是什么 装饰器是一个用于封装函数或者类的代码工具,显式地将封装器作用于函数或者类上,达到程序运行时动态增加功能的目的。对于函数运行前处理常见前置条件...

766

扫码关注云+社区