New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[问答]Java 基础之 String、StringBuilder、StringBuffer、CharSequence 区别 #5

Open
Trinea opened this Issue Mar 9, 2015 · 13 comments

Comments

Projects
None yet
@Trinea
Member

Trinea commented Mar 9, 2015

Android 的基础是 Java,对于一到两年的 Android 开发者一般我都会了解下他的 Java 基础怎么样。而聊的过程除了他自己提到的技术点外,一般还会问一些基础问题,比如

String、StringBuilder、StringBuffer、CharSequence 的区别及使用场景

从结果来看,不到 5% 的应聘者了解的程度我觉得能基本算过关的。

@jorry

This comment has been minimized.

jorry commented Mar 10, 2015

String 普通字符串,如果拼接+,会产生一个新的String对象
StringBuilder 非线程安全,字符串拼接用,除了StringBuffer可用场景外
StringBuffer 线程安全,比如:在http请求中拼接。
CharSequence 现在google之

@lchad

This comment has been minimized.

lchad commented Mar 10, 2015

  1. CharSequence接口:是一个字符序列.String StringBuilder 和 StringBuffer都实现了它.
  2. String类:是常量,不可变.
  3. StringBuilder类;只可以在单线程的情况下进行修改(线程不安全).
  4. StringBuffer类:可以在多线程的情况下进行改变(线程安全).
    5)Stringbuilder比StringBuffer效率高,应该尽量使用StringBuilder.
    CharSequence的使用场景我不熟悉,还需要各位大神分享.

@Trinea Trinea changed the title from 问答-Java 基础之 String、StringBuilder、StringBuffer、CharSequence 区别 to [问答]Java 基础之 String、StringBuilder、StringBuffer、CharSequence 区别 Mar 10, 2015

@Trinea

This comment has been minimized.

Member

Trinea commented Mar 10, 2015

上面两个答案都不算满意。延伸下:

  1. 成员变量、局部变量在什么场景下用哪个更合适
  2. 他们之间效率如何,为什么
  3. 有没有存在特殊情况
  4. 编译器对他们的优化
@junyuecao

This comment has been minimized.

junyuecao commented Mar 11, 2015

.4. 相同的字符串在内存中不会保存多分(new String除外,这个时候字符串对象不相同,但是实际在内存中的字符数组是同一个); 字符串连加时编译器会进行优化,只保存最终字符串

@Rowandjj

This comment has been minimized.

Rowandjj commented Mar 11, 2015

1.CharSequence是一个java接口,代表一个char序列,String、StringBuilder、StringBuffer都实现了该接口,CharSequence实例通过调用toString方法可转化为String对象。
2.String类是final的,不可派生子类,其内部封装的是char[],另外,android下的String类和jdk中的String类是有区别的,android下的String类中部分API通过native方法实现,效率相对高一些。
3.String使用'+'进行字符串拼接时,在编译期会转化为StringBuilder#append方式
4.String在内存中有一个常量池,两个相同的串在池中只有一份实例(String s = "abc"方式或者String#intern方式会在池中分配),使用new String方式会在heap中分配,每次创建都是一个全新的实例。
5.StrigBuilder & StringBuffer都是可扩展的串,提供了一系列apped方法用于拼接不同类型对象
6.StringBuffer于jdk1.0引入,线程安全(多线程场景下使用),StringBuilder于jdk1.5引入,线程不安全,因而效率更高。
7.StringBuilder & StringBuffer初始容量都为16,开发者应该指定其容量,以避免多次扩容所带来的性能问题。

@lchad

This comment has been minimized.

lchad commented Mar 15, 2015

@Trinea 期待大神来给这个问题一锤定音.

@xxmbaobao

This comment has been minimized.

xxmbaobao commented Mar 18, 2015

CharSequece 是个接口String、StringBuilder、StringBuffer 都是它的实现
String 是常量修改它的值实际是创建新的对象
StringBuffer 是变量更改值时是在原对象上添加,属于同步的
StringBuilder 和StringBuffer用法差不多,在非同步情况下使用

@miao1007

This comment has been minimized.

miao1007 commented May 15, 2015

除去楼上大神们的回答,今天再补一个

public static void main(String[] args) {
    // write your code here
        String a = "hello";//a拥有对常量区中String对象"hello"的引用
        String b = "hello";//b拥有对常量区中String对象"hello"的引用
        String c = new String("hello");//在堆中新建一个String对象,c是这个对象的引用
        String d = "hell" + "o"; //编译器自动帮你合并了,仍然是常量区中的hello
        System.out.println(a == b);//true
        System.out.println(a == "hello");//true
        System.out.println(b == "hello");//true
        System.out.println(a == d);//ture
        System.out.println(c == a);//false
        System.out.println(c == b);//false
        System.out.println(c == "hello");//false
    }
@xiaorong1176

This comment has been minimized.

xiaorong1176 commented Jul 20, 2015

来,我们先来分析一下他们的源码吧。(先占个位置,现在在准备面试,后面补充)

@ahsxsk

This comment has been minimized.

ahsxsk commented Mar 23, 2016

###回答1:
  String是不可变的字符串,任何拼接、修改操作都是返回的新的String对象,原对象并没有改变;StringBuilder和StringBuffer是可变字符串,修改操作改变的是原有的对象。StringBuilder和StringBuffer的区别是StringBuffer是线程安全的,他的大部分API都使用synchronized 关键字修饰。所以针对这三个类的使用场景归纳如下
  1)修改操作较少的场景可以用String;
  2)单线程情况下字符串需要大量操作的适合使用StringBuilder;
  3)多线程操作情况下大量操作字符串适合使用StringBuffer。

