常见面试题总结01【自我总结复习+学习自用】
一.String和StringBuilder、StringBuffer的区别
1.String
观察String源码:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
public String() {
this.value = "".value;
}
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
//省略更多的构造器方法
一、分析要素:
1.String类是由final修饰的
2.String的构造方法都是将字符串放入到这个char数组当中,且这个value属性值由final修饰
二、分析所需的知识体系:
首先,要知道被final修饰的类、方法、成员变量有什么特点?
被final修饰的类:
1.不可被继承
2.final类中的方法默认final
3.final不能用于修饰构造方法
被final修饰的方法:
1.可以被继承,不能被重写
被final修饰的成员变量
1.只能被赋值一次,之后不可修改
三、分析
分析要素2:
思路1:value数组被final修饰——>思路2:这个char数组只能被赋值一次,一旦赋值后这个char数组就变成定长的了 —>推断1:每次改变字符串的值,会重新创建一个新的String对象
四、拓展
疑问:1.为什么我们可以直接使用String a=“xxx”,而不是去new一个对象(可行)?
五、引入知识体系/资料查询
1.从源码角度:
首先,疑惑点:为什么可以采用String a=“xxx”这种语法格式,它是在哪里定义的?
进入String类,有如下源码(为方便阅读,截取部分并修改格式):
/**
* 1.The {@code String} class represents character strings. All
* string literals in Java programs, such as {@code "abc"}, are
* implemented as instances of this class.
*
* 2.Strings are constant; their values cannot be changed after they
* are created.
*
* 3..Because String objects are immutable they can be shared
* 4. String str = "abc";
* is equivalent to:
* char data[] = {'a', 'b', 'c'};
* String str = new String(data);
*
* */
源码要素:
1.它告诉我们,所有在java的String字符,比如"abc",都会被这个String类当作一个实例所实现
2.String字符串都是常量,它们的值都是不可变的
3.因为String对象是不可变的,所以它们能够被共享
4.String str = “abc” 等同于
char data[] = {‘a’, ‘b’, ‘c’};
String str = new String(data);
分析:
1.疑问解决,也就是说,String的确提供了这种语法规范,当我们写String x=“xxx”时,它就会将它实例化,而至于它如何实现的,这里不过分追究,但可以猜测JVM在编译过程中能够成功识别到或者通过C或者其他语言实现的
2.String对象是能够被共享的,这里就需要知道“常量池”这个概念
五、引入知识体系/资料查询
2.常量池
String作为一个使用非常频繁的类,但String的类的特性让我们在修改字符串时便会去创建一个新的对象,这样会造成使用的性能底下,于是引入了“常量池”这种机制
常量池的机制:
第一种情况:
1.当我们对一个字符串进行创建或修改(以String a="xxx"的格式)
2.JVM在编译过程会去常量池(也就是一块专属于String的内存空间,这在String类的源码中有说明)找是否有相等的字符串
如果存在,直接在栈中开辟空间,存储指向常量池相应字符串的地址
如果不存在,则在常量池中开辟空间,存储这个字符串,然后在栈中开辟空间,存储指向常量池地址的引用
第二种情况:
1.我们new一个String对象
2.JVM还是会去常量池中查看是否存在这个字符串
如果存在,则不会在常量池开辟空间,但是因为我们是new的对象,所以会在堆中开辟空间
如果不存在,则既会在常量池开辟空间,也会在堆中开辟空间
所以,这种情况下会创建一个或者两个对象。
2.StringBuffer和StringBuilder
1.概述:
StringBuffer和StringBuilder都属于可变字符串。
2.什么叫做可变字符串?
也就是说,当我们使用StringBuffer或者StringBuilder去操作字符串的时候,不会去创建新的对象。
3.两者区别?
StringBuffer是线程安全的,StringBuilder是非线程安全的,所以性能上优于StringBuffer。
4.为什么存在这样的区别?
为什么StringBuffer是线程安全的?
观察StringBuffer部分源码
@Override
public synchronized StringBuffer append(Object obj) {
toStringCache = null;
super.append(String.valueOf(obj));
return this;
}
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
我们可以看到,StringBuffer在执行方法的时候都要求同步,所以它是安全的;StringBuilder对象在执行方法时则没有synchronized去要求它是同步的,所以它是非线程安全的。