JavaRush /Java 博客 /Random-ZH /Java 字符串。面试问题与答案,第 2 部分
Andrey
第 26 级

Java 字符串。面试问题与答案,第 2 部分

已在 Random-ZH 群组中发布
不幸的是,这篇文章无法用一个片段来表达;我不得不将其分成两部分。 请参阅这里的开头 Java 字符串。 面试问题和答案,第 2 - 1 部分

12. 编写一个函数来查找给定字符串中最长的回文

字符串可以包含回文字符串,找到最长的回文字符串是一个编程问题。这里的关键点是,从任何回文的中间开始,如果我们向右和向左移动 1 个字符,它总是相同的字符。例如,12321,中间是3,如果我们从当前位置继续向两个方向移动,我们将得到2,然后得到1。我们在Java程序中使用类似的逻辑来找到最长的回文。但是,如果回文长度是偶数,那么中间的长度也是偶数,所以我们需要确保我们的程序中也提供了这个,例如12333321,中间是33,如果我们继续移动在两个方向上,我们都会得到 3、2 和 1。在我们的程序中,我们首先检查结果字符串,并检查左右字符。我们还有两个全局变量来存储回文的初始位置。我们还需要检查是否已经找到更长的回文,因为我们可以在给定字符串中找到多个回文。下面是一个在所有情况下都能正常工作的示例程序。我们可以通过将 while 循环移至单独的方法中来改进上述代码,但我会将这部分留给您。如果您有更好的实现或者程序以某种方式失败,请告诉我。
package com.journaldev.util;

public class LongestPalindromeFinder {

    public static void main(String[] args) {
        System.out.println(longestPalindromeString("1234"));
        System.out.println(longestPalindromeString("12321"));
        System.out.println(longestPalindromeString("9912321456"));
        System.out.println(longestPalindromeString("9912333321456"));
        System.out.println(longestPalindromeString("12145445499"));
    }

    public static String longestPalindromeString(String in) {
        char[] input = in.toCharArray();
        int longestPalindromeStart = 0;
        int longestPalindromeEnd = 0;

        for (int mid = 0; mid < input.length; mid++) {
            // для случая нечетного палиндрома How 12321, 3 будет серединой
            int left = mid-1;
            int right = mid+1;
            // нам необходимо двигаться влево и вправо на 1 позицию до конца
            while (left >= 0 && right < input.length) {
                // ниже проверка, является ли это палиндромом
                if (input[left] == input[right]) {
                    // обновление глобальных позиций, только если палиндром длиннее имеющегося
                    if (right - left > longestPalindromeEnd
                            - longestPalindromeStart) {
                        longestPalindromeStart = left;
                        longestPalindromeEnd = right;
                    }
                }
                left--;
                right++;
            }
            // для четного палиндрома у нас должна быть подобная логика с размером середины 2
            // для этого мы начнем на одну позицию правее
            left = mid-1;
            right = mid + 2;// к примеру, для 12333321 мы выбрали 33 в качестве середины
            while (left >= 0 && right < input.length)
            {
                if (input[left] == input[right]) {
                    if (right - left > longestPalindromeEnd
                            - longestPalindromeStart) {
                        longestPalindromeStart = left;
                        longestPalindromeEnd = right;
                    }
                }
                left--;
                right++;
            }
        }
        // теперь у нас есть позиции для самого длинного палиндрома
        return in.substring(longestPalindromeStart, longestPalindromeEnd + 1);
    }
}
该程序将输出以下内容:
1
12321
12321
12333321
454454

13. String、StringBuffer和StringBuilder有什么区别

在 Java 中,字符串是不可变的和最终确定的,因此我们所有的字符串操作总是会创建一个新字符串。字符串操作是资源密集型的,因此 Java 提供了两个有用的字符串操作类 -StringBufferStringBuilderStringBuffer并且StringBuilder是可变类。操作StringBuffer是线程安全且同步的,但方法StringBuilder不是线程安全的。因此,当多个线程处理同一个字符串StringBuffer时,我们应该使用StringBuilder. 因为它没有同步的负担, StringBuilder所以效率更高。StringBuffer

14.为什么Java中字符串是不可变的和最终确定的?

字符串不变性有几个优点:
  1. 字符串池之所以可能,是因为字符串在Java中是不可变的,因此虚拟机节省了大量的堆空间,因为不同的字符串变量指向池中的同一个变量。如果字符串不是不可变的,则字符串驻留是不可能的,因为如果任何变量更改其值,引用该字符串的其他变量也会受到影响。

  2. 如果字符串是可变的,那么它就会成为应用程序的严重安全风险。例如,数据库用户名和密码作为字符串传递以获得与数据库的连接,而在套接字编程中,主机和端口详细信息作为字符串传递。由于该字符串是不可变的,因此其值无法更改,否则任何黑客都可以更改链接的值并导致应用程序的安全性出现问题。

  3. 由于字符串是不可变的,因此它是线程安全的,并且可以在不同线程之间共享字符串的一个实例。这避免了线程安全的同步,字符串是完全线程安全的。

  4. Java 中使用字符串classloader,不变性确保使用Classloader. 例如,当您尝试加载java.sql.Connection一个类时,考虑一个类实例,但引用值更改为myhacked.Connection可能对数据库执行不需要的操作的类。

  5. 由于字符串是不可变的,因此hashcode在创建时就被缓存起来,不需要再次计算。这使得该字符串成为键入的绝佳候选者Map,并且其处理速度将比其他键更快HashMap。这就是为什么 string 是最常用的用作键的对象的原因HashMap

