Java字符串與數組


問題及答案來源自《Java程序員面試筆試寶典》第四章 Java基礎知識 4.5字符串與數組

 

 

 

1、字符串創建與存儲的機制是什么?

Java中字符串聲明與初始化主要有兩種情況:

(1)String s1 = new String("abc")與String s2 = new String("abc")語句   

執行String s1 = new String("abc")語句,字符串池中不存在"abc",則會創建一個字符串常量"abc",

並將它添加到字符串常量池中,然后new String()會在堆中創建一個新的對象,s1指向堆中的String對象

緊接着創建String s2 = new String("abc")語句,因為字符串常量池中已經有了字符串常量"abc",所以

不會再創建"abc",直接new String()在堆中創建一個新的對象,然后使用s2指向這個對象

s1與s2指向堆中的不同String對象,地址自然也不相同

(2)String s1 = "abc"語句與String s2 = "abc"語句

在JVM中存在着一個字符串常量池,其中保存了着很多String 對象,s1,s2引用的是同一個常量池中的對象。

當創建一個字符串常量時,例如String s1 = "abc",會首先在字符串常量池中查找是否已經有相同的字符串被定義,

若已經定義,則直接獲取對其的引用,此時不需要創建字符串常量"abc",如果沒有定義,則首先創建字符串常量

"abc",然后把它加入到字符串池中,再將引用返回

 

例子1:

String s1 = new String("abc");   //  先查找常量區有無"abc"常量,若無則將其"abc"添加到常量區,再在堆中創建對象,將s1指向堆中的對象

String s2 = new String("abc");    //  發現在常量區已經有了"abc",在堆中創建對象,將s2指向堆中的對象

例子2:

String s1 = "abc";  //  在常量區里面創建一個"abc"字符串對象,s1獲取對其的引用

String s2 = "abc";  //  發現在常量區已經有了"abc",s2直接獲取對其的引用

 

引申 - 對於String類型的變量s,賦值語句s=null和賦值語句s=""有什么區別?

s=null,是指s不指向任何一個字符串;s=""中的s指向空字符串

 

筆試題 - new String("abc")創建了幾個對象?

一個或兩個,如果常量池中原來就有"abc",那么只創建一個對象,否則創建兩個對象

 

 

2、==、equals和hashCode有什么區別?

==:是運算符,用於比較兩個變量是否相等。當比較對象時,比較的是對象在內存中的地址

equals方法:用於比較兩個對象是否相等,默認Object類的equals方法是比較兩個對象的地址,跟==的結果一樣

如果一個類沒有自己定義equals方法,它默認的equals方法就是使用"=="運算符,也就是在比較兩個變量指向

的對象是否是同一個對象

hashCode方法:是用來鑒定兩個對象是否相等,默認Object類中的hashCode方法返回對象在內存中地址轉換成

的一個int值,所以如果沒有重寫hashCode()方法,任何對象的hashCode()方法都是不相等的。返回一個離散的int型整數。

在集合類操作中使用,為了提高查詢速度。(HashMap,HashSet等)

 

equals方法實際使用:

 1 class Person{
 2     
 3 }
 4 
 5 public class ObjectDemo {
 6     public static void main(String[] args) {
 7         // Person類沒有重寫equals方法 而Object類中的equals方法是比較兩個對象的地址
 8         Person p1 = new Person();
 9         Person p2 = new Person();
10         System.out.println(p1.equals(p2));            // false
11         
12         // String中重寫了equals方法  比較的是兩個字符串的內容
13         String s1 = new String("hello");
14         String s2 = new String("hello");
15         System.out.println(s1.equals(s2));            // true
16 
17         String s3 = "hello";
18         String s4 = "hello";
19         System.out.println(s3.equals(s4));            // true
20     }
21 }

 

java中的數據類型,可分為兩類: 

(1)基本數據類型

Java中基本數據類型有八種:byte,short,char,int,long,float,double,boolean,

他們之間的比較,用雙等號(==),比較的是他們的值。

 

(2)復合數據類型(類)

當他們用(==)進行比較的時候,比較的是他們在內存中的存放地址,所以,除非是同一個new

出來的對象,他們的比較后的結果為true,否則比較后結果為false。 

在Java的Object中的基類中定義了一個equals的方法,這個方法的初始行為是比較對象的內存地址,

但在一些類庫當中這個方法被覆蓋掉了,如String等,在這些類當中equals有其自身的實現,而不再是

比較對象的內存地址了

 

equals方法和hashCode方法的關系(用於set、map):

hashCode方法只有在set或map集合中用到

當覆蓋了equals方法時,比較對象是否相等將通過覆蓋后的equals方法進行比較(判斷對象的內容是否相等)

將對象放入到集合中時,首先判斷要放入對象的hashCode值與集合中的任意一個元素的hashCode值是否相等,

如果不相等直接將該對象放入集合中。如果hashCode值相等,然后再通過equals方法判斷要放入對象與集合中的

任意一個對象是否相等,如果equals判斷不相等,直接將該元素放入到集合中,否則不放入。

 

 

3、String、StringBuffer、StringBuilder和SringTokenizer有什么區別?

Java中有5個類可以對字符或字符串進行操作,分別是Character、String、StringBuffer、StringBuilder

和SringTokenizer,其中Character用於單個字符操作,String用於字符串操作(屬於不可變類),而

StringBuffer也是用於字符串操作(屬於可變類)

 

Character的API:

  • boolean isDigit(char ch)        確定指定字符是否為數字。
  • boolean isLowerCase(char ch)  確定是否是小寫字母字符
  • boolean isUpperCase(char ch)  確定是否大寫字母字符
  • char toLowerCase(char ch)     將給定字符轉換成大寫字符 
  • char toUpperCase(char ch)     將給定字符轉換成小寫字符 

 

String的API:

 1 引用類型String中的方法(4532)
 2 第一組: 判斷方法
 3           boolean equals(String str);            // 比較兩個字符串的內容是否相等
 4           boolean equalsIgnoreCase(String str);     // 比較兩個字符串的內容是否相等(忽略大小寫)
 5           boolean startsWith(String subStr);       // 判斷某個字符串是否以指定的子串開頭
 6           boolean endsWith(String subStr):        // 判斷某個字符串是否以指定的子串結尾
 7  
 8 第二組: 獲取方法
 9           int length();                           // 獲取字符串中字符個數
10           char charAt(int index);                   // 謀取字符串某一個字符(指定下標)
11           String subString(int startIndex);              // 從指定下標開始截取字符串,直到字符串末尾
12           String subString(int startIndex, int endIndex);     // 從指定下標開始截取字符串,到指定下標結束(左閉右開)
13           int indexOf(String subStr);                    // 獲取子串第一次出現的下標
14   
15 第三組: 轉換方法
16           String toLowerCase();    // 轉成小寫串
17           String toUpperCase();    // 轉成大寫串
18           Char[] toCharArray();    // 變成字符數組
19   
20 第四組: 其他方法
21           String trim();                     // 去掉字符串兩端的空格
22           String[] split(String str);        // 切割字符串

 

String和StringBuffer的區別:

String是不可變類,一旦對象創建其值將不能改變,而StringBuffer是可變類,對象創建后值可以改變

實例化String時可以用賦值也可以用new初始化,而實例化StringBuffer只能用new初始化

 

String字符串修改的原理:

當用String類型來對字符串進行修改時,其實現方法是首先創建一個StringBuffer對象,然后調用StringBuffer的

append方法,最后調用StringBuffer的toString方法把結果返回

1 String s = "Hello";
2 s += " World";
3 // 以上代碼等價於
4 StringBuffer sb = new StringBuffer(s);
5 sb.append(" World");
6 s = sb.toString();

 

StringBuilder和StringBuffer:

StringBuilder也是可以被修改的字符串,它與StringBuffer類似,都是字符串緩沖區,但是StringBuilder

不是線程安全的,如果只是在單線程中使用字符串緩沖區,那么StringBuilder的效率會更高些

而StringBuffer在必要時可以對方法進行同步,所以任意特定實例上的操作就好像是以串行順序

發生,該順序與所涉及的每個線程進行的方法調用順序一致

因此在只有單線程訪問時可以使用StringBuilder,當有多個線程訪問時最好用線程安全的StringBuffer

 

StringTokenizer:

StringTokenizer是用來分割字符串的工具類,示例如下:

1 public class Demo{    
2     public static void main(String[] args) {
3         StringTokenizer st = new StringTokenizer("Welcome to our country");
4         while(st.hasMoreTokens()){
5             System.out.println(st.nextToken());
6         }
7     }    
8 }

輸出結果:

Welcome
to
our
country

 

總結:

在執行效率方面,StringBuilder最高,StringBuffer次之,String最低,使用如下:

  • 如果操作的數據量比較小,應優先使用String類
  • 如果是在單線程下操作大量數據應優先使用StringBuilder類
  • 如果是在多線程下操作大量數據應優先使用StringBuffer類

 

 

4、Java中數組是不是對象?

數組是指具有相同類型的數據的集合,它們一般具有固定的長度,並且在內存中占據連續的空間 

在C/C++中,數組名只是一個指針,這個指針指向了數組的首元素,沒有屬性也沒有方法

而在Java中,數組不僅具有自己的屬性,還有方法可以調用,故在Java中數組是對象

每個數組類型都有其對於的類型,可以通過instanceof來判斷數據的類型,如下:

 1 public class FindLeftAndRightBigger {
 2     public static void main(String[] args) {
 3         int[] a = {1, 2, 3};
 4         int[][] b = new int[2][3];
 5         String[] s = {"asfd", "saf"};
 6         if(a instanceof int[]){
 7             System.out.println("int[]");
 8         }
 9         if(b instanceof int[][]){
10             System.out.println("int[][]");
11         }
12         if(s instanceof String[]){
13             System.out.println("String[]");
14         }
15     }    
16 }
17 // 輸出結果:
18 // int[]
19 // int[][]

 

 

5、Java數組的初始化方法有哪幾種?

Java數組的初始化方法如下:

 1 // 一維數組聲明:
 2 type arrayName[] 或 type[] arrayName
 3 // 二維數組聲明:
 4 type arrayName[][] 或 type[][] arrayName 或 type[] arrayName[]
 5 // 數組初始化:可以在聲明時直接賦值也可以在之后new
 6 // 注:type既可以是基本數據類型也可以是類
 7 
 8 // 一維數組初始化實例:
 9 int[] a = new int[5];  // 動態創建了一個包含5個整形值得數組,默認值為0   
10 int[] a = {1, 2, 3};    // 聲明一個數組並初始化
11 
12 // 二維數組初始化實例:
13 // Java中二維數組的第二維長度可以不同
14 int[][] arr = {{1, 2}, {3, 4, 5}};
15 int[][] arr = new int[2][];
16 arr[0] = new int[]{1, 2};
17 arr[1] = new int[]{3, 4, 5};

注:原生類指未被實例化的類,數組是實例化、被分配空間的類,數組不屬於原生類 

 

 

6、length屬性和length()方法有什么區別?

  • length屬性:獲取數組長度
  • length方法:計算字符串長度
 1 public class test{f
 2     public static void testArray(int[] arr){
 3         System.out.println("數組長度為" + arr.length);
 4     }
 5     
 6     public static void testString(String s){
 7         System.out.println("字符串長度為" + s.length());
 8     }
 9     
10     public static void main(String[] args) {
11         testArray(new int[]{1, 2, 3});      // 3
12         testString("hello");            // 5
13     }    
14 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM