Java学习之String、StringBuffer、StringBuilder
String
我们知道字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串我们使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串。
Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。
所谓静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间。
而运行时常量池,则是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。
注意:
1、String源码中可以看出,String底层实际是通过Char【】来保存字符。
2、new String("A") 和 “A ”是不一样的,虽然这种情况可能取得常量池的数据是一样的,但是只要关键字new,就会创建新对象(位置在堆中),例如:
public static void main(String[] args) {
String s1 = "A";
String s2 = "A";
String s3 = new String("A");
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
}
3、因为字符串存在常量池,不需要创建对象,所以"A"+"B"这种计算在编译时即可识别。如果通过 “+”来连接两个String对象,则无法在编译时被识别,而且过程涉及到新对象的创建(即新的引用地址)。
public static void main(String[] args) {
String s1 = "B";
String s2 = "AB";
String s3 = "A"+s1;
System.out.println(s2 == s3);//false
}
public static void main(String[] args) {
String s1 = "B";
String s2 = "AB";
String s3 = "A"+s1;
String s4 = new String("AB");
System.out.println(s2 == s3);//false
System.out.println(s2 == s4);//false
System.out.println(s3 == s4);//false
}
4、关于String.intern()
intern方法使用:一个初始为空的字符串池,它由类String独自维护。当调用 intern方法时,如果池已经包含一个等于此String对象的字符串(用equals(oject)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回此String对象的引用。
它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
补充:equals 和 ==
(1)对于==,如果作用于基本数据类型的变量(byte,short,char,int,long,float,double,boolean ),则直接比较其存储的"值"是否相等;如果作用于引用类型的变量(String),则比较的是所指向的对象的地址(即是否指向同一个对象)。
(2)equals方法是基类Object中的方法,因此对于所有的继承于Object的类都会有该方法。在Object类中,equals方法是用来比较两个对象的引用是否相等,即是否指向同一个对象。
(3)对于equals方法,注意:equals方法不能作用于基本数据类型的变量。如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;而String类对equals方法进行了重写,用来比较指向的字符串对象所存储的字符串是否相等。其他的一些类诸如Double,Date,Integer等,都对equals方法进行了重写用来比较指向的对象所存储的内容是否相等。
摘抄自:https://www.cnblogs.com/xiaoxi/p/6036701.html
StringBuffer&StringBuilder
StringBuffer和StringBuilder都是继承AbstractStringBuilder的类,默认初始容量为16。和String不一样的是,String存在于常量池中,而StringBuffer和StringBuilder是对象,都需要new出来,只不过可以动态的操作字符串,底层也是动态Char[] 。
注意:
1、扩容机制StringBuffer和StringBuilder在调用方法:append()时都会计算一次添加数据后的容量"L1",然后与初始的容量"L0"进行比较,看容量是否溢出,如果溢出则进行扩容.
扩容后的容量为 L0 * 2 + 2(即原始容量的2倍,再加2),如果扩容后的容量还是不够用,就把添加数据时计算的容量"L1"置为新的容量。
//StringBuilder的append()
public StringBuilder append(String str) {
super.append(str);
return this;
}
//StringBuffer的append()
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
//调转至父类AbstractStringBuilder的append()
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
return appendNull();
int len = sb.length();
ensureCapacityInternal(count + len);
sb.getChars(0, len, value, count);
count += len;
return this;
}
private void ensureCapacityInternal(int minimumCapacity) {
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
}
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0)
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
}
2、StringBuffer是线程安全的,StringBuilder线程不安全。从源码中可以看出,StringBuffer的大部分方法都用了synchronized关键字加锁,所以保证了线程安全,当然因为有锁,所以效率上会比StringBuilder差。
//StringBuffer
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
//StringBuilder
public StringBuilder append(String str) {
super.append(str);
return this;
} //StringBuffer
public synchronized StringBuffer delete(int start, int end) {
toStringCache = null;
super.delete(start, end);
return this;
}
//StringBuilder
public StringBuilder delete(int start, int end) {
super.delete(start, end);
return this;
} //StringBuffer
public synchronized StringBuffer replace(int start, int end, String str) {
toStringCache = null;
super.replace(start, end, str);
return this;
}
//StringBuilder
public StringBuilder replace(int start, int end, String str) {
super.replace(start, end, str);
return this;
}
效率对比:
public static void main(String[] args) {
String s1 = "";
StringBuilder builder = new StringBuilder(2000);
StringBuffer buffer = new StringBuffer(2000);
long t1 = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
s1 += i;
}
long t2 = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
builder.append(i);
}
long t3 = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
buffer.append(i);
}
long t4 = System.currentTimeMillis();
long time1 = t2 - t1;
long time2 = t3 - t2;
long time3 = t4 - t3;
System.out.println("String的操作时间 " + time1);
System.out.println("StringBuilder的操作时间 " + time2);
System.out.println("StringBuffer的操作时间 " + time3);
}
总结:
1、String操作比较方便但是仅限于少量字符串的添加,无法直接进行删减和更改,如果操作大量字符串则选用StringBuilder或者StringBuffer。
2、因为StringBuffer线程安全,在需要保证线程安全时只能用StringBuffer。
3、在需要进行大量字符串操作又不需要考虑线程安全时选StringBuilder。
Java学习之String、StringBuffer、StringBuilder的更多相关文章
- Java学习笔记--String StringBuffer StringBuilder
String StringBuffer StringBuilder String http://docs.oracle.com/javase/7/docs/api/ 中文: http://www.cn ...
- Java学习之String StringBuffer StringBuilder区别
1.String:对象长度是不可变的,是线程安全. 2.StringBuffer:对象长度是可变的,是线程安全. 3.StringBuilder:对象长度是可变,不是线程安全.
- 【Java基础】String StringBuffer StringBuilder
String String是不可变的 我们都知道String不是基本数据类型,而是一个对象,并且是final类型的,不可变的.(public final class String) 查看以下代码: S ...
- 浅谈 Java 字符串(String, StringBuffer, StringBuilder)
我们先要记住三者的特征: String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全) 一.定义 查看 API 会发现,String ...
- 重温java中的String,StringBuffer,StringBuilder类
不论什么一个系统在开发的过程中, 相信都不会缺少对字符串的处理. 在 java 语言中, 用来处理字符串的的类经常使用的有 3 个: String.StringBuffer.StringBuilder ...
- Android/Java 中的 String, StringBuffer, StringBuilder的区别和使用
Android 中的 String, StringBuffer 和 StringBuilder 是移动手机开发中经常使用到的字符串类.做为基础知识是必须要理解的,这里做一些总结. A.区别 可以从以下 ...
- 在JAVA中,String,Stringbuffer,StringBuilder 的区别
首先是,String,StringBuffer的区别 两者的主要却别有两方面,第一是线程安全方面,第二是效率方面 线程安全方面: String 不是线程安全的,这意味着在不同线程共享一个String ...
- Java基础知识 String StringBuffer StringBuilder三者的区别(面试题)
相同点:String.StringBuffer.StringBuilder最终底层存储与操作的都是char数组,StringBuffer和StringBuilder都继承了AbstractString ...
- java 基础 5 String StringBuffer StringBuilder
String是不可变的,原因 1是可以缓存hash值,因为String的hash值经常被使用,例如String用作HashMap等.不可变特性 使得hash值不变,因此只需要进行一次计算: 2Str ...
- 探秘Java中的String、StringBuilder以及StringBuffer
探秘Java中String.StringBuilder以及StringBuffer 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问 到的地方,今天就来和大家一起学习 ...
随机推荐
- jsp路径
访问静态资源的时候${pageContext.request.Context}没有作用,在浏览器F12调试的时候发现,路径并没有被解释为项目的根路径,而是没有解释出来,还是${pageContext. ...
- Spring注解开发系列Ⅲ --- 生命周期
Bean的生命周期 Spring Bean 的生命周期在整个 Spring 中占有很重要的位置,掌握这些可以加深对 Spring 的理解. 首先看下生命周期图: 再谈生命周期之前有一点需要先明确: S ...
- 下载 安装MYsql 服务器
摘自 https://blog.csdn.net/youxianzide/article/details/85319106 https://www.2cto.com/database/201805/7 ...
- AWS 入门使用
AWS官方参考文档:https://docs.aws.amazon.com/s3/index.html AWS基本介绍:https://docs.aws.amazon.com/zh_cn/Amazon ...
- NetModular 新年第一更以及升级指南(打造简单易用的.Net Core模块化快速开发框架~)
先给大家拜个晚年,祝大家身体健康,远离肺炎~ NetModular开源已有一年,在这一年收到了很多建议,框架也变得越来越完善.这次更新包括了从去年年尾到现在所做的更改,感觉更改的内容还是蛮多的,所以记 ...
- 最小生成树(一)kruskal
今天写一篇关于最小生成树的番外篇,以前写最小生成树总是用的prim,关于kruskal只是知道一些原理,一直也没有时间去学,今天偶然看了一些并查集,才想起了这个算法 会想起刚刚(预)学过的数据结构,来 ...
- [PowerShell]Python虚拟环境激活失败
用Activate.ps1激活还是失效的情况下, 用ISE打开发现路径中的中文乱码了. 所以解决方案有两种, 一是把中文路径改成英文 二是把Activate.ps1脚本用记事本打开另存为ANSI编码即 ...
- 51Nod 1279 扔盘子 (思维+模拟)
题意: 有口井,往里扔盘子,最多扔多少个 n<=5e5, 1s 思路: 如果比较高的地方井口比较小,那么下面的再大也没有用,只需要维护一个单调减的数组然后O(n+m)模拟即可 代码: #incl ...
- angular 控件间的通信
先引入 设置meta元素 http://blog.sina.com.cn/s/blog_51048da70101cgea.html //设置 虚拟窗口的大小等于设备的大小 <meta name= ...
- layui表格增删改查与上传图片+Api
API 控制器1 主要用于增删改查已经反填数据查询 using System; using System.Collections.Generic; using System.Data.SqlClie ...