常见面试题总结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去要求它是同步的,所以它是非线程安全的。