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. Web自动化测试项目(五)测试结果通知

    一.邮件通知 使用第三方邮件发送库yagmail github地址:https://github.com/kootenpv/yagmail 安装 pip3 install yagmail demo.p ...

  2. sqlserver 分页模糊查询

       积少成多 ----  仅以此致敬和我一样在慢慢前进的人儿 问题: 在sqlserver 进行模糊查询,出现问题 最初使用“concat”,进行拼串操作,如下所示: <select id = ...

  3. netty EventLoop线程与当前线程的问题

    模拟客户端向服务端发送消息: 客户端部分代码如下,当连接激活触发消息发送,采用线程池的形式,分多个线程向服务端发送同一消息 @Override public void channelActive(Ch ...

  4. python sqlalchemy mysql 自动映射

    SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作 简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果 ...

  5. 曹工说Spring Boot源码(14)-- AspectJ的Load-Time-Weaving的两种实现方式细细讲解,以及怎么和Spring Instrumentation集成

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  6. supervisor守护filebeat服务进程

    1.变更原因 部署安装supervisor进行filebeat守护及后面的各种服务进程守护可以用2.变更内容增加supervisor服务 3.变量时间:6月2号-6月3号4.变更风险评估:无风险4.1 ...

  7. Python程序打包EXE遇到的各种坑

    废话不多说,反正我现在还没成功,不过我记录一下遇到的坑! 1:安装相关库太慢 解决办法:离线安装 在一大堆教程中,要安装好几个库,但是有些库用pip在线安装一直卡死(看不到进度条,就当卡死吧),这个问 ...

  8. cpu负载高简单排查思路

    首先通过uptime查看系统负载,然后使用mpstat结合pidstat来初步判断到底是cpu计算量大还是进程争抢过大或者是io过多,接着使用vmstat分析切换次数,以及切换类型,来进一步判断到底是 ...

  9. 吴sir讲Python之 ——Pycharm的教程使用(二)

    欢迎您进入老吴的博客,如有联系请加QQ群:1055524279 Pycharm使用: 第一步:打开的界面: 选择代码路径和Python解释器版本 设置Pycharm菜单字体的大小: 设置编辑器里面字体 ...

  10. Codeforces_714

    A.相遇时间段l = max(l1,l2),r = min(r1,r2),再判断k是否在里面. #include <iostream> using namespace std; long ...