欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

String-面试常考问题剖析

程序员文章站 2024-03-23 12:45:52
...

1. 为什么 String 类型要用 final 修饰?

为啥这样设计呢?, 请带着这一个疑问看下去,从 String 类的源码我们可以看出 String 是被 final 修饰的不可继承类,源码如下:
String-面试常考问题剖析

Java 语言之父 James Gosling 的回答是:

他会更倾向于使用 final,因为它能够缓存结果,当你在传参时不需要考虑谁会修改它的值;如果是可变类的话,则有可能需要重新拷贝出来一个新值进行传参,这样在性能上就会有一定的损失。

那么从 James Gosling的回答,可以知道他从两个方面来考虑设计String类型为 “final 的”

1.安全

当你在调用其他方法时,比如调用一些系统级操作指令之前,可能会有一系列校验,如果是可变类的话,可能在你校验过后,它的内部的值又被改变了,这样有可能会引起严重的系统崩溃问题,这是迫使String类设计成不可变类的一个重要原因。

2.高效

以 JVM 中的字符串常量池来举例,如下两个变量:

String str1 = "java";
String str2 = "java";

只有字符串是不可变时,我们才能实现字符串常量池,字符串常量池可以为我们缓存字符串,提高程序的运行效率,如下图所示:
String-面试常考问题剖析
试想一下如果 String 是可变的,那当 s1 的值修改之后,s2 的值也跟着改变了,这样就和我们预期的结果不相符了,因此也就没有办法实现字符串常量池的功能了。

2. == 和 equals 的区别是什么?

比较官方的回答是这样的:

== 对于基本数据类型来说,是用于比较 “值”是否相等的;而对于引用类型来说,是用于比较引用地址是否相同的。

查看源码我们可以知道 Object 中也有 equals() 方法,源码如下:

public boolean equals(Object obj) {
    return (this == obj);
}

可以看出,Object 中的 equals() 方法其实就是 ==,而 String 重写了 equals() 方法把它修改成比较两个字符串的值是否相等

  public boolean equals(Object anObject) {
  		//先判断当前引用地址是否相同
        if (this == anObject) {
            return true;
        }
        //判断类型是否为String
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            //判断长度是否一致 ,再进行循环比对字符是否相等
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

3. String 和 StringBuilder、StringBuffer 有什么区别?

因为String类型是不可变的,所以在字符串拼接的时候如果使用String的话性能会很低,因此我们就需要使用另一个数据类型StringBuffer,它提供了append和insert方法可用于字符串的拼接,它使用 synchronized 来保证线程安全,如下源码所示:

String-面试常考问题剖析
因为它使用了synchronized来保证线程安全,所以性能不是很高,于是在JDK1.5就有了StringBuilder,它同样提供了append和insert的拼接方法,但它没有…

4. String 的 intern() 方法有什么含义?

String常见的创建方式有两种,直接赋值的方式“Strings1=“Java”;”和“Strings2=newString(“Java”);”的方式,但两者在JVM的存储区域却截然在JDK1.8中,变量s1会先去字符串常量池中找字符串“Java”,如果有相同的字符则直接返回常量句柄,如果没有此字符串则会先在常量池中创建此字符串,然后再返回常量句柄;而变量s2是直接在堆上创建一个变量,如果调用 intern 方法才会把此字符串保存到常量池中,如下代码所示:

String-面试常考问题剖析

5.String 类型在 JVM(Java 虚拟机)中是如何存储的?编译器对 String 做了哪些优化?

JDK 1.7 之后把永生代换成的元空间,把字符串常量池从方法区移到了 Java 堆上。

除此之外编译器还会对 String 字符串做一些优化,例如以下代码:

String-面试常考问题剖析

虽然 s1 拼接了多个字符串,但对比的结果却是 true,我们查看Class 文件可以知道JDK优化了

String s1 = "Java";
String s2 = "Java";
//结果为true
System.out.println(s1 == s2);

相关标签: 面试总结