8000字长文图解String,这次彻底搞懂了

Java是最受欢迎的编程语言之一,它具有简单、安全、稳健等特性。

当你准备Java面试时,你会发现在大多数面试中,开始的问题都是关于Java字符串。

在这篇文章中,我将介绍前20个关于Java字符串的面试问题,读完这篇文章后,你将很轻松应对有关Java String相关的面试问题。

1. Java中String是什么?它是一种数据类型吗?

字符串是Java中定义在java.lang包中的一个类。你可以将一连串的字符分配给一个字符串变量。例如,String name = "Gaurav"

另外,Java中String不是一个像int、char或long那样的数据类型。

当你给String变量分配一个字符序列时,你就是在创建一个字符串对象。

每个字符串字面是一个字符串类的实例,它的值不能被改变。

2. C语言中的字符串和Java中的字符串有什么区别?

如果你的简历中包含与C语言有关的内容,他们可以问你这个问题。

Java和C语言中的字符串是完全不同的。

在C语言中,字符串是一个以null结尾的字符数组。

在下面的图片中,我展示了C语言和Java语言中的字符串的结构。

在Java中,字符串是比较抽象的。

字符串类来自java.lang包,有很多预定义的方法,程序员可以用这些方法对字符串进行操作或获得关于字符串的信息。

因此,在Java中,字符串比C语言的功能更丰富。

3. 什么是Java中的字符串池?

字符串池(String pool)是一种由JVM维护的特殊类型的内存。

字符串池用于存储唯一的字符串对象。

当你将相同的字符串字头分配给不同的字符串变量时,JVM在字符串池中只保存一个字符串对象的副本,并且字符串变量将开始引用该字符串对象。

我在下图中对上述句子进行了图解。

维护这种特殊类型的内存的目的是内存优化。

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

在大多数的Java面试中,你会遇到这样的问题。

你认为Java语言设计者为什么要保持字符串的不可变性?

如果你把相同的字符串字面符号分配给许多字符串变量,JVM将在Java字符串池中只保存一份字符串对象,这些变量将开始引用该字符串对象。

如果在这个问题之前没有人问过你关于字符串池的问题,请你介绍一下Java中字符串池概念的背景。请参考前面的问题。

另外,另一个原因是安全。我们知道,几乎每个Java程序都包含字符串,它被用来保存重要的数据,如用户名和密码。所以它不应该在中间被改变。否则,就会出现安全问题。

5. 以下代码将创建多少个对象?

String firstString = "Gaurav";
String secondString = "Gaurav";
String thirdString =  new String("Gaurav");

看到上面的代码,只有两个字符串对象将被创建。前两个变量将引用同一个字符串对象,其值为 "Gaurav"。JVM使用字符串池的概念,将重复的字符串对象只存储一份到字符串常量池。

但是,当我们使用new关键字来创建一个新的字符串时,一个新的字符串对象将被创建并存储在Java堆内存中。

所以对于第三个变量thirdString,一个新的字符串对象将被创建并存储在Java堆空间中。

所以总共会有两个对象,一个来自Java字符串池,一个来自Java堆内存。

下面,我在下图中展示了这两个对象。

6. intern()方法的作用是什么?

intern()方法用来将字符串对象的唯一副本手动添加到Java字符串池中。

我们知道,当我们使用new关键字创建一个字符串时,它将被存储在堆内存中。

我们可以使用intern()方法将该字符串对象的唯一副本存储在Java字符串池中。

当你做这样的事情时,JVM会检查字符串池中是否有相同值的字符串对象存在。

如果具有相同值的字符串对象存在,JVM将简单地将该对象的引用提供给相应的字符串变量。

如果字符串池中没有相同值的字符串对象,JVM会在字符串池中创建一个相同值的字符串对象,并将其引用返回到字符串变量中。

7. String和StringBuffer之间的区别是什么?

字符串是Java中的一个final类,字符串是不可变的,这意味着我们不能再改变String对象的值。

由于字符串在应用程序中被广泛使用,我们必须对字符串对象进行多次操作。每次都会产生一个新的String对象,而之前的所有对象都会成为垃圾对象,给垃圾收集器带来压力。

因此,Java团队引入了StringBuffer类。它是一个可变的String对象,这意味着你可以改变它的值。

字符串是不可变的,但StringBuffer是可变的。

8. StringBuffer和StringBuilder的区别是什么?

我们知道字符串在Java中是不可变的。但是使用StringBuffer和StringBuilder,你可以创建可编辑的字符串对象。

当Java团队意识到对可编辑字符串对象的需求时,他们引入了StringBuffer类。但是StringBuffer类的所有方法都是同步的。

这意味着在同一时间,只有一个线程可以访问StringBuffer的一个方法。

因此,它需要更多的时间。

后来,Java团队意识到,让StringBuffer类的所有方法都同步化并不是一个好主意,于是他们引入了StringBuilder类。

StringBuilder类的所有方法都不是同步的。

由于StringBuffer类的所有方法都是同步的,所以与StringBuilder相比,StringBuffer是线程安全的,速度较慢,而且效率较低。

由于StringBuilder类的方法没有一个是同步的,所以与StringBuffer相比,StringBuilder不是线程安全的,但是对比StringBuffer速度更快、效率更高。

9. 我们可以使用==运算符来比较字符串吗?有什么风险?

答案是肯定的,我们可以使用==运算符来比较字符串。

但是,当我们使用==运算符比较字符串时,无论这些字符串变量是否指向同一个字符串对象,我们都是在比较它们的对象引用。

大多数时候,开发人员想比较字符串的内容,但他们错误地用==运算符比较字符串,其实应该使用equals()方法,这导致了一个错误。

下面,我给出了一个程序,对比一下使用==运算符和equals()方法进行的字符串比较。

publicclass StringCompareUsingEqualsOperator {
 
 public static void main(String[] args) {
 
 String firstString = "Gaurav";
 String secondString = "Gaurav";
 
 String thirdString =  new String("Gaurav");
 
 System.out.print("Case 1 : ");
 System.out.println(firstString == secondString); // true
 
 System.out.print("Case 2 : ");
 System.out.println(firstString == thirdString); // false
 
 // Comparing strings using equals() method
 System.out.print("Case 3 : ");
 System.out.println(firstString.equals(thirdString)); // true
 }
 
}

上述程序的输出如下:

Case 1 : true
Case 2 : false
Case 3 : true

在'Case 1'中,我们使用等价运算符(==)比较firstString和secondString,因为这两个变量都指向同一个字符串对象,所以会打印为真。

在'Case 2'中,我们使用等价运算符(==)比较firstString和thirdString,因为两个变量都没有指向同一个字符串对象,所以会打印出false。

你可以看到,对于thirdString,我们使用了new关键字,它在Java堆内存中创建了一个新对象。

在 "Case 3 "中,我们使用equals()方法比较了firstString和thirdString。即使两者是不同的字符串对象,它的内容也是一样的,因此它打印的是true。

10. 比较字符串的方法有哪些?

我们可以使用equals()方法、==运算符和compareTo()方法来比较字符串。

当我们使用equals()方法比较字符串时,我们在比较字符串的内容,这些字符串是否有相同的内容。

当我们使用==操作符比较字符串时,我们是在比较字符串的引用,即这些变量是否指向同一个字符串对象。

此外,我们还可以按字母顺序比较字符串(按字母顺序比较字符串)。我们可以使用compareTo()方法来比较按字母顺序排列的字符串。

compareTo()方法返回一个负整数、0或一个正整数。

firstString.compareTo(secondString)

如果firstString小于secondString,它将返回一个负整数,即firstString < secondString → 返回一个负整数。

如果firstString等于secondString,它将返回0,即firstString == secondString → 返回0。

如果firstString大于secondString,将返回一个正整数,即firstString > secondString → 返回一个正整数。

11. substring()方法的用途是什么?

Java中的substring()方法返回指定字符串的一个子字符串。

子字符串的创建取决于传递给substring()方法的参数。

Substring方法有两种使用用法:

  • substring(int beginIndex)

  • substring(int beginIndex, int endIndex)

在第一个方法中,我们只给出了参数beinIndex,而在第二个变体中,我们同时给出了beginIndex和endIndex。

对于第一个变体,子字符串将从beginIndex(包括)取到字符串的最后一个字符。

对于第二个变体,子字符串将从beginIndex(包括)取到endIndex(不包括)。

请看下面的图来理解substring()方法。

在第一张图中,使用substring()的第一种用法。

String name = "Gaurav Kukade";
String result = name.substring(4);
 
System.out.println(result);

在第二张图中,我有substring()方法的第二种用法。

String name = "Gaurav Kukade";
String result = name.substring(4, 9);
 
System.out.println(result);

12. 如何检查字符串是否为空?

Java字符串类有一个特殊的方法来检查字符串是否为空。

isEmpty()方法检查字符串的长度是否为零,如果是零,意味着字符串是空的,isEmpty()方法将返回true。

如果字符串的长度不是零,那么isEmpty()方法将返回false。

13. 什么是Java字符串中的format()方法?format()方法和printf()方法的区别是什么?

format()方法和printf()方法都是对字符串进行格式化。

唯一的区别是format()方法返回格式化的字符串,而printf()方法则是打印格式化的字符串。

因此,当你想在程序中使用格式化的字符串时,你可以使用format方法。

而当你想直接打印格式化的字符串时,你可以使用printf()方法。

14. String在Java中是 "线程安全"的吗?

是的,字符串是线程安全的。

正如我们所知,在Java中,字符串是不可变的。这意味着一旦我们创建了一个字符串,我们就不能再修改它。

因此,不存在多个线程访问一个字符串对象的问题。

15. 为什么大多数情况下字符串被用作HashMap的键?

这个字符串是不可改变的。所以有一点是固定的,那就是它一旦创建就不会被改变。

因此,计算出来的哈希码可以被缓存并在程序中使用。

这将节省我们一次又一次计算哈希码的精力,所以,字符串可以比其他HashMap键对象使用起来更加有效。

16. 你能将String转换为Int,反之亦然吗?

是的,你可以将字符串转换为int,反之亦然。

你可以使用Integer类的valueOf()方法和parseInt()方法将字符串转换为整数。

同时,你也可以使用String类的valueOf()方法将整数转换为字符串。

下面,我给出了一个程序,显示了字符串到整数和整数到字符串的转换。

publicclass Conversion{
 public static void main(String [] args){
 
 String str = "1254";
 
 int number = 7895;
 
 // convert string to int using Integer.parseInt() method
 int parseIntResult1 = Integer.parseInt(str);
 
 // convert string to int using Integer.valueOf() method
 int valueOfResult1 = Integer.valueOf(str);
 
 System.out.println("Converting String to Integer:");
 System.out.println("Using the Integer.parseInt() method : "+parseIntResult1);
 System.out.println("Using the Integer.valueOf() method : "+valueOfResult1);
 
 System.out.println("\n");
 // convert integer to string using String.valueOf() method
 String valueOfResult2 = String.valueOf(number);
 
 System.out.println("Converting Integer to String :");
 System.out.println("Using the String.valueOf() method : "+valueOfResult2);
 
 }
}

上述程序的输出如下:

Converting String to Integer:
Using the Integer.parseInt() method : 1254
Using the Integer.valueOf() method : 1254
 
 
Converting Integer to String :
Using the String.valueOf() method : 7895

17. 什么是split()方法?

split方法用于根据提供的regex表达式来分割字符串。

该方法将返回一个分割子字符串的数组:

publicclass SplitExample {
 
 public static void main(String[] args) {
 String name = "My, name, is ,Gaurav!";
 
 String [] substringArray = name.split(",");
 
 for(String substring : substringArray) {
 System.out.print(substring);
 }
 }
}

上述程序的输入为:

My name is Gaurav!

18. "Gaurav Kukade".equals(str)和str.equals("Gaurav Kukade")之间有什么区别?

两者看起来都一样,它将检查字符串变量str的内容是否等于字符串 "Gaurav Kukade"。

但是当字符串变量str = null时,它们就不同了。

第一个代码片断将返回false,但第二个代码片断将抛出NullPointerExpection。

下面我给出了一个程序,它使用equals()方法比较字符串的两种方式。

publicclass StringExample {
 
 public static void main(String[] args) {
 
 String str = "Gaurav Kukade";
 
 System.out.println("Gaurav Kukade".equals(str)); // true
 
 System.out.println(str.equals("Gaurav Kukade")); // true
 } 
}

上述程序的输入为:

true
true

两次都是打印为true,因为两个字符串的内容都是相等的。

现在,我们将检查一个程序,其中str=null:

publicclass StringNullExample {
 
 public static void main(String[] args) {
 
 String str = null;
 
 System.out.println("Gaurav Kukade".equals(str)); // false
 
 System.out.println(str.equals("Gaurav Kukade")); // NullPointerException
 }
}

上述程序的输入为:

false
Exception in thread "main" java.lang.NullPointerException
 at StringNullExample.main(StringNullExample.java:14)

我们可以看到上面的输出,对于第一个代码片断,它是打印false,但对于第二个代码片断,它是抛出NullPointerException。

这是避免java字符串中出现空指针异常的最重要的技巧之一。

19. 在java中,我们可以在switch case中使用一个字符串吗?

是的,从Java 7开始,我们可以在switch情况下使用String。

下面,我给出了一个程序,展示了字符串在switch情况下的使用。

publicclass StringInSwitchExample  
{ 
    public static void main(String[] args) 
    { 
        String str = "two"; 
        switch(str) 
        { 
            case"one": 
                System.out.println("January"); 
                break; 
            case"two": 
                System.out.println("February"); 
                break; 
            case"three": 
                System.out.println("March"); 
                break; 
            default: 
                System.out.println("Invalid month number"); 
        } 
    } 
}

上述程序的输入为:

February

20. 在Java中如何使用+运算符进行字符串连接?

+运算符是唯一的重载运算符,你可以把它用于两个数字的相加,也可以用于字符串连接。

如果你使用的是1.5或以上的Java版本,字符串连接在内部使用StringBuilder的append()方法。而对于低于1.5的版本,它使用StringBuffer类的append()方法。


hello,大家好,我是 Jackpop,硕士毕业于哈尔滨工业大学,曾在华为、阿里等大厂工作,如果你对升学、就业、技术提升等有疑惑,不妨交个朋友:

我是Jackpop,我们交个朋友吧!icon-default.png?t=M276https://mp.weixin.qq.com/s/fCHn8JpLQDH-M_QkVxwR1w

猜你喜欢

转载自blog.csdn.net/jakpopc/article/details/124067676