15. 如何将字符串分割成多个部分?

我们可以使用一种方法,split(String regex)使用正则表达式作为分隔符将字符串拆分为字符串数组。
import java.util.Arrays;

public class JavaSplitString {
    public static void main(String[] args) {
        String line = "I am a java developer";
        String[] words = line.split(" ");
        String[] twoWords = line.split(" ", 2);
        System.out.println("String split with delimiter: "+Arrays.toString(words));
        System.out.println("String split into two: "+Arrays.toString(twoWords));
        //split string delimited with special characters
        String wordsWithNumbers = "I|am|a|java|developer";
        String[] numbers = wordsWithNumbers.split("\\|");
        System.out.println("String split with special character: "+Arrays.toString(numbers));
    }
}
该方法split(String regex, int numOfStrings)是一个重载方法,用于将字符串拆分为指定行数。我们可以使用反斜杠将正则表达式特殊字符用作正则字符。该程序将输出以下内容:
String split with delimiter: [I, am, a, java, developer]
String split into two: [I, am a java developer]
String split with special character: [I, am, a, java, developer]

16. 为什么字符串数组比字符串更适合存储密码?

Java 中的字符串是不可变的,存储在字符串池中。一旦它被创建,它就会保留在池中直到被垃圾收集,因此当我们认为我们已经完成了密码时,它会在内存中保留一段时间,并且没有办法避免这种情况。这是一个安全风险,因为任何有权访问内存转储的人都能够找到明文形式的密码。如果我们使用字符数组来存储密码,我们可以在使用完后将其清除。这样我们就可以控制它在内存中保留的时间,避免字符串固有的安全风险。

17. 在Java中如何检查两个字符串的相似性?

有两种方法可以检查两个字符串是否相等 - 使用“ ==”运算符,或使用equals. 当我们使用“ ==”运算符时,它会检查字符串的值作为引用,但在编程中大多数时候我们仅检查该值的字符串等效性。因此,我们必须使用 equals 方法来测试两个字符串是否相等。我们还有一种方法equalsIgnoreCase可以用来忽略大小写。
String s1 = "abc";
String s2 = "abc";
String s3= new String("abc");
System.out.println("s1 == s2 ? "+(s1==s2)); //true
System.out.println("s1 == s3 ? "+(s1==s3)); //false
System.out.println("s1 equals s3 ? "+(s1.equals(s3))); //true

18.什么是字符串池?

顾名思义,字符串池是存储在 Java 堆中的字符串的集合。我们知道String这是Java中的一个特殊类,我们可以使用new运算符创建该类的对象,就像我们可以通过在双引号中提供字符串值来创建对象一样。下图解释了字符串池是如何在Java堆中分配的,以及当我们使用不同的方式创建字符串时会发生什么。 Java 字符串。 面试问题和答案,第 2 - 2 部分字符串池之所以成为可能,仅仅是因为Java的字符串不变性和字符串驻留思想的实现。字符串池也是享元模式的一个示例。字符串池有助于节省大量内存,但另一方面,创建行需要更多时间。当我们使用双引号创建字符串时,它首先在池中查找具有相同值的字符串,如果找到则简单地返回引用,否则在池中创建一个新字符串然后返回引用。然而,当我们使用new运算符时,我们强制类String创建一个新的字符串对象,然后我们可以使用该方法intern()将字符串放入池中,或者从池中获取对另一个String具有相同值的对象的引用。下面的示例显示了字符串池的工作原理。
public class StringPool {
    public static void main(String[] args) {
        String s1 = "Cat";
        String s2 = "Cat";
        String s3 = new String("Cat");

        System.out.println("s1 == s2 :"+(s1==s2));
        System.out.println("s1 == s3 :"+(s1==s3));
    }
}
该程序将输出以下内容:
s1 == s2 :true
s1 == s3 :false

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

当调用该方法时intern(),如果字符串池已经包含与我们的对象等效的字符串(经该方法验证equals(Object)),则返回对池中字符串的引用。否则,字符串对象将被添加到池中,并返回对该对象的引用。此方法始终返回与当前字符串具有相同值的字符串,但保证它将是唯一字符串池中的字符串。下面是该方法如何工作的示例intern()
public class StringPool {
    public static void main(String[] args) {
        String a = "string a";
        String b = new String("string a");
        String c = b.intern();

        System.out.println(a == b);
        System.out.println(b == c);
        System.out.println(a == c);
    }
}
Программа выведет следующее:false
false
true

20. Java中字符串是线程安全的吗?

字符串是不可变的,因此我们无法在程序中更改它们的值。因此它们是线程安全的,可以安全地在多线程环境中使用。

21.为什么String是Java中HashMap中流行的键?

由于字符串是不可变的,因此它们的哈希码在创建时会被缓存,不需要重新计算。这使得字符串成为键的绝佳候选者Map,并且它们的处理速度比其他键对象更快HashMap。这就是为什么字符串主要用作键的原因HashMap。我希望本文列出的问题对您的面试有所帮助,如果我遗漏了什么,请告诉我。 原始文章链接 作者:Pankaj Kumar
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION