我们所有人都必须通过java中与String类相关的面试问题。这些字符串访谈问题包括不变性和内存泄漏问题。我将尝试在这篇文章中介绍这些问题。
常见的字符串面试问题
1. Java中的String关键字是什么?
2.为什么字符串是不可变的?
3.什么是String常量池?
4.关键字'实习生'用法
5.匹配正则表达式?
6.使用equals()和'=='进行字符串比较?
7. String类中的内存泄漏问题
8. String如何在Java中运行?
9.创建String对象有哪些不同的方法?
10.如何检查String是否为回文。
11.如何从String中删除或替换字符。
12.如何制作String大写或小写?
13.如何在java程序中比较两个字符串?
14.我们可以在开关盒中使用String吗?
15.编写一个程序来打印String的所有排列?
16.编写一个java程序来反转给定字符串的每个单词?
17.如何在java中拆分字符串?
18.为什么Char数组优先于字符串存储密码?
19. String中的String是否是线程安全的
20.为什么String是Java中流行的HashMap密钥
21. String,StringBuffer和StringBuilder之间的区别?
22.如何连接多个字符串。
23.使用字符串初始化代码创建多少个对象?
24.如何计算字符串中每个字符的出现次数?
25.编写一个java程序来反转一个字符串?
1. Java中的String关键字是什么?
没有。String
不是Java保留关键字。它是派生类型数据类型,即类。
StringExample.java
public class StringExample { public static void main(String[] args) { Integer String = 10 ; System.out.println(String); //Prints 10 } } |
2.为什么字符串是不可变的?
我们都知道java中的字符串是不可变的。如果你想知道,什么是不变性以及如何实现?按照这篇文章:如何使java类不可变?
这里的问题是为什么?为什么一成不变?我们来分析吧。
- 我能想到的第一个原因是性能提升。Java语言的开发是为了加速应用程序的开发,因为它在以前的语言中并没有那么快。JVM设计人员必须足够聪明,以确定实际应用程序将主要由标签,消息,配置,输出和各种方式的字符串组成。
看到这种过度使用,他们想象了弦的不当使用是多么危险。所以他们想出了一个字符串池的概念(下一节)。字符串池只是一些字符串的集合,大多是唯一的。String池背后的基本思想是在创建后重用字符串。这样,如果在代码中创建了20次特定字符串,则应用程序最终只有一个实例。
- 我认为安全考虑的第二个原因。字符串是java编程的每个方面中最常用的参数类型。无论是加载驱动程序还是打开URL连接,您都需要以字符串的形式将信息作为参数传递。如果字符串还没有最终结果,那么他们就会打开一个Pandora框的安全问题。我们所有人都必须通过java中与String类相关的面试问题。这些问题包括从不变性到内存泄漏问题。我将尝试在这篇文章中介绍这些问题。
除了上述两个原因外,我没有找到任何令人信服的答案。如果您有什么吸引力的话,请与我分享。
3.字符串池概念
字符串池是一个特殊的内存区域,与存储这些字符串常量的常规堆内存分开。这些对象在应用程序的生命周期中被称为字符串变量。
在Java中,可以通过多种方式创建String。让我们理解他们:
1)字符串赋值
上面的代码使JVM验证是否已经有一个字符串“abc”(相同的char序列)。如果存在这样的字符串,JVM只是将现有对象的引用赋给变量str
,否则,将创建一个新对象“abc”,并将其引用赋给变量str
。
2)使用新关键字
String str = new String( "abc" ); |
此版本最终在内存中创建两个对象。字符串池中的一个对象具有char序列“abc”,第二个在堆内存中,由变量引用str
并具有与“abc”相同的char序列。
正如java文档所说:除非需要原始的显式副本,否则不必使用此构造函数,因为字符串是不可变的。
4.关键字'实习生'用法
这是java docs最好的描述:
intern()
调用该方法时,如果池已包含String
与equals(Object)
方法确定的此对象相等的字符串,则返回池中的字符串。否则,将此String
对象添加到池中,并String
返回对此对象的引用。
String str = new String( "abc" ); str.intern(); |
它遵循对于任何两个字符串s
和t
,s.intern() == t.intern()
是true
当且仅当s.equals(t)
是true
。意味着如果s和t都是不同的字符串对象并且具有相同的字符序列,则在两者上调用intern()将导致由两个变量引用的单个字符串池文字。
5.匹配正则表达式
如果您还没有探索过它,那么不是那么秘密但有用的功能。您必须已经看到Pattern和Matcher用于正则表达式匹配。String类提供了自己的快捷方式。直接使用它。此方法还在函数定义中使用Pattern.matches()。
String str = new String( "abc" ); str.matches( "" ); |
6.与equals()和'=='的字符串比较
采访中另一个最喜欢的领域 通常有两种比较对象的方法
==
运算符比较对象引用,即内存地址相等。因此,如果两个字符串对象在字符串池中引用相同的文字或在堆中引用相同的字符串对象,则s==t
返回true
,否则false
。
equals()
方法在String类中重写,它验证字符串对象保存的char序列。如果它们存储相同的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] |
现在,substring只有它需要的字符,用于创建正确子字符串的中间字符串可以被垃圾收集,因此不会留下任何内存。
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.如何检查Palindrome中的字符串?
如果字符串在反转时的值相同,则称其为回文结构。要检查Palindrome,只需反转字符串并检查原始字符串和崇拜字符串的内容。
StringExample.java
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()
。这些方法有两个参数。第一个参数是要替换的字符,第二个参数是将放在字符串中的新字符。
如果要删除字符,则在第二个参数中传递空白字符。
StringExample.java
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()
方法将字符串转换为小写或大写。
StringExample.java
String blogName = "HowToDoInJava.com" ; System.out.println(blogName.toLowerCase()); //howtodoinjava.com System.out.println(blogName.toUpperCase()); //HOWTODOINJAVA.COM |
13.如何在java程序中比较两个字符串?
始终使用equals()
方法来验证字符串相等性。切勿使用"=="
操作员。双等运算符始终检查内存中的对象引用。equals()
方法检查String内容。
StringExample.java
String blogName = "HowToDoInJava.com" ; String anotherString = new String( "HowToDoInJava.com" ); System.out.println(blogName == anotherString); //false System.out.println(blogName.equals(anotherString)); //true |
14.我们可以在开关盒中使用String吗?
是的,您可以在Java 7之后使用String
类in switch
语句。在Java 7之前,它是不可能的,您必须使用if-else
语句来实现类似的行为。
StringExample.java
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。
一串长度N
具有N! (N Factorial)
排列。
StringExample.java
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 getPermutations(String string) { //All permutations Set permutationsSet = new HashSet(); // 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 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程序来反转给定字符串的每个单词?
要分别反转每个单词,首先,对字符串进行标记,然后将所有单词分开。然后对每个单词应用反向字逻辑,最后连接所有单词。
StringExample.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()
method返回字符串数组。数组中的每个字符串都是单个标记。
StringExample.java
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更适合存储密码?
我们知道字符串存储在Java中的常量池中。在字符串池中创建字符串后,它将保留在池中,直到收集垃圾为止。此时,任何恶意程序都可以访问物理内存位置中的内存位置并访问该字符串。
如果我们将密码存储为字符串,那么它也将存储在弹簧池中,并且将在内存中可用的持续时间超过所需的时间,因为垃圾收集周期是不可预测的。这使得敏感密码字符串容易受到黑客攻击和数据窃取。
使用后我们可以将String变成空白吗?不,我们不可以。我们知道,一旦创建了一个String,我们就无法操纵它,例如你不能改变它的内容。字符串是最终的,不可变的。
但是char数组是可变的,它们的内容在使用后可以被覆盖。因此,您的应用程序应使用char []存储密码文本,并在使用密码后,用空白替换数组内容。
StringExample.java
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中流行的HashMap键?
在Java中,必须使用的密钥Map
应该是不可变的,并且应该遵守equals()
和hashCode()
方法之间的契约。String
班级满足两个条件。
此外,String类提供了许多有用的方法来比较,排序,标记化或低级大小写。在执行CRUD操作时可以使用这些方法Map
。它使它成为一个非常有用的类,Map
而不是创建自己的类。
21. String,StringBuffer和StringBuilder之间的区别?
22.如何连接多个字符串?
根据您的使用StringBuffer
或StringBuilder
类别需要线程安全性。使用append()
两个类中的方法来连接字符串。
StringExample.java
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 |
23.使用字符串初始化代码创建多少个对象?
StringExample.java
String s1 = "howtodoinjava.com" ; String s2 = "howtodoinjava.com" ; String s3 = new String( "howtodoinjava.com" ); |
- 上面的代码将创建2个对象。
- 第一个对象将在第一个语句的字符串池中创建。
- 第二个语句不会创建任何新对象,
s2
并将引用相同的字符串常量s1
。
- 第三个语句将在堆内存中创建一个新的字符串对象。
24.如何计算字符串中每个字符的出现次数?
为了找到给定字符串中每个字符的出现次数,我们HashMap
将字符用作键,并将其作为值出现。每次出现新事件时,我们都会增加该字符的值。
StringExample.java
String blogName = "howtodoinjava.com" ; HashMap occurancesMap = new HashMap(); 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()
和StringBuilder.reverse()
方法。面试官可能会要求您编写自己的程序,以检查您的技能水平。
使用下面给出的基于递归的示例来反转字符串。该程序从字符串中获取第一个字符,并放在字符串中的最后一个位置。它使用此替换字符串中的所有字符,直到整个字符串被尊重。
StringExample.java
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 ); } } |