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的引用。