Java字符串笔试题汇总

字符串常量池

字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价。JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。为
了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池。如果字符串已经存在池中, 就返回池中的实例引用。如果字符串不在池中,就会实例化一个字符串并放到池中。Java能够进行这样的优化是因为字符串是不可变的,可以不用担心数据冲突 进行共享。

字符串常量池是Java节约资源的一种方式。

字符串常量池在哪里?

在JDK6.0及之前版本,字符串常量池是放在Perm Gen区(也就是方法区)中;
在JDK7.0版本,字符串常量池被移到了堆中了。至于为什么移到堆内,大概是由于方法区的内存空间太小了。

String类

String 为字符串常量是不可变对象,String 每次修改相当于生成一个新对象,因此性能最低

StringBuffer

StringBuffer为字符串变量是可变对象,StringBuffer 使用 synchronized 来保证线程安全,性能优于 String,但不如 StringBuilder,StringBuffer 为线程安全类

StringBuilder

StringBuffer 为字符串变量是可变对象,StringBuilder 为非线程安全类。

题目一

package com.forcoldplay.javase;

public class Demo04 {

    public static void main(String[] args) {
        String s1 = "forcoldplay.com";
        String s2 = s1;
        String s3 = new String(s1);
        System.out.println(s1 == s2);
        System.out.println(s1 == s3);
    }

}

输出结果为

true flase

对于String类,字符串创建有两种方式

String str = "forcoldplay.com";
String str = new String("forcoldplay.com");

第一种创建在字符串常量池,第二种在堆区。

S1在字符串常量池创建一个字符串"forcoldplay.com";

s2 直接使用了s1 的引用,所以s1==s2 返回是true

s3是在堆中创建了字符串对象"forcoldplay.com",它的地址和s1当然不一样。

顺带一提"==" 对基本类型来说是值比较,对于引用类型来说是比较的是引用。

题目二

package com.forcoldplay.javase;

public class Demo05 {

    public static void main(String[] args) {
        String str1 = "for" + "cold" +"play";
        String str2 = "forcoldplay";
        System.out.println(str1==str2);
    }

}

结果是

true

jvm虚拟机里提到过,多少页我忘了,翻到了回来再更新,这个是jvm语法糖,在编译期间优化了。

对于

        String str1 = "for" + "cold" +"play";

jvm优化后,成为了

        String str1 = "forcoldplay";

所以,str2发现常量池有该字符串,str1 == str2

题目三

package com.forcoldplay.javase;

public class Demo06 {

    public static void main(String[] args) {

        String str1 = "for" + "cold" + "play" ;
        String str2 = "for";
        str2+="cold";
        str2+="play";
        String str3 = "forcoldplay";
        
        System.out.println(str1==str2);
        System.out.println(str1==str3);
        System.out.println(str2==str3);
        
        System.out.println(str1.equals(str2));
        System.out.println(str1.equals(str3));
        System.out.println(str2.equals(str3));        
    }

}
false
true
false
true
true
true

jdk API 1.8里有这么一句话

​ Java语言为字符串连接运算符(+)提供特殊支持,并为其他对象转换为字符串。

字符串连接是通过StringBuilder (或StringBuffer )类及其append方法实现的。

字符串转换是通过方法来实现toString ,由下式定义Object和继承由在Java中的所有类。

有关字符串连接和转换的其他信息,请参阅Gosling,Joy和Steele, Java语言规范

理解这句话,那么str就好理解了

        String str2 = "for";
        str2+="cold";
        str2+="play";

str2它指向的是堆内存中新创建的字符串对象。

题目四

package com.forcoldplay.javase;

public class Demo08 {

    public static void main(String[] args) {
        
        String str1 = "forcoldplay";
        String str2 = "forcoldplay";
        
        String str3 = new String("forcoldplay");
        String str4 = new String("forcoldplay");

        System.out.println(str1==str2);
        System.out.println(str3==str4);
        
    }

}
true
false

每当代码创建字符串常量时,JVM会首先检查字符串常量池。如果字符串已经存在池中, 就返回池中的实例引用。如果字符串不在池中,就会实例化一个字符串并放到池中。

而每new一次的时候,就会在堆上创建一个相应的实例对象。

题目五

package com.forcoldplay.javase;

public class Demo09 {

    public static void main(String[] args) {
        
        StringBuffer str1 = new StringBuffer("for");
        change(str1);
        System.out.println(str1);
    }
    public static void change(StringBuffer str) {
        str.append("coldplay");
    }
}
forcoldplay

str1 和 参数str都指向了堆上的一个StringBuffer对象“for”,

StringBuffer为字符串变量是可变对象,因此str.append("coldplay"),其值会改变

因此str1引用的指向也会改变

题目六

package com.forcoldplay.javase;

public class Demo10 {

    public static void main(String[] args) {    
        String str1 = new String("for");
        change(str1);
        System.out.println(str1);
    }
    public static void change(String str) {
        str = str + "coldplay";
    }
}

str1 和 参数str都指向了字符串常量池的“for”,

String为字符串变量是不可变对象,因此str.append("coldplay"),str会指向堆上的一个实例对象

但是str引用的指向没有改变

题目七

package com.forcoldplay.javase;

public class Demo03 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        StringBuffer a = new StringBuffer("A");
        StringBuffer b = new StringBuffer("B");
        operator(a,b);
        System.out.println(a+","+b);
    }
    public static void operator(StringBuffer x ,StringBuffer y) {
        //System.out.println("way 1: " + x);
        x.append(y);
        //System.out.println("way 2: " + x);
        
        //System.out.println("way 3: " + y);    
        y = x;
        //System.out.println("way 4: " + y);
    }
}

输出结果为

AB B

如果是基本类型,就是值传递,如果引用类型,就是引用传递

实例的对象放在堆区,对象的引用放在栈区

a和x指向的是同一个对象,b和y指向的是同一个对象

x.append(y); 改变的是对象里面的值

y = x 只是改变了y的引用。

Last modification:November 18th, 2019 at 11:46 pm
如果觉得我的文章对你有用,请随意赞赏