Java字符串面试问题与答案

我们所有人都必须通过与Java中的String类有关的面试问题。这些String面试问题的范围从不变性到内存泄漏问题。我将在这篇文章中尝试解决此类问题。

常见的字符串面试问题

1。 Java中的String关键字吗?
2.为什么字符串是不可变的?
3.什么是字符串常量池?
4.关键字“实习生”的用法
5.匹配正则表达式?
6.用equals()和'=='进行字符串比较?
7。 String类中的内存泄漏问题
8。 String在Java中如何工作?
9.创建字符串对象有哪些不同的方法?
10.如何检查String是否为回文。
11.如何从字符串中删除或替换字符。
12.如何使String大写或小写?
13.如何在Java程序中比较两个字符串?
14.我们可以在开关盒中使用String吗?
15.编写一个程序以打印String的所有排列?
16.编写一个Java程序来反转给定字符串的每个单词?
17.如何在Java中拆分字符串?
18.为什么使用Char数组而不是String来存储密码?
19。 Java中的String线程安全吗?
20.为什么String是Java中 popular 的HashMap键
21。 String,StringBuffer和StringBuilder之间的区别?
22.如何连接多个字符串。
23.使用字符串初始化代码将创建多少个对象?
24.如何计算字符串中每个字符的出现次数?
25.编写一个Java程序来反转字符串?

1。 Java中的String关键字吗?

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

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

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

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

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

  1. 我能想到的第一个原因是性能提高。开发Java语言是为了加快应用程序开发,因为以前的语言并没有那么快。JVM设计人员必须足够聪明,才能识别出现实世界中的应用程序将主要由标签,消息,配置,输出等多种形式的字符串组成。看到这种过度使用,他们想象不正确使用字符串会带来多大的危险。因此,他们提出了字符串池的概念(下一部分)。字符串池不过是一些大多数唯一字符串的集合。字符串池背后的最基本思想是重新创建字符串。这样,如果一个特定的字符串在代码中创建了20次,则应用程序最终将只有一个实例。
  2. 我将第二个原因视为安全考虑。字符串是Java编程各个方面中最常用的参数类型。无论是加载驱动程序还是打开URL连接,您都需要以字符串形式将信息作为参数传递。如果字符串不是最后的字符串,那么它们会打开一个安全问题的潘多拉盒。我们所有人都必须通过与Java中的String类相关的访谈问题。这些问题的范围从不变性到内存泄漏问题。我将在这篇文章中尝试解决此类问题。

除了上述两个原因外,我没有找到任何令人信服的答案。如果您有任何吸引人的内容,请与我分享。

3.字符串池概念

字符串池是一个特殊的内存区域,与存储这些字符串常量的常规堆内存分开。这些对象在应用程序的生命周期中称为字符串变量。

在Java中,可以通过多种方式创建String。让我们了解它们:

1)字符串分配

String str = "abc";

上面的代码使JVM验证是否已经有一个字符串“ abc”(相同的字符序列)。如果存在这样的字符串,JVM会简单地将现有对象的引用分配给variable str,否则,将创建一个新的对象“ abc”并将其引用分配给variable str

2)使用新关键字

String str = new String("abc");

这个版本最终在内存中创建两个对象。字符串池中的一个对象具有char序列“ abc”,第二个对象在堆存储器中由变量引用,str并且具有与“ abc”相同的char序列。

如java docs所说:除非需要显式的原始副本,否则不需要使用此构造函数,因为String是不可变的。

4.关键字“实习生”的用法

这是java docs最好的描述:

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

String str = new String("abc");

str.intern();

它遵循对于任何两个字符串sts.intern() == t.intern()true当且仅当s.equals(t)true。意味着如果s和t都是不同的字符串对象,并且具有相同的字符序列,则在这两个变量上调用intern()将导致两个变量引用的单个字符串池文字。

5.匹配正则表达式

如果您还没有探索的话,它并不是那么秘密,但很有用。您必须已经了解过将Pattern和Matcher用于正则表达式匹配的用法。字符串类提供了自己的快捷方式。直接使用它。此方法还在函数定义内使用Pattern.matches()

String str = new String("abc");

str.matches("<regex>");

6.使用equals()和’==’进行字符串比较

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

  • 使用== Operator
  • 使用equals()方法

== Operator 比较对象引用,即内存地址相等。因此,如果两个字符串对象在字符串池中引用相同的文字或堆中的相同字符串对象,s==t则将返回true否则false

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

7.内存泄漏问题

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

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

Output:

