String-面试常考问题剖析

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

为啥这样设计呢?, 请带着这一个疑问看下去,从 String 类的源码我们可以看出 String 是被 final 修饰的不可继承类,源码如下:
在这里插入图片描述

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

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

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

1.安全

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

2.高效

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

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

只有字符串是不可变时,我们才能实现字符串常量池,字符串常量池可以为我们缓存字符串,提高程序的运行效率,如下图所示:
在这里插入图片描述
试想一下如果 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 来保证线程安全,如下源码所示:

在这里插入图片描述
因为它使用了synchronized来保证线程安全,所以性能不是很高,于是在JDK1.5就有了StringBuilder,它同样提供了append和insert的拼接方法,但它没有…

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

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

在这里插入图片描述

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

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

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

在这里插入图片描述

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

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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值