Java String 面試題以及答案

String是最常使用的Java類之一,位于java的lang包下面,是唯一一個(gè)不需要引包的包。

下面我們來(lái)討論一下String類的一些基本問(wèn)題

1、什么是String,它是什么數(shù)據(jù)類型?

String是定義在 java.lang 包下的一個(gè)類。它不是8種基本數(shù)據(jù)類型之一。String是不可變的,JVM使用字符串池來(lái)存儲(chǔ)所有的字符串對(duì)象。

2、創(chuàng)建String對(duì)象的不同方式有哪些?

1)、 和其他類一樣通過(guò)new一個(gè)對(duì)象來(lái)創(chuàng)建。

使用這種方式時(shí),JVM創(chuàng)建字符串對(duì)象但不存儲(chǔ)于字符串池,存儲(chǔ)在棧或者堆當(dāng)中。我們可以調(diào)用intern()方法將該字符串對(duì)象存儲(chǔ)在字符串池,如果字符串池已經(jīng)有了同樣值的字符串,則返回引用。

2)、使用雙引號(hào)直接創(chuàng)建。

使用這種方式時(shí),JVM去字符串池找有沒有值相等字符串,如果有,則返回找到的字符串引用。否則創(chuàng)建一個(gè)新的字符串對(duì)象并存儲(chǔ)在字符串池。

String str = new String("abc");
String str1 = "abc";

3、寫一個(gè)方法來(lái)判斷一個(gè)String是否是回文(順讀和倒讀都一樣的詞)?

這里介紹兩個(gè)方法:
1)、使用StringBuffer和StringBuilder有reverse方法
首先將String轉(zhuǎn)換為StringBuffer或StringBuilder

private static boolean isPalindrome(String str) {
        if (str == null)
            return false;
        StringBuilder strBuilder = new StringBuilder(str);
        strBuilder.reverse();
        return strBuilder.toString().equals(str);
    }

2)、首尾一一對(duì)比

private static boolean isPalindromeString(String str) {
        if (str == null)
            return false;
        int length = str.length();
        for (int i = 0; i < length / 2; i++) {
            if (str.charAt(i) != str.charAt(length  - 1- i))
                return false;
        }
        return true;
    }

4、如何讓一個(gè)字符串變成小寫或大寫形式?

String提供兩個(gè)方法,toUpperCase 和 toLowerCase 方法,可以讓一個(gè)字符串全部變?yōu)?大寫或小寫。

5、如何比較兩個(gè)字符串的大???

在String類當(dāng)中,有兩個(gè)比較方法,實(shí)現(xiàn)了Comparable接口:
直接比較:compareTo(String anotherString) ,如果小于傳入的字符串返回負(fù)數(shù),如果大于則返回正數(shù)。當(dāng)兩個(gè)字符串值相等時(shí),返回0。
忽略大小寫的比較:compareToIgnoreCase(String str)。該方法與compareTo方法類似,區(qū)別只是內(nèi)部利用了Character.toUpperCase等方法進(jìn)行了大小寫轉(zhuǎn)換后進(jìn)行比較。

6、如何將String轉(zhuǎn)換為char,反過(guò)來(lái)呢?

1)、String轉(zhuǎn)換成char
這是一個(gè)誤導(dǎo)題,String是一系列字符,所以沒有辦法直接轉(zhuǎn)換成一個(gè)單一的char,這里應(yīng)該說(shuō)的是轉(zhuǎn)換為字符串?dāng)?shù)組,我們可以通過(guò)調(diào)用toCharArray() 方法將字符串轉(zhuǎn)成字符數(shù)組。

String str = "Hello world!";

    char[] chars = str.toCharArray();
    System.out.println(chars.length);

2)、char轉(zhuǎn)換成string:
char轉(zhuǎn)換成string有6種方法:

①. String s = String.valueOf('a'); //效率最高的方法

②. String s = String.valueOf(new char[]{'a'}); //將一個(gè)char數(shù)組轉(zhuǎn)換成String

③. String s = Character.toString('a');
// Character.toString(char)方法實(shí)際上直接返回String.valueOf(char)

④. String s = new Character('a').toString();

⑤. String s =  'a'+"";
// 雖然這個(gè)方法很簡(jiǎn)單,但這是效率最低的方法
// Java中的String Object的值實(shí)際上是不可變的,是一個(gè)final的變量。
// 所以我們每次對(duì)String做出任何改變,都是初始化了一個(gè)全新的String Object并將原來(lái)的變量指向了這個(gè)新String。
// 而Java對(duì)使用+運(yùn)算符處理String相加進(jìn)行了方法重載。
// 字符串直接相加連接實(shí)際上調(diào)用了如下方法:
// new StringBuilder().append('c').append("").toString();


⑥. String s = new String(new char[]{'c'});

7、如何將String轉(zhuǎn)換為byte array,反過(guò)來(lái)呢?

1)、String轉(zhuǎn)換為byte array
使用String的getBytes()方法將String轉(zhuǎn)成byte數(shù)組
2)byte array轉(zhuǎn)換為String
使用String的構(gòu)造方法 new String(byte[] arr) 將byte數(shù)據(jù)轉(zhuǎn)為String。

public class StringToByteArray {

    public static void main(String[] args) {
        String str = "Hello World!";
        byte[] b = str.getBytes();
        // print the byte[] elements
        for(int i=0;i<b.length;i++){
              System.out.println(i);
        }
    }
}

public class ByteArrayToString {

    public static void main(String[] args) {
        byte[] b1 = { 'H', 'e', 'l', 'l', '0' };
        byte[] b2 = { 72, 101, 108, 108, 111};

        String str1 = new String(b1);
        String str2 = new String(b2);

        System.out.println(str1);
        System.out.println(str2);
    }
}

8、淺談一下String, StringBuffer,StringBuilder的區(qū)別?

String是不可變類,每當(dāng)我們對(duì)String進(jìn)行操作的時(shí)候,如果字符串常量池沒有該字符串,就會(huì)創(chuàng)建新的字符串。操作String很耗資源,所以Java提供了兩個(gè)工具類來(lái)操作String,StringBuffer和StringBuilder。

StringBuffer和StringBuilder是可變類,StringBuffer是線程安全的,StringBuilder則不是線程安全的。所以在多線程對(duì)同一個(gè)字符串操作的時(shí)候,我們應(yīng)該選擇用StringBuffer。由于不需要處理多線程的情況,StringBuilder的效率比StringBuffer高。

9、String是不可變的有什么好處?

1)、由于String是不可變類,所以在多線程中使用是安全的。
2)、String是不可變的,它的值也不能被改變,所以用來(lái)存儲(chǔ)數(shù)據(jù)密碼很安全。
3)、 因?yàn)閖ava字符串是不可變的,可以在java運(yùn)行時(shí)節(jié)省大量java堆空間。因?yàn)椴煌淖址兞靠梢砸贸刂械南嗤淖址?。如果字符串是可變的,那么任何一個(gè)變量的值改變,就會(huì)反射到其他變量,所有引用該字符串對(duì)象的變量都會(huì)產(chǎn)生變化,字符串池也就沒有任何意義了。

10、如何分割一個(gè)String?

String類中自帶兩種實(shí)現(xiàn)方法:
1)、public String[] split(String regex):

根據(jù)傳入的正則字符串進(jìn)行分割,注意,如果最后一位剛好有傳入的字符,返回?cái)?shù)組最后一位不會(huì)有空字符串。
String str = "vrevdfsdsl";
System.out.println(Arrays.toString(str.split("s")));

//以上代碼輸出為  [vrevdf, d, l].

2)、 public String[] split(String regex, int limit):

限制分割結(jié)果數(shù)組中有幾個(gè)字符串。傳入2,則結(jié)果分割后數(shù)組長(zhǎng)度為2。
String s = "vfe,vef,ve,we";
String[] data = s.split(",", 2);
for(int i=0;i<data.length;i++){
      System.out.println(i);
}

實(shí)際上第一個(gè)方法調(diào)用了第二個(gè)方法,只是沒有限制數(shù)組長(zhǎng)度。

public String[] split(String regex) {
    return split(regex, 0);
}

11、如何判斷兩個(gè)String是否相等?

有兩種方式判斷字符串是否相等,使用"=="或者使用equals方法。
1)、當(dāng)使用"=="操作符時(shí),不僅比較字符串的值,還會(huì)比較引用的內(nèi)存地址。
2)、equals方法,只判斷值是否相等,大多數(shù)時(shí)候也就是判斷這兩個(gè)值是否相等,所以使用這個(gè)方法比較多。

