面试题1 - 什么情况下用+运算符进行字符串连接比调用StringBuffer/StringBuilder对象的append方法连接字符串性能更好?

面试题2 - 请说出下面程序的输出。

class StringEqualTest {

    public static void main(String[] args) {
String s1 = "Programming";
String s2 = new String("Programming");
String s3 = "Program";
String s4 = "ming";
String s5 = "Program" + "ming";
String s6 = s3 + s4;
System.out.println(s1 == s2);
System.out.println(s1 == s5);
System.out.println(s1 == s6);
System.out.println(s1 == s6.intern());
System.out.println(s2 == s2.intern());
}
}
返回值:
false
true
false
true
false

  今天在看面试题的时候注意到一个String的intern()方法,平常没用过,只是见过这个方法,也没去仔细看过这个方法。所以今天看了一下。个人觉得给String类中加入这个方法可能是为了提升一点点性能,因为从常量池取数据比从堆里面去数据要快一些。(个人感觉)

  API上的那几句关于这个方法,其实总结一句就是调用这个方法之后把字符串对象加入常量池中,常量池我们都知道他是存在于方法区的,他是方法区的一部分,而方法区是线程共享的,所以常量池也就是线程共享的,但是他并不是线程不安全的,他其实是线程安全的,他仅仅是让有相同值的引用指向同一个位置而已,如果引用值变化了,但是常量池中没有新的值,那么就会新开辟一个常量结果来交给新的引用,而并非像线程不同步那样,针对同一个对象,new出来的字符串和直接赋值给变量的字符串存放的位置是不一样的,前者是在堆里面,而后者在常量池里面,另外,在做字符串拼接操作,也就是字符串相"+"的时候,得出的结果是存在在常量池或者堆里面,这个是根据情况不同不一定的,我写了几行代码测试了一下。

  先上结果:

    1.直接定义字符串变量的时候赋值,如果表达式右边只有字符串常量,那么就是把变量存放在常量池里面。

    2.new出来的字符串是存放在堆里面。

    3.对字符串进行拼接操作,也就是做"+"运算的时候,分2中情况:

      i.表达式右边是纯字符串常量,那么存放在栈里面。

      ii.表达式右边如果存在字符串引用,也就是字符串对象的句柄,那么就存放在堆里面。

    String str1 = "aaa";
String str2 = "bbb";
String str3 = "aaabbb";
String str4 = str1 + str2;
String str5 = "aaa" + "bbb";
System.out.println(str3 == str4); // false
System.out.println(str3 == str4.intern()); // true
System.out.println(str3 == str5);// true

  结果:str1、str2、str3、str5都是存在于常量池,str4由于表达式右半边有引用类型,所以str4存在于堆内存,而str5表达式右边没有引用类型,是纯字符串常量,就存放在了常量池里面。其实Integer这种包装类型的-128 ~ +127也是存放在常量池里面,比如Integer i1 = 10;Integer i2 = 10; i1 == i2结果是true,估计也是为了性能优化。

学习了String类和StringBuffer类,现在从三分面来总结一下String、StringBuffer、StringBudder三者的区别:

  • 是否可变:

String:底层利用字符数组保存字符串常量,是不可变的,因为String类的原码中有:private final char value[];因为有final修饰,所以String类的对象是不可改变的。所以每次修String对象的值时,实际上是生成了一个新的对象,而指针指向了新的String对象;

StringBufferStringBudder底层是利用字符数组保存字符串变量的,在jdk1.7中它们都继承了AbstractStringBuilder类,而在AbstractStringBuilder类中有char[] value;,所以这两者对象是可变的;

  • 执行速度:一般情况StringBudder > StringBuffer > String

    String:因为String对象是不可变的,所以每次修String对象的时候,实际上是生成了一个新的对象,而指针指向了新的String对象;所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。

    StringBuffer:而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。
    但是有特殊情况: String str = “abc” + “def”;StringBuffer Sb = new
    StringBuilder(“abc”).append(“
    def”);这时这种情况下:String的速度就要比StringBuffer的速度要快,因为这时jvm认为String str = “abc”
    + “def”;其实是:String str =
    “abcdef”;所以速度当然很快,这里说的是当String保存的字符串中有其他String的字符串时,速度就会变慢。

  • 是否线程安全:

    String: String中的对象是不可变的,也就可以理解为常量,显然线程安全。

    StringBuffer:是线程安全的,因为对方法加了同步锁或者对调用的方法加了同步锁,部分方法原码如下:

 public synchronized int length() {
return count;
} public synchronized int capacity() {
return value.length;
} public synchronized void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > value.length) {
expandCapacity(minimumCapacity);
}
}

