你真的了解Java中的String吗(也太菜了)?
时间:2022-07-23
本文章向大家介绍你真的了解Java中的String吗(也太菜了)?,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
背景
我们在开发的时候,在处理字段的时候遇到大量的字符拼接的时候会使用StringBuffer和StringBuild。这是为什么呢?那就是因为String会在每一次创建的时候都会新建一个对象,原来的对象也不会被删除,还有就是说还有StringBuffer和StringBuild有什么区别呢?带着这个疑问我们看一下源码
源码阅读
- 我们先看一下String类
//从类上看,他使用了final关键字,说明这个类是不可以改变的,且继承了Serializable,他是可以被序列化的
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
//还有这个存储我们的字符串的value 也是被final 修饰了所以他这个值是不可以改变的
private final char value[];
- 从上面的源码看出了String里面的存储数据的主类型是不可以变的,那我们在拼接字符串的时候是怎么实现的呢?那这里我们就得看一下String的+“”的实现原理
javac Test 编译文件
javap -c Test 查看虚拟机指令
实验一:纯字符串
public class Test {
public static void main(String args[]) {
String str = "a";
}
}
// 将字符串 a 存入常数池
0: ldc #2; //String a
// 将引用存放到 1 号局部变量中
2: astore_1
3: return
实验二:纯字符串相加
public class Test {
public static void main(String args[]) {
String str = "a" + "b";
}
}
// 将字符串 ab 压入常数池
0: ldc #2; //String ab
2: astore_1
3: return
实验二能够非常明显地看出,编译器在编译时产生的字节码已经将 "a" + "b" 优化成了 "ab",
同理多个字符串的相加也会被优化处理,须要注意的是字符串常量相加。
实验三:字符串与自己主动提升常量相加
public class Test {
public static void main(String args[]) {
String str = "a" + (1 + 2);
}
}
// 将字符串 a3 压入常数池
0: ldc #2; //String a3
2: astore_1
3: return
通过虚拟机指令能够看出,1 + 2 自己主动提升后的常量与字符串常量,虚拟机也会对其进行优化。
- 从上面的分析我们看出的是在+的时候没有引用变量的时候所以会在编译阶段后将java中的String直接拼接好直接存入数据库中去(因为引用变量会在运行时期才会给值)。所以说在运行时是怎样的呢? 这个时候我们再看一下StringBuilder在编译后是怎样的。
String b = new StringBuilder().append("a").append(bb).toString();
- 是不是很惊喜,好的那我们来解释一下为什么呢?正是因为String内部的char数组被修饰了final且是一个基本类型,所以说他这个值是不可以用了。所以需要使用我们的StringBuild来实现字符串在动态运行时的拼接。
- 那么我们也就可以解释,String为什么会比直接使用StringBuild而更多的内存了。因为每一次使用字符串+引用的时候都会进行茶创建StringBuilder对象将原有的StringBuilder对象又拼到现在这个StringBuilder对象。而我们直接使用StringBuilder进行apend的话是在原有的基础上进行添加的。所以说是这个原因。
- 那说到这里了,那它为什么不使用StringBuffer而使用StringBuilder呢?再去看看StringBuffer和StringBuilder的区别是什么?
// 看到这个类也是不能被继承的且继承了AbstractStringBuilder的抽象类
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
………………
}
在这里我们可以看到他是使用了锁的。
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
// 看到这个类我们也可以看到他也继承了AbstractStringBuilder
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/** use serialVersionUID for interoperability */
static final long serialVersionUID = 4383685877147921099L;
/**
* Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuilder() {
super(16);
}
// 这也可以看看,他这块是没有使用Sychronized这把锁的
@Override
public StringBuilder append(String str) {
// 这就是重点他也是使用了AbstractStringBuilder中的apend方法。
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;
}
- 这么对比下来他两最大的区别也就是在他的操作方法上一个有锁一个是没有锁的。那么也就是说为什么StringBuilder了呢?从性能的角度来看StringBUilder虽然不是线程3安全的,但是他的性能是优秀的。并且在String拼接引用变量的时候想想也不会出现有并发安全问题的,因为他是在编译期生成且不会被并发修改的。所以使用StringBuilder而不使用StringBuffer。
总结
- String 是线程安全的,因为他的变量是不可变的,也就是它是一个imutable类。
- String的运行时字符串拼接使用过编译器翻译成StringBuilder实现的
- StringBuilder和StringBuffer的区别就是一个是线程安全的一个是线程不安全的。原因也就是buffer会在操作数据的方法上加锁使其同步操作达到线程安全
- 其中也和HashMap和HashRTable,ArrayLIst和Vector的区别一样。
参考链接
https://www.cnblogs.com/chenlong-50954265/p/5632275.html https://blog.csdn.net/weixin_33713707/article/details/85912589
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- flink实战-使用广播实现报警阈值动态更新
- 浅谈MVC设计模式(示例)
- flink实战-聊一聊flink中的聚合算子
- 浙大版《C语言程序设计(第3版)》题目集 习题11-2 查找星期
- flink实战-模拟简易双11实时统计大屏
- Android Studio首次运行指南
- PAT (Basic Level) Practice (中文)1047 编程团体赛
- 聊聊AWK命令的那些事
- Flink实战-定时器实现已完成订单自动五星好评
- 树状数组-HDU3015 Disharmony Trees
- 放弃fastjson,拥抱Jackson
- Spring入门
- 贪心-HDU1789 Doing Homework again(活动安排问题)
- flink实战-实时计算平台通过api停止流任务
- JAVA初级岗面试知识点——基础篇