1. 程式人生 > >顯式初始化和隱式初始化

顯式初始化和隱式初始化

問題一:

null和""的區別
String s=null;
s.trim()就會丟擲為空的exception
String s="";
s.trim()就不會拋,為什麼?

答:
NULL代表聲明瞭一個空物件,根本就不是一個字串。
""代表聲明瞭一個物件例項,這個物件例項的值是一個長度為0的空字串。


NULL代表聲明瞭一個空物件,對空物件做任何操作都不行的,除了=和==;

""是一個字串了,只是這個字串裡面沒有內容了。
String s=null;只是定義了一個控制代碼,也就是說你有了個引用,但是這個引用未指向任何記憶體空間(只分配了棧記憶體,而沒有分配堆記憶體)。
String s="";這個引用已經指向了一塊是空字串的記憶體空間,是一個實際的東東了,所以你可以對它操作,而不用擔心什麼了。

這裡""和NULL絕對是兩個概念。
""代表一個字串存在,它的值就是"";NULL代表字串根本沒有實際的值,你並不知道它是什麼。。。

意思就是String string = null 跟String string;是一回事兒

null是空物件 ""是空字串

  1. String s=null;  //null是未分配堆記憶體空間 但分配了棧記憶體空間,並初始化為空物件,
  2. String a;    //分配了一個棧記憶體空間,沒存入任何物件 
  3. String a="";  //分配了一個記憶體空間,存了一個字串物件

問題二:

String s;  和   String s=null;  和   String s="a";     有什麼區別?
針對這三種情況,使用 out.println(s);  的時候, 第一個會出現異常,  第二個會輸出null.    第三個則會輸出a.
這是為什麼呢?這三句宣告語句,各自作了什麼呢?


答:

第一個
:只是定義了一個String型別變數s,並沒有給它賦初值,在Java中,預設在使用一個變數的時候必須賦予它初值
(降低風險)。
第二個和第三個都定義了String型別變數s,並賦予它初值,只不過第二個賦予的值為null(空)罷了

主要要理解的是String s; s為一個引用~~它不是物件
第一個是沒有初始化的引用;
第二個為空引用;
第三個是在字串池裡寫入一個字元'a',然後用s指向它。

另外,
String s="a"  和   String s=new String("a");   是有本質上的區別的 :
前者是在字串池裡寫入一個字元'a',然後用s指向它;
後者是在上建立一個內容為"a"的字串物件
  1. String str="aaa";      //於棧上分配記憶體
  2. String str=new String("aaa"
    );     //於堆上分配記憶體,棧上產生棧幀,str地址指向了堆上的物件 
  3. String s;    //系統會自動賦值null
  4. String s;   //只是給s分配一個記憶體空間 
  5. String s=null;   //是分配的空間中儲存的值為空值 
  6. String s="a";    //這句就不用我多說了分配的空間的值為字元a

問題三:

聲明瞭一個string a;變數
在以後的判斷中,a==""和a==null有何不同? 

答:

如果沒有給a賦過值,a==""會導致異常。
在實際處理時,往往認為""和null代表相同的含義,即都代表無值。
此時建議用如下語法:
  1. if(a==null || a=="") {   }   
如果a為null,就不會執行後面的判斷,直接返回true。

null是用來判斷引用型別是否分配了儲存空間
""是針對字串的;
string型別實際上是字串指標,也即是一個引用型別
所以如果沒有給a賦過值,a==""會導致異常
所以if(a==null || a==""){}這種寫法也是正確的


問題四:

String abc=null;    String abc="";    String abc;    三種寫法有什麼區別?
答:
1:建立一個空字串物件,
2:建立一個字串為空的字串物件。
對於最後一種表示,你不能if(abc==null),或者int length = abc.length();編譯的時候會提示可能沒有初始化.
String abc=null;
String abc="";
一般推薦使用第二種

第一種abc指向null,很多時候要判斷字串是否為空時,容易漏掉這種情況,在呼叫String的相關方法的時候就會出錯
第二種則相對簡單,String的方法都可以用,判斷的時候也不會出錯

  1. 1) String abc=null;   
  2. 2) String abc;   
  3. 3)String a="";   
  4. 4) String b="";   
  5. 5) String c=new String("");   
  6. 6) String d=new String("");  
//  1)等於2),和C語言不同,JAVA為安全原因不允許一個懸掛引用,沒有賦值的引用地址一律自動賦值為NULL,以防止訪問到任意記憶體
//  3)和4)中, 變數a和b將會指向同一記憶體地址(""的地址)
//  5)和6)中,變數c和d不會指向同一地址,而是兩個""內容的地址,並且和a,b不同,實際上 ,  3)和4) 相當於new String("").intern().
//  String類維護著一個字串池,對於像3)和4)這樣的賦值方法,String會在這個池中查詢字串是否已經在池中,如果在,就直接指向該地址,
如果不在,生成一個例項放入池中再指向那個地址,可見對於同樣內容的字串多次引用時3)4)的方法要比5)6)的方法節省記憶體,之所以這樣做,是
因為String是一個內容不可變的量,運用的是設計模式GOF.FlyWeight;
但有個關鍵的一點,沒有人說到,這就是:
String s;   在什麼情況下可以等同於   String s=null;   而在什麼情況下又不等同?!

考慮下面的程式碼:

  1. //StringTest.java 
  2. publicclass StringTest {   
  3. static String s; //* 
  4. publicstaticvoid main(String[] args) {   
  5. //String s; //**   本地變數是不會自動初始化的
  6. System.out.println(s);   
  7. }   
  8. }   
編譯並執行上面的程式碼,將列印null。
可見標有*號的行是自動初始化了的(s被自動初始化為null)。
而如果把標有**號的行取消註釋,程式碼將不能通過編譯,這是因為這行定義的是本地變數,而本地變數是不會自動初始化的
由此得出結論:
成員變數的定義中,String s;等同於String s=null;
而在本地變數(方法變數)的定義中,String s;不等同於String s=null;,這時要使用s必須顯式地賦值。
這些雖然是小知識點,但在實際應用中很重要,也很容易被一些人忽視,特此提出。

還有一點要說明的是:
只要是在方法在中定義變數都要顯示賦初值,main()方法也不例外,而在方法之外編譯器回自動賦初值。