StringBudder:并没有对方法进行加同步锁,所以是非线程安全的。部分方法原码如下:

 private StringBuilder append(StringBuilder sb) {
if (sb == null)
return append("null");
int len = sb.length();
int newcount = count + len;
if (newcount > value.length)
expandCapacity(newcount);
sb.getChars(0, len, value, count);
count = newcount;
return this;
}
public StringBuilder delete(int start, int end) {
super.delete(start, end);
return this;
}
  • 对三者的使用意见:

1.如果要操作少量的数据用: String
2.单线程操作字符串缓冲区 下操作大量数据 :StringBuilder
3.多线程操作字符串缓冲区 下操作大量数据 : StringBuffer

java面试题----String、StringBuffer、StringBudder区别的更多相关文章

  1. Java学习之String StringBuffer StringBuilder区别

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

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

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

  3. 【Java基础】String StringBuffer StringBuilder

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

  4. String,StringBuffer,StringBudilder区别--2019-04-13

    String,StringBuffer,StringBudilder区别: 1String 是字符串常量,创建内容不可以变, final修饰意味着String类型不能被继承,减少被修改的可能,从而最大 ...

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

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

  6. String,StringBuffer,StringBuilder区别

    String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) 简要的说, String 类型和 StringBuffer 类型的主要性能 ...

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

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

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

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

  9. 转:String StringBuffer StringBuilder区别

    转自:http://www.iteye.com/topic/522167 作者:每次上网冲杯Java时,都能看到关于String无休无止的争论.还是觉得有必要让这个讨厌又很可爱的String美眉,赤裸 ...

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

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

随机推荐

  1. LightOJ - 1234 分块预处理

    求∑1/i,但是范围很大 和bitmap的想法一样,分个块,均摊复杂度就降下来了 //到底排行榜上的0ms是怎么做到的? #include<bits/stdc++.h> using nam ...

  2. jstl 遍历数据

    1   导入 jstl  的  jar 包 2. 页面中添加 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/ ...

  3. python操作Spark常用命令

    1. 获取SparkSession spark = SparkSession.builder.config(conf = SparkConf()).getOrCreate() 2. 获取SparkCo ...

  4. JS 克隆Object.prototype.Clone

    我们知道,在js中,当object作为参数传递到函数中进行处理后,实际上是修改了传入的对象本身(或者说是对象的引用),但很多时候我们并不希望函数去修改我们的这些对象参数,这就需要使用到对象的克隆,我们 ...

  5. 字典树+map

    Problem Description Carryon最近喜欢上了一些奇奇怪怪的字符,字符都是英文小写字母,但奇怪的是a可能比b小,也可能比b大,好奇怪.与此同时,他拿到了好多的字符串,可是看着很不顺 ...

  6. poj3262

    一.题意:有n头牛,每头牛每分钟会吃D个菜,把这头牛赶回去需要时间T(人再返回又需要T),一次只能赶回去一头牛,也就是说剩下的牛会继续吃菜.求牛最少吃多少菜 二.思路:贪心.按D/T将牛进行排序,然后 ...

  7. 案例47-crm练习登录校验拦截器

    1 LoginInterceptor package www.test.web.interceptor; import java.util.Map; import com.opensymphony.x ...

  8. pulic——功能性(自己写完测试的)

    一. 构建一个数组[“00:00”,"00:05"..."23:55"]的数组 function buildAxis(){ var ary=[]; ary.pu ...

  9. Redis启动和关闭

    带配置文件启动 ./redis-server redis.conf 关闭 无密码模式  ./redis-cli -h xxx -p xxx shutdown 密码模式  ./redis-cli -h ...

  10. 【linux】netstat 详解

    Linux netstat命令用于显示网络状态. 利用netstat指令可让你得知整个Linux系统的网络情况. 在Internet RFC标准中,Netstat的定义是: Netstat是在内核中访 ...