Java String面试题汇总


给定的Java String面试问题涵盖了字符串方法、字符串不可变性和内存泄漏问题,以及简单的示例和用例。我将尽力涵盖Java面试中最常问的String类相关问题。

Java中String是关键字吗?

不是的。String不是Java中的保留关键字。它是一种派生数据类型,也就是一个类。

public class StringExample
{
    public static void main(String[] args)
    {
        Integer String = 10;
        System.out.println(String);        //输出 10
    }
}

为什么String是不可变的?

第一个原因是性能改进。Java语言的开发旨在加快应用程序的开发速度,因为在之前的语言中它的速度不是那么快。JVM的设计者必须足够聪明,能够识别到实际应用程序将主要由字符串组成,这些字符串是标签、消息、配置、输出和其他形式的数据。看到这种过度使用,他们想象了字符串的不当使用可能有多危险。因此,他们提出了字符串池的概念。字符串池实际上是一组大部分是唯一的字符串。字符串池背后的基本思想是一旦创建了字符串,就可以重用它。这样,如果在代码中创建了一个特定的字符串20次,应用程序只有一个实例。

我认为第二个原因是安全性考虑。字符串是Java编程的各个方面中最常用的参数类型。无论是加载驱动程序还是打开URL连接,都需要将信息作为字符串参数传递。如果字符串不是不可变的,就会引发一系列安全性问题。

什么是字符串常量池?

字符串常量池是常规堆内存中的一块特定内存区域,用于存储这些字符串常量。在应用程序的生命周期中,字符串变量引用这些常量。

在Java中,我们可以通过多种方式创建字符串。例如,使用字符串字面值和使用new关键字。

String str1 = "abc";
String str2 = new String("abc");

使用字符串字面值会导致JVM验证是否已经存在一个与字符串”abc”(相同的字符序列)。如果存在这样的字符串,JVM会将现有对象的引用赋给变量str;否则,将创建一个新的对象”abc”,并将其引用赋给变量str1。

当使用new关键字时,Java会在正常的堆内存中创建一个新的String对象。我们必须使用intern方法将字符串从堆内存移到字符串池中。

为了更好地利用内存并提高性能,建议使用字符串字面值来创建字符串。除非需要显式复制原始字符串,否则不需要使用构造函数,因为字符串是不可变的。

什么是String intern()?

当调用String的intern()方法时,如果字符串池已经包含与此字符串相同内容的字符串(由equals()方法确定),则返回池中的引用。否则,将此String对象添加到池中,并返回池中此新String对象的引用。

简单来说,字符串池化是将一个String对象从常规堆内存移动到字符串常量池中,并使用池中的对象引用的过程。

String str = new String("abc");
str.intern();

对于intern()方法,对于任何两个字符串s1和s2,只有当s1.equals(s2)为true时,s1.intern() == s2.intern()才为true。

这意味着如果s1和s2是不同的字符串对象,并且具有相同的字符序列,那么在两者上调用intern()将导致由两个变量引用的单个字符串池字面值。

默认情况下,请记住所有字面字符串和具有字符串值的常量表达式都会被池化。

如何使用正则表达式查找匹配的字符串?

我们可以使用Pattern和Matcher API进行正则表达式匹配。String类提供了自己的matches()方法。我们应该直接使用matches()方法。该方法在函数定义内部也使用Pattern.matches()。

String str = new String("Welcome to panziye.com");
System.out.println(str.matches("(.*)ziye(.*)"));    //Prints true
System.out.println(Str.matches("(.*)www(.*)"));  //Print false

如何比较两个字符串?

面试中的另一个受欢迎的领域。通常有两种比较对象的方法:

  • 使用==运算符
  • 使用equals()方法

==运算符用于比较对象引用。因此,如果两个字符串对象引用字符串池中的相同字面值或堆中的相同字符串对象,则’s == t’将返回true,否则返回false。

equals()方法在String类中被重写,并验证String对象所持有的字符序列。换句话说,equals()方法比较字符串对象的值。如果它们存储相同的字符序列,’s.equals(t)’将返回true,否则返回false。

Java中的字符串是如何工作的?

与其他编程语言一样,Java中的字符串是字符序列。这更像是一个用于处理该字符序列的实用类。这个字符序列以char数组类型的以下变量维护:

/** 值使用char 数组存储 */
private final char value[];

各种字符串方法在不同的情况下使用以下变量来维护数组中的位置:

/** 偏移量(offset)是存储中首个被使用的索引。*/
private final int offset;
/** 计数(count)是字符串中字符的数量。 */
private final int count;

如何检查回文字符串?

如果一个字符串的值在反转后仍然相同,那么它就是回文字符串。要检查回文字符串,可以将字符串反转,然后将其与原始字符串进行比较。

如果原始字符串和反转后的字符串相同,那么给定的字符串就是回文字符串。

String originalString = "abcdcba";
StringBuilder strBuilder = new StringBuilder(originalString);
String reverseString = strBuilder.reverse().toString();
boolean isPalindrame = originalString.equals(reverseString);
System.out.println(isPalindrame);    //true

如何在字符串中删除或替换字符?

要替换或删除字符,可以使用String.replace()或String.replaceAll()方法。

这两种方法都接受两个参数。第一个参数是要替换的字符,第二个参数是要放入字符串中的新字符。

如果想删除字符,可以在第二个参数中传递空字符。

String originalString = "howtodoinjava";
//Replace one character
System.out.println( originalString.replace("h", "H") );         //Howtodoinjava
//Replace all matching characters
System.out.println( originalString.replaceAll("o", "O") );      //hOwtOdOinjava
//Remove one character
System.out.println( originalString.replace("h", "") );         //owtodoinjava
//Remove all matching characters
System.out.println( originalString.replace("o", "") );         //hwtdinjava

如何将字符串转换为小写或大写?

要将字符串转换为小写或大写,可以使用String.toLowerCase()和String.toUpperCase()方法。

String blogName = "PanZiYe.com";
System.out.println(blogName.toLowerCase());     //panziye.com
System.out.println(blogName.toUpperCase());     //PANZIYE.COM

我们可以在’ switch ‘语句中使用String吗?

可以,自Java 7以来,我们可以在switch语句中使用String类。在Java 7之前,这是不可以的,我们必须使用if-else语句来实现类似的功能。

如何打印一个字符串的所有排列组合?

排列是将字符元素重新排列,以使每个排列在其他排列方面都是唯一的。例如,下面是字符串“ABC”的排列 – ABC、ACB、BAC、BCA、CBA 和 CAB。

长度为N的字符串有N!(N阶乘)个排列。

import java.util.HashSet;
import java.util.Set;
public class StringExample
{
    public static void main(String[] args)
    {
        System.out.println(getPermutations("ABC"));
        //Prints
        //[ACB, BCA, ABC, CBA, BAC, CAB]
    }
    public static Set<String> getPermutations(String string)
    {
        //All permutations
        Set<String> permutationsSet = new HashSet<String>();
        // invalid strings
        if (string == null || string.length() == 0)
        {
            permutationsSet.add("");
        }
        else
        {
            //First character in String
            char initial = string.charAt(0);
            //Full string without first character
            String rem = string.substring(1);
            //Recursive call
            Set<String> wordSet = getPermutations(rem);
            for (String word : wordSet) {
                for (int i = 0; i <= word.length(); i++) {
                    permutationsSet.add(charInsertAt(word, initial, i));
                }
            }
        }
        return permutationsSet;
    }
    public static String charInsertAt(String str, char c, int position)
    {
        String begin = str.substring(0, position);
        String end = str.substring(position);
        return begin + c + end;
    }
}

如何翻转字符串中的每个单词?

要分别翻转每个单词,首先要对字符串进行分词,将所有单词分隔成一个数组。然后,对每个单词应用翻转单词的逻辑,最后将所有单词连接起来。具体代码可以参考:反转字符串中的单词

如何分割一个字符串?

使用String.split()方法,该方法会根据给定的正则表达式来分割字符串。它也被称为根据分隔符获取字符串标记。

split()方法返回一个字符串数组,数组中的每个字符串都是一个独立的标记。

为什么不应该使用字符串来存储密码?

我们知道在Java中,字符串存储在常量池中。一旦一个字符串被创建在字符串池中,它会一直在池中存在,除非被垃圾回收。在这段时间内,任何恶意程序都可以访问物理内存中的内存区域并访问字符串数据。

如果我们将密码存储为一个字符串,它将在内存中保留的时间比所需的时间长,因为垃圾收集周期是不可预测的。这会使敏感的密码字符串容易受到黑客攻击和数据盗窃的威胁。

有人可能会提出一个观点,即在使用后将字符串设置为空。但是,这是不可行的,因为我们知道一旦一个字符串被创建,就无法操纵它,例如无法更改它的内容。字符串是不可变的。

但是,字符数组是可变的,我们可以在使用后覆盖它们的内容。因此,我们的应用程序应该使用char[]来存储密码文本,并在使用密码后替换数组内容为空白。

总之,使用char[]而不是字符串来存储密码是更安全的做法,因为它可以在使用后覆盖密码,减少了敏感信息被恶意访问的风险。这是更好的密码安全实践。

String password = "123456";     //不能使用字符串
char[] passwordChars = new char[4];      //从数据库等系统中获取密码。
//使用密码
for(char c : passwordChars) {
    c = ' ';
}

字符串是线程安全的吗?

是的,字符串是线程安全的,因为它们是不可变的。

请记住,所有不可变的实例都是线程安全的,这是它们的设计特点。

为什么String是HashMap键的最佳选择?

在Java中,Map的键必须是不可变的,并且应该遵守equals()和hashCode()方法之间的约定。String类满足这两个条件。

此外,String类提供了许多有用的方法,用于比较、排序、分词或大小写转换。在对Map执行CRUD操作时,可以使用这些方法。

所有这些特点使得String类非常适合用作Map中的键,而不是创建我们自己的类。

String、StringBuffer和StringBuilder之间有什么区别?

String类表示字符序列,并提供了处理字符的有用方法。String类的实例是不可变的。因此,每次我们使用String类进行字符串连接时,都会创建一个新对象,其中包含连接后的字符串。 StringBuilder类用于以更节省内存的方式执行字符串连接操作。它在内部维护char[],只在这个数组中操作内容。当我们在执行所有操作后需要获取完整的连接字符串时,它会使用存储的字符数组创建一个新的String。 StringBuffer与StringBuilder类非常相似,唯一的区别是它是线程安全的,它的所有方法都是同步的。

如何连接多个字符串?

根据是否需要线程安全,使用StringBuffer或StringBuilder类。在这两个类中,使用append()方法来连接字符串。

统计给定程序中的字符串对象数量

String s1 = "panziye.com";
String s2 = "panziye.com";
String s3 = new String("panziye.com");
  • 上面的代码将创建2个对象。
  • 第一条语句将在字符串池中创建第一个字符串字面量。
  • 第二条语句不会创建任何新对象,s2将引用与s1相同的字符串常量。
  • 第三条语句将在堆内存中创建一个新的字符串对象。

统计字符串中每个字符的出现次数?

要找出给定字符串中每个字符的出现次数,我们使用了HashMap,其中字符作为键,其出现次数作为值。

每次字符出现新的次数时,我们将增加该字符的计数值。代码实现可以参考《Java中查找字符串中的重复字符》

在不使用 StringBuilder 或 StringBuffer 的情况下反转字符串?

反转字符串的最佳方法是使用 StringBuffer.reverse() 和 StringBuilder.reverse() 方法。尽管如此,面试官可能会要求您编写自己的程序,以检查您的技能水平。

请使用下面给出的基于递归的示例来反转字符串。

该程序从字符串中取出第一个字符,并将其放置在字符串的最后位置。它使用这种替换方式来反转字符串中的所有字符,直到整个字符串被反转。

具体代码实现可以参考:《基于递归的示例来反转字符串》

总结

以上就是我认为面试时经常被问到的关于String类问题,希望对你的面试有帮助。如果你知道更多关于Java String面试题问题,可以留言。



Java 字符串常量池

香港数码港发布声明,暗网上出现员工和求职者的被盗数据

获取更多资讯请加入交流群


    协助本站SEO优化一下,谢谢!
    关键词不能为空
评 论
更换验证码