前 24 个 Java 字符串面试问题及答案

位置:首页>文章>详情   分类: Java教程 > 编程技术   阅读(310)   2023-06-26 07:54:18

给定的 Java 字符串面试问题 范围从字符串方法、字符串不可变性和内存泄漏问题到简单的示例和用例。我将尝试涵盖 Java 面试中最常被问到的问题

1.String是Java中的关键字吗?

不是。String 不是 Java 保留关键字。它是派生数据类型,即它是一个类。

public class StringExample
{
    public static void main(String[] args)
    {
        Integer String = 10;

        System.out.println(String);		//Prints 10
    }
}

2. 为什么字符串是不可变的?

我们都知道 Java 中的字符串是不可变的。如果您想知道什么是不变性以及它是如何实现的?关注这篇文章:How to使 java 类不可变?

这里的问题是为什么?为什么不可变?让我们分析一下。

  1. 第一个原因是性能提升。开发 Java 语言是为了加快应用程序的开发,因为它在以前的语言中并没有那么快。 JVM 设计者一定足够聪明,可以识别出现实世界的应用程序将主要由标签、消息、配置、输出等多种形式的字符串组成。

    看到这样的过度使用,他们想象字符串的不当使用会有多危险。于是他们想出了字符串池的概念。字符串池只不过是一些大多数唯一的字符串的集合。字符串池背后的基本思想是重用创建后的字符串。这样一来,如果某个特定字符串在代码中创建了 20 次,应用程序最终将只有一个实例。

  2. 我认为的第二个原因是安全考虑。字符串是java编程各个方面最常用的参数类型。无论是加载驱动程序还是打开 URL 连接,都需要以字符串形式将信息作为参数传递。如果字符串不是最终的,那么它们就打开了安全问题的潘多拉盒子。

3.什么是字符串常量池?

字符串池是常规堆内存中的一个特定内存区域,其中存储了这些字符串常量。这些对象在应用程序的生命周期中被引用为字符串变量。

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

String str1 = "abc";

String str2 = new String("abc");

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

使用 new 关键字时,Java 最终会在内存中创建两个对象。字符串池中的一个对象具有字符序列“abc”,第二个对象位于常规堆内存中,由变量 str2 引用并具有与“abc”相同的字符序列。

为了获得更好的内存利用率和整体性能,建议使用字符串文字来创建字符串。 除非需要原始的显式副本,否则不需要使用构造函数,因为字符串是不可变的

4. String intern() 过程是什么?

调用 String intern() 方法时,如果字符串池中已经包含等于 String 对象的字符串,由 equals(Object) 方法,然后返回池中的字符串。否则,会将此 String 对象添加到池中,并返回对此 String 对象的引用。

简单来说,string interning 是将 String 对象从常规堆内存移动到 String 常量并使用池中的对象引用的过程。

String str = new String("abc");

str.intern();

对于intern()方法,对于任意两个字符串s1s2s1.intern() == t2.intern( )true 当且仅当 s1.equals(s2)true 时。

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

默认情况下,请记住所有文字字符串和字符串值常量表达式都是驻留的。

5.如何用正则表达式匹配字符串?

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

String str = new String("Welcome to howtodoinjava.com");
 
System.out.println(str.matches("(.*)java(.*)"));    //Prints true
System.out.println(Str.matches("(.*)python(.*)"));  //Print false

6.如何比较字符串?

采访中另一个最喜欢的领域。比较对象一般有两种方式

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

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

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

7.解释substring()方法引起的内存泄漏问题?

到现在为止,我们已经完成了基本的工作。现在是严肃的事情。您是否尝试过从字符串对象创建子字符串?我敢打赌,是的。你知道 Java 中 substring 的内部结构吗?它们是如何造成内存泄漏的?

Java 中的子字符串是使用方法 substring(int beginIndex) 和该方法的一些其他重载形式创建的。所有这些方法都会创建一个新的 String 对象并更新我们在本文开头看到的 offset 和 count 变量。

原始值[]没有改变。因此,如果您创建一个包含 10000 个字符的字符串并创建 100 个子字符串,每个子字符串包含 5-10 个字符,则所有 101 个对象将具有大小为 10000 个字符的相同字符数组。毫无疑问,这是内存浪费。

让我们用一个程序看看:

import java.lang.reflect.Field;
import java.util.Arrays;
 
public class SubStringTest {
    public static void main(String[] args) throws Exception
    {
        //Our main String
        String mainString = "i_love_java";
        //Substring holds value 'java'
        String subString = mainString.substring(7);
 
        System.out.println(mainString);
        System.out.println(subString);
 
        //Lets see what's inside mainString
        Field innerCharArray = String.class.getDeclaredField("value");
        innerCharArray.setAccessible(true);
        char[] chars = (char[]) innerCharArray.get(mainString);
        System.out.println(Arrays.toString(chars));
 
        //Now peek inside subString
        chars = (char[]) innerCharArray.get(subString);
        System.out.println(Arrays.toString(chars));
    }
}
i_love_java
java
[i, _, l, o, v, e, _, j, a, v, a]
[i, _, l, o, v, e, _, j, a, v, a]

显然,两个对象都存储了相同的 char 数组,而子字符串只需要四个字符。

让我们使用自己的代码来解决这个问题:

import java.lang.reflect.Field;
import java.util.Arrays;
 
public class SubStringTest
{
    public static void main(String[] args) throws Exception
    {
        //Our main String
        String mainString = "i_love_java";
        //Substring holds value 'java'
        String subString = fancySubstring(7, mainString);
 
        System.out.println(mainString);
        System.out.println(subString);
 
        //Lets see what's inside mainString
        Field innerCharArray = String.class.getDeclaredField("value");
        innerCharArray.setAccessible(true);
        char[] chars = (char[]) innerCharArray.get(mainString);
        System.out.println(Arrays.toString(chars));
 
        //Now peek inside subString
        chars = (char[]) innerCharArray.get(subString);
        System.out.println(Arrays.toString(chars));
    }
 
    //Our new method prevents memory leakage
    public static String fancySubstring(int beginIndex, String original)
    {
        return new String(original.substring(beginIndex));
    }
}
i_love_java
java
[i, _, l, o, v, e, _, j, a, v, a]
[j, a, v, a]

现在子字符串只有它需要的字符,用于创建正确子字符串的中间字符串可以被垃圾收集,因此不会留下内存足迹。

8. 字符串如何在 Java 中工作?

与任何其他编程语言一样,Java 中的字符串是字符序列。这更像是一个处理该字符序列的实用程序类。此 char 序列保存在以下 char array 类型的变量中:

/** The value is used for character storage. */
private final char value[];

各种字符串方法在不同的场景下对这个数组进行操作,使用以下变量来维护数组中的位置:

/** The offset is the first index of the storage that is used. */
private final int offset;
 
/** The count is the number of characters in the String. */
private final int count;

10. 如何检查回文串?

如果一个字符串在反转时其值相同,则它是回文串。 要检查回文,将字符串反转并与原始字符串进行比较

如果原始字符串和反转字符串相同,则给定字符串是回文。

String originalString = "abcdcba";
         
StringBuilder strBuilder = new StringBuilder(originalString);
String reverseString = strBuilder.reverse().toString();

 
boolean isPalindrame = originalString.equals(reverseString);

System.out.println(isPalindrame);    //true

11. 如何删除或替换字符串中的字符?

要替换或删除字符,请使用 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

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

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

String blogName = "HowToDoInJava.com";

System.out.println(blogName.toLowerCase());     //howtodoinjava.com

System.out.println(blogName.toUpperCase());     //HOWTODOINJAVA.COM

13. 我们可以在“switch”语句中使用字符串吗?

是的,我们可以在 switchString 类code> statements since Java 7. 在 Java 7 之前,这是不可能的,我们必须使用 if-else 语句来实现类似的行为。

String number = "1";

switch (number)
{
case "1":
    System.out.println("One");	//Prints '1'
    break;
case "2":
    System.out.println("Two");
    break;
default:
    System.out.println("Other");
}

14.如何打印字符串的所有排列?

排列是字符元素的重新排列,因此每个排列相对于其他排列都是唯一的。例如,下面是字符串“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;
    }
}

15.如何反转字符串中的每个单词?

要分别反转每个单词,将字符串标记化并将所有单词分隔在一个数组中。然后,对每个单词应用反向单词逻辑,最后,连接所有单词。

String blogName = "how to do in java dot com";
 
//spilt on white space
String[] tokens = blogName.split(" ");
 
//It will store reversed words 
StringBuffer finalString = new StringBuffer();
 
//Loop all words and reverse them
for (String token : tokens) {
    String reversed = new StringBuffer(token).reverse().toString();
    finalString.append(reversed);
    finalString.append(" ");
}
 
//Check final string
System.out.println(finalString.toString());     //woh ot od ni avaj tod moc

16.如何拆分字符串?

使用 String.split()< /code> 在给定正则表达式的匹配项周围断开给定字符串的方法。它也称为获取基于定界符的字符串标记

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

String numbers = "1,2,3,4,5,6,7";
         
String[] numArray = numbers.split(",");
 
System.out.println(Arrays.toString(numArray));  //[1, 2, 3, 4, 5, 6, 7]

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

我们知道在Java中字符串是保存在常量池中的。一旦在字符串池中创建了一个字符串,它就会留在池中,除非被垃圾回收。此时,任何恶意程序都可以访问物理内存中的内存区域,也可以访问字符串数据。