i_love_java
java
[i, _, l, o, v, e, _, j, a, v, a]
[i, _, l, o, v, e, _, j, a, v, a]

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

让我们使用自己的代码解决此问题:

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

Output:

i_love_java
java
[i, _, l, o, v, e, _, j, a, v, a]
[j, a, v, a]

现在,子字符串只有它需要的字符,并且可以无用地收集用于创建正确子字符串的中间字符串,从而不占用内存。

8。 String如何在Java中工作?

Java中的字符串类似于任何其他编程语言,都是字符序列。这更像是用于该char序列的实用程序类。此char序列在以下变量中维护:

/** 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.如何检查回文中的字符串?

如果字符串的值在反转时相同,则称其为回文。要检查回文,只需反转字符串并检查原始字符串和受尊敬的字符串的内容。

public class StringExample 
{
    public static void main(String[] args) 
    {
        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中删除或替换字符?

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

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

String blogName = "how2codex.com";

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

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

13.如何在Java程序中比较两个字符串?

始终使用equals()方法验证字符串是否相等。切勿使用"==" Operator 。双重等于 Operator 始终检查内存中的对象引用。equals()方法检查String的内容。

String blogName = "how2codex.com";
        
String anotherString = new String("how2codex.com");

System.out.println(blogName == anotherString);     //false

System.out.println(blogName.equals(anotherString));     //true

14.我们可以在开关盒中使用String吗?

是的,从Java 7开始,您就可以Stringswitch语句中使用。在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");
}

15.编写一个程序以打印String的所有排列?

排列是对字符的有序列表的元素进行重新排列,以使每个排列相对于其他排列都是唯一的。例如,下面是字符串“ ABC”的排列– ABC ACB BAC BCA CBA CAB。

一串长度NN! (N Factorial)排列。

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

16.编写一个Java程序来反转给定字符串的每个单词?

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

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

17.如何在Java中拆分字符串?

使用String.split()方法,该方法在给定正则表达式的匹配项周围破坏给定字符串。也称为基于定界符的获取字符串标记

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]

18.为什么用Char数组而不是String来首选Char数组来存储密码?

我们知道字符串存储在Java的常量池中。一旦在字符串池中创建了一个字符串,它将一直保留在该池中,直到收集到垃圾为止。这时,任何恶意程序都可以访问物理内存位置中的内存位置,也可以访问字符串。

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

使用后可以将String留空吗?不,我们不可以。我们知道一旦创建了字符串,我们将无法对其进行操作,例如,您无法更改其内容。字符串是最终的且不可变的。

但是char数组是可变的,使用后它们的内容可以被覆盖。因此,您的应用程序应使用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 = ' ';
}

19。 Java中的字符串线程安全吗?

是的,字符串是线程安全的。它们是不可变的,默认情况下,java中所有不可变的实例都是线程安全的。

20.为什么String是Java中 popular 的HashMap键?

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

另外,String类提供了许多有用的方法来比较,排序,标记化或小写。在上执行CRUD操作时可以使用这些方法Map。它使它成为一个非常有用的类,Map而不是创建自己的类。

21。 String,StringBuffer和StringBuilder之间的区别?

  • String类表示字符序列,并提供了使用字符的有用方法。字符串类实例是不可变的。因此,每次使用字符串类执行字符串连接时,都会使用连接的字符串创建一个新对象。
  • StringBuilder类用于以更有效的内存方式执行字符串连接操作。它在内部维护a char array并仅操作此数组中的内容。执行完所有操作后需要获取完整的串联字符串时,它将创建一个具有字符数组内容的新String。
  • StringBufferStringBuilder上课很像 唯一的区别是它是线程安全的。都是方法synchronized

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

根据您的需要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); //how2codex.com

23.使用字符串初始化代码将创建多少个对象?

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

24.如何计算字符串中每个字符的出现次数?

为了找到给定字符串中每个字符的出现次数,我们使用HashMap了该字符作为键,并将其出现作为值的情况。每次出现新的字符时,我们将增加该字符的值。

String blogName = "how2codex.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}

25.编写一个Java程序来反转没有StringBuilder或StringBuffer的字符串?

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

使用下面给出的基于递归的示例来反转字符串。该程序从字符串中获取第一个字符,并将其放置在字符串中的最后一个位置。它将替换字符串中的所有字符,直到验证整个字符串为止。

public class StringExample
{
    public static void main(String[] args) 
    {
        String blogName = "how2codex.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面试常见问题,将在您下一次面试中为您提供帮助。如果您还有其他关于String班级的疑问,请分享。

saigon has written 1445 articles

Leave a Reply