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的更多相关文章

  1. Java学习笔记--String StringBuffer StringBuilder

    String StringBuffer StringBuilder String http://docs.oracle.com/javase/7/docs/api/ 中文: http://www.cn ...

  2. Java学习之String StringBuffer StringBuilder区别

    1.String:对象长度是不可变的,是线程安全. 2.StringBuffer:对象长度是可变的,是线程安全. 3.StringBuilder:对象长度是可变,不是线程安全.

  3. 【Java基础】String StringBuffer StringBuilder

    String String是不可变的 我们都知道String不是基本数据类型,而是一个对象,并且是final类型的,不可变的.(public final class String) 查看以下代码: S ...

  4. 浅谈 Java 字符串(String, StringBuffer, StringBuilder)

    我们先要记住三者的特征: String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全) 一.定义 查看 API 会发现,String ...

  5. 重温java中的String,StringBuffer,StringBuilder类

    不论什么一个系统在开发的过程中, 相信都不会缺少对字符串的处理. 在 java 语言中, 用来处理字符串的的类经常使用的有 3 个: String.StringBuffer.StringBuilder ...

  6. Android/Java 中的 String, StringBuffer, StringBuilder的区别和使用

    Android 中的 String, StringBuffer 和 StringBuilder 是移动手机开发中经常使用到的字符串类.做为基础知识是必须要理解的,这里做一些总结. A.区别 可以从以下 ...

  7. 在JAVA中,String,Stringbuffer,StringBuilder 的区别

    首先是,String,StringBuffer的区别 两者的主要却别有两方面,第一是线程安全方面,第二是效率方面 线程安全方面: String  不是线程安全的,这意味着在不同线程共享一个String ...

  8. Java基础知识 String StringBuffer StringBuilder三者的区别(面试题)

    相同点:String.StringBuffer.StringBuilder最终底层存储与操作的都是char数组,StringBuffer和StringBuilder都继承了AbstractString ...

  9. java 基础 5 String StringBuffer StringBuilder

    String是不可变的,原因 1是可以缓存hash值,因为String的hash值经常被使用,例如String用作HashMap等.不可变特性  使得hash值不变,因此只需要进行一次计算: 2Str ...

  10. 探秘Java中的String、StringBuilder以及StringBuffer

    探秘Java中String.StringBuilder以及StringBuffer 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问 到的地方,今天就来和大家一起学习 ...

随机推荐

  1. PTA 练习 7-24 喊山 (30 分)

    7-24 喊山 (30 分) 喊山,是人双手围在嘴边成喇叭状,对着远方高山发出"喂-喂喂-喂喂喂--"的呼唤.呼唤声通过空气的传递,回荡于深谷之间,传送到人们耳中,发出约定俗成的& ...

  2. ZJU-Reactor Cooling(无源汇有上下界最大流)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2314 Reactor Cooling Time Limit: 5 ...

  3. C# LINQ查询表达式用法对应Lambda表达式

    C#编程语言非常优美,我个人还是非常赞同的.特别是在学习一段时间C#后发现确实在它的语法和美观度来说确实要比其它编程语言强一些(也可能是由于VS编译器的加持)用起来非常舒服,而且对于C#我觉得他最优美 ...

  4. learn more ,study less(二):整体性学习技术(下)

    随意信息的处理 随意信息,或者内容太多.太复杂的信息,都不容易理解,它们需要不同的技术.假 如你发现联想法不能帮助你理解材料,或者需要花费的时间太长,这时候处理随意信息的方 法就很适合了. 这些处理随 ...

  5. vue 新建脚手架项目npm命令

    使用国外原镜像 npm install -g @vue/cli   //yarn global add @vue/cli            使用淘宝镜像 cnpm install -g @vue/ ...

  6. Nodejs实战系列:数据加密与crypto模块

    博客地址:<NodeJS模块研究 - crypto> Github :https://github.com/dongyuanxin/blog nodejs 中的 crypto 模块提供了各 ...

  7. mybatis从数据库中取数据且分组,返回分组数据

    mapper.xml文件 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PU ...

  8. shell命令之一天一见:awk

    AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一. 这种编程及数据操作语言(其名称得自于它的创始人阿尔佛雷德·艾侯.彼得·溫伯格和布萊恩·柯林漢姓氏的首个字 ...

  9. 机器学习(ML)十之CNN

    CNN-二维卷积层 卷积神经网络(convolutional neural network)是含有卷积层(convolutional layer)的神经网络.卷积神经网络均使用最常见的二维卷积层.它有 ...

  10. 11g与12c启动,关闭RAC

    oracle11g 关闭,启动顺序 1.关闭数据库(oracle)srvctl stop database -d rac 2.关闭集群(root)crsctl stop cluster -all 3. ...