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效率更高。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- linux 磁盘管理
- linux 安装各个版本nodejs
- python3 使用cookie模拟post实现修改活码内容
- VIM 创建程序文件自动添加头部注释
- 【简记】Linux 计划任务 Crontab
- VS Code 免密登录Linux服务器
- Linux部署私钥实现免密登录
- 搭建Jenkins+tomcat+maven+Gitlab持续部署/回滚系统
- Java--注解
- 如何在 Ubuntu 20.04 上安装 Jenkins
- 在 Linux 下如何检查内存使用率
- 3分钟短文 | MySQL存时间,到底该用timestamp还是datetime?
- js中class的继承的基础用法
- JavaScript 设计模式学习总结与感悟(开发&面试必备)
- 3分钟短文 | PHP多维数组搜索值,就只能for循环?这样写更高效