您好,欢迎来电子发烧友网! ,新用户?[免费注册]

您的位置:电子发烧友网>源码下载>java源码下载>

探究面试最常见的String、StringBuffer、StringBuilder问题

大小:0.5 MB 人气: 2017-09-27 需要积分:2

  一。你了解String类吗?

  二。深入理解String、StringBuffer、StringBuilder

  三。不同场景下三个类的性能测试

  四。常见的关于String、StringBuffer的面试题(辟谣网上流传的一些曲解String类的说法)

  若有不正之处,请多多谅解和指正,不胜感激。

  一。你了解String类吗?

  想要了解一个类,最好的办法就是看这个类的实现源代码,String类的实现在\jdk1.6.0_14\src\java\lang\String.java 文件中。

  打开这个类文件就会发现String类是被final修饰的:

  public finalclassStringimplements java.io.Serializable, Comparable《String》, CharSequence { /** The value is used for character storage. */privatefinalchar value[]; /** The offset is the first index of the storage that is used. */privatefinalint offset; /** The count is the number of characters in the String. */privatefinalint count; /** Cache the hash code for the string */privateint hash; // Default to 0/** use serialVersionUID from JDK 1.0.2 for interoperability */privatestatic finallong serialVersionUID = - 6849794470754667710L; 。。.。。. }

  从上面可以看出几点:

  1)String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。在早期的JVM实现版本中,被final修饰的方法会被转为内嵌调用以提升执行效率。而从Java SE5/6开始,就渐渐摈弃这种方式了。因此在现在的Java SE版本中,不需要考虑用final去提升方法调用效率。只有在确定不想让该方法被覆盖时,才将方法设置为final。

  2)上面列举出了String类中所有的成员属性,从上面可以看出String类其实是通过char数组来保存字符串的。

  下面再继续看String类的一些方法实现:

  publicString substring( intbeginIndex, intendIndex) { if(beginIndex 《 0) {thrownewStringIndexOutOfBoundsException(beginIndex); } if(endIndex 》 count) {thrownewStringIndexOutOfBoundsException(endIndex); } if(beginIndex 》 endIndex) {thrownewStringIndexOutOfBoundsException(endIndex - beginIndex); } return((beginIndex == 0) && (endIndex == count)) ? this: newString(offset + beginIndex, endIndex - beginIndex, value); } publicString concat(String str) { intotherLen = str.length(); if(otherLen == 0) { returnthis; } charbuf[] = newchar[ count+ otherLen]; getChars( 0, count, buf, 0);str.getChars( 0, otherLen, buf, count); returnnewString( 0, count+ otherLen, buf); }publicString replace( charoldChar, charnewChar) { if(oldChar != newChar) { intlen = count;inti = - 1; char[] val = value; /* avoid getfield opcode */intoff = offset; /* avoid getfield opcode */while(++i 《 len) { if(val[off + i] == oldChar) { break; } } if(i 《 len) { charbuf[] =newchar[len]; for( intj = 0; j 《 i ; j++) { buf[j] = val[off+j]; } while(i 《 len) { charc = val[off + i]; buf[i] = (c == oldChar) ? newChar : c; i++; } returnnewString( 0, len, buf); } } returnthis;

  从上面的三个方法可以看出,无论是sub操、concat还是replace操作都不是在原有的字符串上进行的,而是重新生成了一个新的字符串对象。也就是说进行这些操作后,最原始的字符串并没有被改变。

  在这里要永远记住一点:

  “对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象”。

  在了解了于String类基础的知识后,下面来看一些在平常使用中容易忽略和混淆的地方。

  二。深入理解String、StringBuffer、StringBuilder

  1.String str=”hello world”和String str=new String(“hello world”)的区别

  想必大家对上面2个语句都不陌生,在平时写代码的过程中也经常遇到,那么它们到底有什么区别和联系呢?下面先看几个例子:

  publicclassMain { publicstaticvoidmain(String[] args) { String str1 = “hello world”; String str2 = newString( “hello world”); String str3 = “hello world”; String str4 = newString( “hello world”); System. out.println(str1==str2); System. out.println(str1==str3); System.out.println(str2==str4); } }

  这段代码的输出结果为

  探究面试最常见的String、StringBuffer、StringBuilder问题

  为什么会出现这样的结果?下面解释一下原因:

  在前面一篇讲解关于JVM内存机制的一篇博文中提到 ,在class文件中有一部分 来存储编译期间生成的 字面常量以及符号引用,这部分叫做class文件常量池,在运行期间对应着方法区的运行时常量池。

  因此在上述代码中,String str1 = “hello world”;和String str3 = “hello world”; 都在编译期间生成了 字面常量和符号引用,运行期间字面常量”hello world”被存储在运行时常量池(当然只保存了一份)。通过这种方式来将String对象跟引用绑定的话,JVM执行引擎会先在运行时常量池查找是否存在相同的字面常量,如果存在,则直接将引用指向已经存在的字面常量;否则在运行时常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量。

  众所周知,通过new关键字来生成对象是在堆区进行的,而在堆区进行对象生成的过程是不会去检测该对象是否已经存在的。因此通过new来创建对象,创建出的一定是不同的对象,即使字符串的内容是相同的。

  2.String、StringBuffer以及StringBuilder的区别

  既然在Java中已经存在了String类,那为什么还需要StringBuilder和StringBuffer类呢?

非常好我支持^.^

(0) 0%

不好我反对

(0) 0%

      发表评论

      用户评论
      评价:好评中评差评

      发表评论,获取积分! 请遵守相关规定!