###回答2:
  String的修改、拼接等操作由于需要重新申请新对象所以速度一般情况下比StringBuilder和StringBuffer慢。StringBuffer API采用synchronized修饰,一般速度会比StringBuilder慢。

###回答3:
  用例子回答这个问题

String s = “a” + “b” + “c” + “d”;
StringBuilder sb = new StringBuilder("a").append("b").append("c").append("d");

  回答2指出StringBuilder速度比String快,这两个语句执行效率情况如下:

public void testSpeed() {
    long t1 = System.nanoTime();
    String s = "a" + "b" + "c" + "d";
    long t2 = System.nanoTime();
    System.out.println("String耗时为: " + (t2 - t1));
    long t3 = System.nanoTime();
    StringBuilder sb = new StringBuilder("a").append("b").append("c").append("d");
    long t4 = System.nanoTime();
    System.out.println("StringBuilder耗时为: " + (t4 -t3));
}

  执行结果为:

String耗时为: 3611
StringBuilder耗时为: 13617

###回答4:
  回答3中指出了String效率可能会比StringBuilder高,产生这种情况的原因是JVM对此进行了优化。理论上说String s = “a” + “b” + “c” + “d”; 这条语句会产生4个对象,实际向JVM将这条语句优化为String s = “abcd”;所以效率高。

@printfll

This comment has been minimized.

printfll commented Aug 27, 2016

String a="abc"; String e="ab";e+="c"; a==e是false。在这个过程中,似乎编译器不会自动合并。那是不是会有两个"abc"存在于内存中?

@JingMeng

This comment has been minimized.

JingMeng commented Oct 28, 2016

回复楼上的:
这是因为在 e+="c";这个地方创建了一个StringBuilder对象,并且调用了toString方法

    StringBuilder 对象的的toString在堆内存中创建了一个String对象,

     public String toString() {
            // Create a copy, don't share the array
            return new String(value, 0, count);
        }

如果是 String s = "a" + "b" + "c" + "d"; 编译器会直接优化成abcd

如果是对象的toString()

public String toString() {
return "Person [nickName=" + nickName + ", name=" + name + "]";
}
也会优化成为一个StringBuilder

你可以好好理解一下楼上Rowandjj的第三条

@lijinxiong

This comment has been minimized.

lijinxiong commented Oct 31, 2016

@printfll String e+="c" 因为e是一个变量,在编译器是没法确定它的值的,假如你这样定义:
String a="abc"; final String e="ab"; String b=e+"c"; a==b;//true 这样的时候,编译期就会对其进行优化,可以用javap 看编译后的class文件

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment