面试题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

最新文章

  1. 去除magento多店铺URL地址中的“___from_store=”
  2. 新塘ARM平台交叉编译minigui界面库
  3. Git学习笔记 git revert
  4. 移动端html页面布局
  5. AngularJS初始化闪烁
  6. SharePoint 2013 排错之"Code blocks are not allowed in this file"
  7. Hark的数据结构与算法练习之插入排序
  8. Oracle数据库启动流程
  9. C# 计算器 如果设置键盘输入的监听事件
  10. 转:drupal使用superfish建立下拉菜单
  11. 数据库出现1045 access denied for user 'root'@'localhost' using password yes (转)
  12. phpcms 的getcache()函数
  13. windows下搭建virtualenv虚拟环境
  14. svnsync同步svn
  15. Python【初识篇】简介
  16. get方法与post方法的区别与js获取url参数的方式
  17. tween 缓动动画
  18. 使用KVM虚拟机遇到的问题(持续更新)
  19. 转载:编译安装Nginx(1.4)《深入理解Nginx》(陶辉)
  20. Servlet中web.xml的配置

热门文章

  1. 24个常用 Python 实现
  2. 洛谷 P2680 运输计划(NOIP2015提高组)(BZOJ4326)
  3. (找到最大的整数k使得n! % s^k ==0) (求n!在b进制下末尾0的个数) (区间满足个数)
  4. 多重if 与 switch case的区别
  5. pyspark SparkSession及dataframe基本操作
  6. GreenPlum 大数据平台--非并行备份(六)
  7. DP Intro - Tree DP
  8. gradle cache目录(.gradle)剖析
  9. ubuntu安装VMware Tools报错enter the path to the kernel header files
  10. Unity Editor Console Pro 扩展点击定位到外部工程