如果我们将密码存储为字符串,它将保存在 spring 池中,并且在内存中可用的时间比所需的时间更长,因为垃圾收集周期是不可预测的。这使得敏感的密码字符串容易受到黑客攻击和数据窃取

是否可以争论一个选项在使用后将 String 设为空白?不,我们不可以。我们知道,一旦创建了 String,我们就无法对其进行操作,例如你不能改变它的内容。 字符串是最终的和不可变的

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

String password = "123456";     //Do not use it
         
char[] passwordChars = new char[4];      //Get password from some system such as database
 
//use password
 
for(char c : passwordChars) {
    c = ' ';
}

18. 字符串是线程安全的吗?

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

请记住,所有不可变实例在设计上都是线程安全的。

19. 为什么使用String作为HashMap的Keys?

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

此外,String 类提供了许多有用的方法来比较、排序、标记化或大写大小写。在 Map 上执行 CRUD 操作时可以使用这些方法。

所有这些使 String 成为一个非常有用的类,可以在 Map 中使用,而不是创建我们自己的类。

20.String、StringBuffer、StringBuilder的区别?

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

21.如何连接多个字符串?

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

StringBuffer buffer = new StringBuffer();
         
buffer.append("how")
        .append("to")
        .append("do")
        .append("in")
        .append("java")
        .append(".")
        .append("com");
 
String blogName = buffer.toString();
 
System.out.println(blogName); //howtodoinjava.com

22. 计算给定程序中字符串对象的数量?

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

23. 计算字符串中每个字符出现的次数?

为了找到给定字符串中每个字符的出现次数,我们使用了 HashMap 并将该字符作为 key 并将其出现次数作为 value

每次新出现一个字符,我们都会增加该字符的计数器

String blogName = "howtodoinjava.com";
 
HashMap<Character, Integer> occurancesMap = new HashMap<Character, Integer>();
 
char[] strArray = blogName.toCharArray();
 
for (char c : strArray)
{
    if(occurancesMap.containsKey(c))
    {
        occurancesMap.put(c, occurancesMap.get(c)+1);
    }
    else
    {
        occurancesMap.put(c, 1);
    }
}
 
System.out.println(occurancesMap);
//{a=2, c=1, d=1, h=1, i=1, j=1, m=1, n=1, .=1, o=4, t=1, v=1, w=1}

24. 在没有 StringBuilder 或 StringBuffer 的情况下反转字符串?

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

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

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

public class StringExample
{
    public static void main(String[] args) 
    {
        String blogName = "howtodoinjava.com";
         
        String reverseString = recursiveSwap(blogName);
         
        System.out.println(reverseString);
    }
     
    static String recursiveSwap(String str)
    {
         if ((null == str) || (str.length() <= 1))
         {
                return str;
         }
         return recursiveSwap(str.substring(1)) + str.charAt(0);
    }
}

我认为这些String 面试常见问题 会对您的下一次面试有所帮助。

地址:https://www.cundage.com/article/string-questions.html

相关阅读

给定的 Java 字符串面试问题 范围从字符串方法、字符串不可变性和内存泄漏问题到简单的示例和用例。我将尝试涵盖 Java 面试中最常被问到的问题。 1.String是Java中的关键字吗? 不...
在“HashMap 如何在 Java 中工作“,我们了解了 HashMap 或 ConcurrentHashMap 类的内部结构,以及它们如何融入整个概念。但是当面试官问你HashMap相关概念...
Java String compareTo() 方法按字典顺序比较两个字符串。我们可以认为它是基于字典的比较。 1.字符串比较 如果字符串 'str1' 在字典中出现在另一个字符串 'str2'...
java.lang.String.charAt(int index) 方法返回 index 参数处的字符series/java-string/"&gtl;String 对象。 正如我们所知,Ja...
3 个使用 Long.parseLong(String)、Long.valueOf(String) 和 new Long(String) 构造函数将 String 转换为 long 值的 Jav...
Java String equals() 方法用于将字符串与方法参数对象进行比较。 1.Java String.equals() 方法 /** * @param anObject - The ...
要将整数转换为字符串,请使用String.valueOf() 或Integer.toString() 方法。 1. 将 int 转换为 String – String.valueOf() Str...
Java String compareToIgnoreCase() 方法按字典顺序比较两个字符串忽略大小写。此方法与 String.compareTo() 方法相同,除了 compareTo (...
Java String equalsIgnoreCase() 方法用于比较字符串与方法参数对象,忽略案例考虑。 在 equalsIgnoreCase() 方法中,如果两个字符串的长度相同并且两个...
学习使用 Float.toString() 和 String.valueOf() 方法将浮点值转换为字符串。学习将浮点数格式化为字符串到 n 个小数点。 1.Java将float转String ...