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. HDU-2647 Reward(链式前向星+拓扑排序)

    Reward Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submis ...

  2. CTF--HTTP服务--SQL注入GET参数

    开门见山 1. 扫描靶机ip,发现PCS 192.168.31.37 2. 用nmap扫描开放端口信息 3. 快速扫描全部信息 4. 探测敏感信息 5. 用浏览器打开用户登录页面 6. 使用OWASP ...

  3. SpringCloud与微服务Ⅹ --- SpringCloud Config分布式配置中心

    一.SpringCloud Config是什么 分布式系统面临的问题 --- 配置问题 微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务.由于每个 ...

  4. java反射API

    反射主要对象 Class Constructor Field Method API-Class 获取Class对象 Object.getClass() className.class Class.fo ...

  5. redis5.0 Cluster集群搭建

    安装redis sudo apt update sudo apt install build-essential tcl cd ~ mkdir document/ cd document/ curl ...

  6. TensorFlow相关博客

    Tensor官方教程 极客学院TensorFlow中文文档 xf__mao的博客

  7. python dict 中的中文处理

    dict1 = {'中':'国 '} print dict1 ##{'\xc3\xa4\xc2\xb8\xc2\xad': '\xc3\xa5\xc2\x9b\xc2\xbd'} import jso ...

  8. HDU_3415_单调队列

    http://acm.hdu.edu.cn/showproblem.php?pid=3415 初探单调队列,需要注意的是每次i维护的是i-1. #include<iostream> #in ...

  9. Cmake知识----编写CMakeLists.txt文件编译C/C++程序(转)

    1.CMake编译原理 CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多.CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt ...

  10. Spark RDD基本概念、宽窄依赖、转换行为操作

    目录 RDD概述 RDD的内部代码 案例 小总结 转换.行动算子 宽.窄依赖 Reference 本文介绍一下rdd的基本属性概念.rdd的转换/行动操作.rdd的宽/窄依赖. RDD:Resilie ...