java面试题:string,stringbuffer详解(通过代码说明)

 

 

    最近一直看到很多关于string的java面试题,下面通过代码进行测试并说明,针对不同角度,写了一下几个测试方法,供参考。另外从网上看到一个例子,用于比较string和stringbuffer的效率,也直接拿过来了。

 

/**

 * 常量池(constant pool)指的是在编译期被确定,

 * 并被保存在已编译的.class文件中的一些数据.它包括了关于类、方法、接口等中的常量,也包括字符串常量.

 * 我们要知道Java会确保一个字符串常量只有一个拷贝.

 * @author Administrator

 *

 */

public class StringTest {

 

public static void main(String[] args) {

StringTest  t = new StringTest();

t.test1();

// t.test2();

/*t.test3();

t.test4();

t.test5();*/

// t.test6();

}

/*栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。

但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。

另外,栈数据可以共享。

堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,

Java的垃圾收集器会自动收走这些不再使用的数据。

但缺点是,由于要在运行时动态分配内存,存取速度较慢。 

例子:

栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

int a = 3; 

int b = 3; 

编译器先处理int a = 3;

首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,

没找到,就开辟一个存放3这个字面值的地址,

然后将a指向3的地址。接着处理int b = 3;

在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。

这样,就出现了a与b同时均指向3的情况。 

*/

/*我们在使用诸如String str = "abc";的格式定义类时,

总是想当然地认为,我们创建了String类的对象str。担心陷阱!

对象可能并没有被创建!唯一可以肯定的是,指向String类的引用被创建了。

至于这个引用到底是否指向了一个新的对象,必须根据上下文来考虑,

除非你通过new()方法来显要地创建一个新的对象。

因此,更为准确的说法是,我们创建了一个指向String类的对象的引用变量str,

这个对象引用变量指向了某个值为"abc"的String类。

清醒地认识到这一点对排除程序中难以发现的bug是很有帮助的。*/ 

 

/**

* s0和s1中的"kvill"都是字符串常量,它们在编译期就被确定了,所以s0==s1为true;

* 而"kv"和"ill"也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,

* 所以s2也同样在编译期就被解析为一个字符串常量,所以s2也是常量池中"kvill"的一个引用.

*/

public void test1(){

String s0="kvill";

 

   String s1="kvill";

   

 //有3个字符串常量,首先"kv"和"ill"生成了"kvill"存在内存中,

  //然后"kvill"又和" " 生成 "kvill "存在内存中,

   //String的"不可变"产生了很多临时变量,这也就是为什么建议用StringBuffer的原因

   String s2="kv" + "ill";

   

   //实际上在编译的时候,s3是一个对象,被分别分配了一个地址,

   // s3 = s3 + "ill"执行时,原来的s3被释放,然后重新分配。s3原本指向一 String object instance ("kv"), 

   //s3 = s3 + "ill"会造出另一新的 String object instance ("kvill"), 然后s3再指向这新的 String instance。

   String s3 = "kv";

   s3 = s3 + "ill";

   

   String s4 = s0;

   

   String s5 = s3;

   

   System.out.println( s0==s1 );//是true

 

   System.out.println( s0==s2 );//是true

   

   System.out.println( s0==s3 );//是false

   

   System.out.println( s0==s4 );//是true

   

   System.out.println( s0==s5 );//是false

}

/**

* s0还是常量池中"kvill"的应用,s1因为无法在编译期确定,所以是运行时创建的新对象"kvill"的引用,

* s2因为有后半部分new String("ill")所以也无法在编译期确定,所以也是一个新创建对象"kvill"的应用;

*/

public void test2(){

String s0="kvill";

 

   String s1=new String("kvill");

 

   String s2="kv" + new String("ill");

 

   System.out.println( s0==s1 );

 

   System.out.println( s0==s2 );

 

   System.out.println( s1==s2 );

   

   System.out.println("hashcode:");

   System.out.println("s0:"+s0.hashCode());

   System.out.println("s1:"+s1.hashCode());

   System.out.println("s2:"+s2.hashCode());

   

   System.out.println(s0.getClass());

}

/*String:

是对象不是原始类型.

为不可变对象,一旦被创建,就不能修改它的值.

对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去.

String 是final类,即不能被继承.

 

StringBuffer:

是一个可变对象,当对他进行修改的时候不会像String那样重新建立对象

它只能通过构造函数来建立,

StringBuffer sb = new StringBuffer();

note:不能通过付值符号对他进行付值. 

sb = "welcome to here!";//error

对象被建立以后,在内存中就会分配内存空间,并初始保存一个null.向StringBuffer

中付值的时候可以通过它的append方法.

sb.append("hello");

总结: 

(1)由于String 对象是不可变对象,每次操作Sting 都会重新建立新的对象来保存新的值.

这样原来的对象就没用了,就要被垃圾回收.这也是要影响性能的.

(2)如果在程序中需要对字符串进行频繁的修改连接操作的话.使用StringBuffer性能会更高

*/

public void test3(){

String tempstr = "abcdefghijklmnopqrstuvwxyz"; 

       int times = 5000; 

       long lstart1 = System.currentTimeMillis(); 

       String str = ""; 

       for (int i = 0; i < times; i++) { 

           str += tempstr; 

       } 

       long lend1 = System.currentTimeMillis(); 

       long time = (lend1 - lstart1); 

       System.out.println(time);

}

public void test4(){

String tempstr = "abcdefghijklmnopqrstuvwxyz"; 

        int times = 5000; 

        long lstart2 = System.currentTimeMillis(); 

        StringBuffer sb = new StringBuffer(); 

        for (int i = 0; i < times; i++) { 

            sb.append(tempstr); 

        } 

        long lend2 = System.currentTimeMillis(); 

        long time2 = (lend2 - lstart2); 

        System.out.println(time2);

}

public void test5(){

String tempstr = "abcdefghijklmnopqrstuvwxyz"; 

        int times = 5000; 

        long lstart2 = System.currentTimeMillis(); 

        String str = ""; 

        for (int i = 0; i < times; i++) { 

            StringBuffer sb = new StringBuffer(str); 

            sb.append(tempstr); 

            str = sb.toString(); 

        } 

        long lend2 = System.currentTimeMillis(); 

        long time2 = (lend2 - lstart2); 

        System.out.println(time2);

}

/**

* StringBuffer类中没有重新定义equals这个方法,因此这个方法就来自Object类,

而Object类中的equals方法是用来比较地址的,所以等于false.

 

String类中重新定义了equals这个方法,而且比较的是值,而不是地址。所以会是

true。

*/

public void test6(){

StringBuffer s1 = new StringBuffer("a");

StringBuffer s2 = new StringBuffer("a");

 

String s3 = new String("a");

String s4 = new String("a");

System.out.println(s1.equals(s2));//是false

System.out.println(s3.equals(s4));//是true

}

}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值