補(bǔ)充:還有一個(gè)equalsIgnoreCase可以用來(lái)忽略大小寫進(jìn)行比較。

        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

12、什么是字符串池?

顧名思義,字符串常量池就是用來(lái)存儲(chǔ)字符串的。它存在于Java 堆內(nèi)存。

下圖解釋了字符串池在java堆空間如何存在以及當(dāng)我們使用不同方式創(chuàng)建字符串時(shí)的情況。

image

以下是上圖的一個(gè)編程例子

public class StringPool {

    public static void main(String[] args) {
        String s1 = "aaa";
        String s2 = "aaa";
        String s3 = new String("aaa");

        System.out.println("s1 == s2 :"+(s1==s2));//true
        System.out.println("s1 == s3 :"+(s1==s3));//false
    }

}

一些java題中,可能會(huì)問(wèn)一段代碼中有幾個(gè)對(duì)象被創(chuàng)建,例如:

String str = new String("aaa");

上面一行代碼將會(huì)創(chuàng)建1或2個(gè)字符串。如果在字符串常量池中已經(jīng)有一個(gè)字符串“aaa”,那么就只會(huì)創(chuàng)建一個(gè)“aaa”字符串。如果字符串常量池中沒有“aaa”,那么首先會(huì)在字符串池中創(chuàng)建字符串對(duì)象,然后才在堆內(nèi)存中創(chuàng)建String對(duì)象,這種情況就會(huì)創(chuàng)建2個(gè)對(duì)象了。

13、String的intern()方法

當(dāng)intern()方法被調(diào)用,如果字符串池中含有一個(gè)字符串和當(dāng)前調(diào)用方法的字符串的值相等,那么就會(huì)返回池中的字符串。如果池中沒有的話,則首先將當(dāng)前字符串加入到池中,然后返回引用。

14、String是線程安全的嗎?

String是是線程安全的,因?yàn)樗遣豢勺冾?,一旦?chuàng)建了String對(duì)象,我們就無(wú)法改變它的值。因此,它是線程安全的,可以安全地用于多線程環(huán)境中。

15、為什么我們?cè)谑褂肏ashMap的時(shí)候總是用String做key?

因?yàn)樽址遣豢勺兊模?dāng)創(chuàng)建字符串時(shí),它的它的hashcode被緩存下來(lái),不需要再次計(jì)算。因?yàn)镠ashMap內(nèi)部實(shí)現(xiàn)是通過(guò)key的hashcode來(lái)確定value的存儲(chǔ)位置,所以相比于其他對(duì)象更快。這也是為什么我們平時(shí)都使用String作為HashMap對(duì)象的key。

16、String編程題

1、下面的代碼輸出什么

String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1 == str2);

輸出:
false

2、下面的代碼輸出什么

String str1 = "abc";
StringBuffer str2 = new StringBuffer(str1);
System.out.println(str1.equals(str2));

輸出:
false,因?yàn)閟tr2不是String類型,String的equals方法進(jìn)行了類型判斷。

3、下面的代碼輸出什么

String str1 = "abc";
String str2 = new String("abc");
str2.intern();
System.out.println(str1 ==str2);

輸出:
false,intern()方法將返回從字符串池中的字符串對(duì)象的引用,但因?yàn)槲覀儧]有分配到str2,str2沒有變化,如果該第三行代碼為
str2 = str2.intern(),則輸入true。

4、下面的代碼將創(chuàng)建幾個(gè)字符串對(duì)象。

String str1 = new String("Hello");  
String str2 = new String("Hello");

會(huì)創(chuàng)建3個(gè)對(duì)象。首先會(huì)在字符穿常量池創(chuàng)建一個(gè)對(duì)象,只是這個(gè)對(duì)象創(chuàng)建后就是一個(gè)常量“Hello”,不可以更改, 并且這個(gè)對(duì)象是放在串池里面的。然后在堆內(nèi)存中創(chuàng)建一個(gè)對(duì)象str1,指向常量池中的“Hello”,最后又創(chuàng)建一個(gè)對(duì)象str2,指向常量池中的“Hello”,這里“hello”字符串池中的字符串被重用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容