美文网首页Java
String类面试题

String类面试题

作者: h2coder | 来源:发表于2021-09-05 22:40 被阅读0次

String类的面试题,往往是面试的开端,如果String类的面试题都没有答好,那么给面试官的第一印象并不太好了

String 是如何实现的?它有哪些重要的方法?

String类的内部组成

以JDK1.8为例,发现String类实质是一个字符数组

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    //字符串的值
    private final char value[];
    //字符串的哈希码
    private int hash;
    //...
}
  • 多构造方法

String类有4个构造方法,其中容易忽略StringBufferStringBuilder为参数的构造方法

//以String字符串为参数的构造方法

public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

//以char[],字符数组为参数构造方法
public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}

//StringBuffer,为参数的构造方法
public String(StringBuffer buffer) {
    synchronized(buffer) {
        this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
    }
}

//StringBuilder,为参数的构造方法
public String(StringBuilder builder) {
    this.value = Arrays.copyOf(builder.getValue(), builder.length());
}

equals() 比较两个字符串是否相等

public boolean equals(Object anObject) {
    //对象引用相同直接返回 true
    if (this == anObject) {
        return true;
    }
    //判断需要对比的值是否为 String 类型,如果不是则直接返回 false
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            //把两个字符串都转换为 char 数组对比
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            // 循环比对两个字符串的每一个字符
            while (n-- != 0) {
                // 如果其中有一个字符不相等就 true false,否则继续对比
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

String类重写了Object类的equals()方法,该方法传入一个Object类型的对象,在比较时,先通过instanceof判断是否为String类型,如果不是则直接返回false,如果是,则会循环比较2个字符串的每一个字符,当所有字符都相等时,返回true

还有一个和equals()方法类型的equalsIgnoreCase()方法,它用于忽略字符大小写的比较

compareTo() 比较两个字符串

compareTo()用于比较2个字符串,返回值为int

public int compareTo(String anotherString) {
    int len1 = value.length;
    int len2 = anotherString.value.length;
    //获取到两个字符串长度最短的那个 int 值
    int lim = Math.min(len1, len2);
    char v1[] = value;
    char v2[] = anotherString.value;
    int k = 0;
    //对比每一个字符
    while (k < lim) {
        char c1 = v1[k];
        char c2 = v2[k];
        if (c1 != c2) {
            //有字符不相等就返回差值
            return c1 - c2;
        }
        k++;
    }
    return len1 - len2;
}

compareTo()方法中,会循环比较2个字符串的所有字符,当有一个字符不相等时,则返回2个字符的相减值c1 - c2,如2个字符串分别存储的是1和2,那么返回值为-1,如果存储的值是1和1,那么返回值为0,如果存储的是2和1,那么返回值为1

还有一个和compareTo()方法类似的compareToIgnoreCase()方法,用于忽略大小写的字符比较

综上所述,可以看出,compareTo()equals()都用于比较字符串,但它们有2点不同

  • equals()方法可以接收一个Object类型的参数,而compareTo()则只能接收一个String类型的参数
  • equals()返回值为 Boolean,而compareTo()的返回值则为int

它们都可以用于比较2个字符串的值,equals()方法返回true,或者compareTo()方法返回0时,2个字符串完全相同

String类的其他重要方法

  • indexOf():查询字符串首次出现的下标位置
  • lastIndexOf():查询字符串最后出现的下标位置
  • contains():查询字符串中是否包含另一个字符串
  • toLowerCase():把字符串全部转换成小写
  • toUpperCase():把字符串全部转换成大写
  • length():查询字符串的长度
  • trim():去掉字符串首尾空格
  • replace():替换字符串中的某些字符
  • split():把字符串分割并返回字符串数组
  • join():把字符串数组转为字符串

为什么 String 类型要用 final 修饰?,== 和 equals 的区别是什么?

== 和 equals 的区别

== 对于基本数据类型来说,比较的是是否相等,而对于引用类型来讲,比较的是对象的内存地址,而Object的equals()方法,使用的就是==进行比较

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

所以默认对象的equals()方法比较的就是对象的地址值,而子类可以复写该方法,例如String类就复写了equals()方法,比较2个字符串的值是否相等

public boolean equals(Object anObject) {
    //对象引用相同直接返回 true
    if (this == anObject) {
        return true;
    }
    //判断需要对比的值是否为 String 类型,如果不是则直接返回 false
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            //把两个字符串都转换为 char 数组对比
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            //循环比对两个字符串的每一个字符
            while (n-- != 0) {
                //如果其中有一个字符不相等就 true false,否则继续对比
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

final 修饰的好处

String类的源码可以看出,String类是final修饰的不可变类

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    //...
}

主要原因有2点,一个是安全,另外一个是高效,理由如下:

  • 安全
    • 在调用其他方法时,比如调用一些系统级操作指令之前,可能会有一系列校验,如果是可变类的话,可能在校验过后,它的内部的值又被改变了,这样有可能会引起严重的系统崩溃问题
  • 高效
    • 它能够缓存结果,当你在传参时不需要考虑谁会修改它的值,如果是可变类的话,则有可能需要重新拷贝出来一个新值进行传参,这样在性能上就会有一定的损失

以JVM常量池来讲

String s1 = "java";
String s2 = "java";

只有字符串时不可变时,我们才能够实现字符串常量池,字符串常量池可以缓存字符串,提高程序的运行效率

如果String类是可变的,当我们修改s1的值后,s2也跟着变了,这样和我们预期就不相符了,因此也没办法实现字符串常量池了

String 和 StringBuilder、StringBuffer 的区别

因为String类是不可变类,所以在字符串拼接时,性能会很低,这时我们需要使用StringBuffer,它提供了appendinsert,用于字符串拼接,它使用synchronized关键字来保证线程安全

@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;
}

因为它使用synchronized关键字来保证线程安全,所以它的性能不是很高,于是在JDK 1.5中,提供了StringBuilder,它同样提供了appendinsert,但它没有使用synchronized关键字来修饰,因此性能优于StringBuffer,所以在非并发环境下可以使用StringBuilder

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

String类的intern()方法是一个native方法

public native String intern();

它会先从字符串常量池中查找,如果存在,则直接返回该引用,如果不存在,则创建该字符串,再放到字符串常量池中,再返回

String 和 JVM

String的常见创建方式有2种,new String()和字面量赋值,字面量赋值会先去常量池中查找是否有该值的字符串,如果有则直接把引用地址指向该值,如果没有则先会在常量池中创建,再把引用指向该值。而new String()是直接在堆上创建一个字符串对象,然后再去常量池中查找是否存在该值,不存在则在常量池中创建,再把引用的值指向该字符串

//堆上直接创建一个String类对象
String s1 = new String("Java");
//从常量池中查询,找得到则使用,找不到则创建,再把字符串拷贝到常量池,它和s1不是同一个对象
String s2 = s1.intern();
//字面量声明,从常量池中查找,找到s2,所以s2和s3是同一个对象
String s3 = "Java";
System.out.println(s1 == s2); //false
System.out.println(s2 == s3); //true

除此以外,JVM还会对字符串做优化,在使用+号拼接字符串时,会直接把字面量组合成新的值

String s1 = "Ja" + "va";
String s2 = "Java";
System.out.println(s1 == s2);//true

结果是true,因为编译器在编译时做了优化,直接把"ja" + "va"编译成了"java",所以s1实际是"java",然后存放在了字符串常量池中,而s2再去常量池中找时,则找到s1,所以他们是同一个对象

相关文章

网友评论

    本文标题:String类面试题

    本文链接:https://www.haomeiwen.com/subject/temswltx.html