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中使用得最频繁的类之一,并且又是各大公司面试喜欢问 到的地方,今天就来和大家一起学习 ...
随机推荐
- 深入SpringMVC注解
原文链接:https://blog.csdn.net/chenpeng19910926/article/details/70837756 @Controller 在SpringMVC 中提供了一个非常 ...
- 《ASP.NET Core 高性能系列》关于.NET Core的配置信息的若干事项
1.配置文件的相关闲话 Core自身对于配置文件不是必须品,但由上文分析可知ASP.NET Core默认采用appsettings.json作为配置文件,关于配置信息的优先等级 命令行>环境变量 ...
- 八、django学习之分组查询、F查询和Q查询
分组查询.F查询和Q查询 分组查询 统计每个出版社出版的书籍的平均价格 第一种方式 obj = models.Book.objects.values('publishs_id').annotate(a ...
- WTL Hello World
构建最简单的WTL Hello World程序,基于:WTL91_5321_Final + VS2013 + WIN7 添加->新建项目 为了简单起见,我们删除一些button和对应的处理代码( ...
- mod3 如何用硬件实现
今天接到Qualcom 的电话面试,表现很一般.Qualcom 不愧是一流的IC 设计公司,问得问题非常基础,但是非常深入! 其中问了一个如何实现模3 的问题.没有回答上来. 后来想了一下,其实非常简 ...
- 2019icpc南京网络赛 A The beautiful values of the palace(离线+树状数组)
题意: (假设所有的点对应的值已经求出)给你一个1e6*1e6的矩阵,有m<=1e5个点有值,其余都为0 q<=1e5个询问,求子矩阵的权值和 思路: 根据二维差分,对于询问左下角(x1, ...
- mixin很难吗?
实践类工作经常会遇到这样的问题,有些概念会用不会说,最近在学习Dart,遇到mixin便是如此.读了几篇网文总觉得良莠不齐,一群码友也说越读越懵,索性静下心来重新出发,一点一滴地弄明白.记录下来分享给 ...
- PaddleBook的部署安全性问题
作为一个学习paddle的新手,按照官方流程全套走一波是很有必要的. 按照官方的推荐,首先得安装一个PaddleBook. 然而,我在自己vps上安装好后,输入 http://myvps:8888,直 ...
- ajax 解决中文乱码问题
最近遇到了ajax 中文乱码的问题.下面总结一下 1. HTTP协议的编码规定 在HTTP协议中,浏览器不能向服务器直接传递某些特殊字符,必须是这些字符进行URL编码后再进行传送.url编码遵循的规则 ...
- 【转】Android之四大组件、六大布局、五大存储
文章来自:http://blog.csdn.net/shenggaofei/article/details/52450668 一.四大组件: Android四大组件分别为activity.servic ...