java 學習 方法參數按值傳遞和按引用傳遞:

[list]

按值傳遞:所謂按值傳遞就是在方法內部改變參數的值並不會影響傳遞進來的外部對象,例如:
Java代碼 複製代碼 收藏代碼
  1. int i = 1;   
  2. public void increment(int i){   
  3.    i++;   
  4.    System.out.println(i);   //輸出爲2   
  5. }   
  6. System.out.println(i);   //輸出爲1  
        int i = 1;
        public void increment(int i){
           i++;
           System.out.println(i);   //輸出爲2
        }
        System.out.println(i);   //輸出爲1
按引用傳遞:引用傳遞和按值傳遞相反,它會影響傳遞進來的外部對象(像C中的"&參數"就是按引用傳遞);

[/list]
在Java只有按值傳遞,可能有人會奇怪傳遞進來如是對象,它會改變對象的值,例如:

Java代碼 複製代碼 收藏代碼
  1. public class Test{   
  2.    int i;   
  3.    public void increment(Test t){   
  4.        t.i++;   
  5.        System.out.println(i);   //輸出爲1   
  6.    }   
  7.    public static void main(String[] args){   
  8.        Test t = new Test();   
  9.        t.increment(t);   
  10.        System.out.println(t.i); //輸出也爲1   
  11.    }   
  12. }  
       public class Test{
          int i;
          public void increment(Test t){
              t.i++;
              System.out.println(i);   //輸出爲1
          }
          public static void main(String[] args){
              Test t = new Test();
              t.increment(t);
              System.out.println(t.i); //輸出也爲1
          }
       }


這的確是改變了對象的值,但它並沒有改變對象引用的值,它還是指向原來的對象,我們傳遞進來的是對象引用並不是對象,造成這種錯誤的認識主要是沒有理解對象和對象引用的區別,我們可以將對象理解爲氣球,而對象引用可理解爲拉着氣球的線,所以這還是按值傳遞;

1)"別名"問題:因爲Java中只有按值傳遞,所以就會出現當有幾個句柄(對象引用)指向同一對象時,有的可能需要改變對象的值,而有的並不需要,這就產生了別名問題,解決這一問題就是製作本地副本對象,通過Object.clone()方法,如下:

Java代碼 複製代碼 收藏代碼
  1.      public class TestHandIn implements Cloneable {   
  2.         private int in;   
  3.         public void testreference(TestHandIn testin){   
  4.    //製作本地副本,使其不影響外部對象   
  5.     TestHandIn in = (TestHandIn)testin.clone();   
  6.     in.in++;   
  7.     System.out.println(in.in);//輸出爲1   
  8. }   
  9.         public Object clone(){   
  10.    Object obj = null;   
  11.    try {   
  12.      obj = super.clone();   
  13.            } catch (CloneNotSupportedException e) {   
  14.     System.out.println(e.getMessage());   
  15.    }   
  16.    return obj;   
  17. }   
  18.         public static void main(String[] args){   
  19.             TestHandIn in = new TestHandIn();   
  20.             in.testreference(in);   
  21.     System.out.println(in.in); //輸出爲0,沒有改變   
  22.         }   
  23.      }  
      public class TestHandIn implements Cloneable {
         private int in;
         public void testreference(TestHandIn testin){
	   //製作本地副本,使其不影響外部對象
	    TestHandIn in = (TestHandIn)testin.clone();
	    in.in++;
	    System.out.println(in.in);//輸出爲1
	}
         public Object clone(){
	   Object obj = null;
	   try {
		 obj = super.clone();
            } catch (CloneNotSupportedException e) {
		System.out.println(e.getMessage());
	   }
	   return obj;
	}
         public static void main(String[] args){
             TestHandIn in = new TestHandIn();
             in.testreference(in);
	    System.out.println(in.in); //輸出爲0,沒有改變
         }
      }


clone()方法在Object中是protected的,子類要具有clone能力需覆蓋此方法並實現Cloneable接口,這樣做是爲了不使每個類默認都具有clone能力,並且Object.clone()方法會檢查該類是否實現了Cloneable接口,所以必須實現Cloneable接口;
2)只讀類String及其"同志"類StringBuffer和StringBuilder:先看如下一段代碼:

Java代碼 複製代碼 收藏代碼
  1. public void passString(String s){   
  2.    s = s + "abc";   
  3.    System.out.println(s);  //輸出123abc   
  4. }   
  5. public static void main(String[] args){   
  6.    String s = "123";   
  7.    passString(s);   
  8.    System.out.println(s);   //輸出123,並沒有改變   
  9. }  
         public void passString(String s){
            s = s + "abc";
            System.out.println(s);  //輸出123abc
         }
         public static void main(String[] args){
            String s = "123";
            passString(s);
            System.out.println(s);   //輸出123,並沒有改變
         }


這好像看起來是按引用傳遞參數,其實是String類的作用,在String中的每個方法都是新建了個對象對其進行操作,所以原來對象並沒有改變,String類也稱只讀類,它很好的解決了"別名問題",但如果需要一個修改的對象就很麻煩,同時有效率問題,於是出現了"同志"類StringBuffer和StringBuilder,StringBuffer是線程同步的,而StringBuilder不是,效率高些;StringBuffer和StringBuilder的append()方法修改不需要頻繁創建對象,效率比"+"要高,但"+"看起來比較直觀,根據實際情況選擇:

Java代碼 複製代碼 收藏代碼
  1. String s = "abc";   
  2. s = s + "def" + "f" + "g" + "h";  //效率低   
  3.  StringBuffer sb = new StringBuffer("abc");   
  4. sb.append("def").append("f").append("g").append("h"); //效率高  
         String s = "abc";
         s = s + "def" + "f" + "g" + "h";  //效率低
          StringBuffer sb = new StringBuffer("abc");
         sb.append("def").append("f").append("g").append("h"); //效率高


在String中比較有用的字符集轉換方法:String.getBytes()和new String(byte[] bytes, String charsetName),在解決中文問題時非常有用的兩個方法,字節流和字符流的轉換橋樑類InputStreamReader和InputStreamWriter,底層實現就是使用這兩個方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章