方法由傳統的函數發展而來,方法與傳統的函數顯著不一樣:在結構化編程中,函數是一等公民,這個程序由一個個函數組成;在面向對象編程語言裏,類纔是一等公民,整個系統由一個個類組成。所以在Java語言裏,方法不能獨立存在,方法必須屬於類或對象。編程
方法的所屬性:
(1)方法相似於函數。但與函數不一樣的是,方法不能存在,方法必須定義在類裏面。
(2)方法必定要有執行者,必須經過類或對象來調用方法。從邏輯上來看,該方法屬於類自己,應該用類來調用
若是該方法有static修飾,該方法屬於類自己,應該用類調用;
若是該方法無static修飾,該方法屬於對象自己,應該用對象調用
【規則】若是調用同一個類中方法,能夠省略調用者,此時系統會默認添加調用者。若是方法是無static方法,添加this做爲默認調用者;若是方法是static方法,添加類做爲調用者。數組
1 class Method_attribute 2 { 3 //定義一個普通方法 4 public void nonStaticMethod() 5 { 6 System.out.println("這是一個普通方法"); 7 } 8 9 //定義一個static方法 10 public static void StaticMethod() 11 { 12 System.out.println("這是一個類方法"); 13 } 14 15 //在同一個類中一個方法調用另一個方法 16 public void test() 17 { 18 19 this.nonStaticMethod(); 20 this.StaticMethod(); 21 StaticMethod();//省略的是主調類 22 } 23 public static void main(String[] args) 24 { 25 var p=new Method_attribute(); 26 //此時test()方法中的兩個this表明對象p 27 p.test(); 28 } 29 } 30 ---------- 運行Java捕獲輸出窗 ---------- 31 這是一個普通方法 32 這是一個類方法 33 這是一個類方法 34 35 輸出完成 (耗時 0 秒) - 正常終止
Java裏方法是不能獨立存在的,調用方法時必須使用類或對象做爲主調者。若是聲明方法時,包含了形參聲明,則調用方法時必須給這些形參指定參數值,調用參數時傳給形參參數值也稱爲實參。編程語言
Java裏面參數傳遞方式只有一種:值傳遞。所謂值傳遞,就是將實際參數的副本(複製品)傳入方法內,而參數自己不會受到影響。函數
class ParamTransferTest { public static void swap(int a,int b) { //實現變量a和b的值交換 //定義一個臨時變量來保存a的值 var temp=a; a=b; b=temp; System.out.println("swap方法裏,a的值爲:"+a+",b的值爲:"+b); } public static void main(String[] args) { int a=6; int b=9; swap(a,b); System.out.println("交換結束後,a的值爲:"+a+",b的值爲:"+b); } } ---------- 運行Java捕獲輸出窗 ---------- swap方法裏,a的值爲:9,b的值爲:6 交換結束後,a的值爲:6,b的值爲:9 輸出完成 (耗時 0 秒) - 正常終止
Java程序從main()方法開始執行,main()方法開始定義了a、b兩個局部變量,如圖所示:this
程序從main()函數開始執行,當程序進入swap()方法時,系統分配了兩個棧區,將mian()方法中的變量a、b的副本傳入swap()方法,而不是a、b自己。spa
程序在swap()方法中,進行變量a、b交換的值,交換結束後,內存中的存儲狀況:code
兩個示意圖能夠發現,mian()方法棧區中a、b值並未發生改變,程序只改變swap()棧區中的變量a、b。這就是值傳遞的實質:當系統開始執行方法時,系統爲形參初始化,就是把實參變量的值賦給方法的形參變量,方法裏操做的並非實參變量。對象
再看一個例子:blog
1 class DataWrap 2 { 3 int a; 4 int b; 5 } 6 7 public class ReferenceTransferTest 8 { 9 public static void swap(DataWrap dw) 10 { 11 //下面實現的dw的兩個成員的變量值的交換 12 var temp=dw.a; 13 dw.a=dw.b; 14 dw.b=temp; 15 System.out.println("swap()方法裏,a成員變量的值是:" + dw.a + ",b成員變量的值是:"+dw.b); 16 } 17 18 public static void main(String[] args) 19 { 20 var dw=new DataWrap(); 21 dw.a=6; 22 dw.b=9; 23 swap(dw); 24 System.out.println("swap()方法裏,a成員變量的值是:"+dw.a+",b成員變量的值是:"+dw.b); 25 } 26 } 27 ---------- 運行Java捕獲輸出窗 ---------- 28 swap()方法裏,a成員變量的值是:9,b成員變量的值是:6 29 swap()方法裏,a成員變量的值是:9,b成員變量的值是:6 30 31 輸出完成 (耗時 0 秒) - 正常終止
上面結果swap()方法裏和mian()方法裏的兩個變量a、b都發生了改變。這很容易產生錯覺:調用swap()方法時,傳入的時dw自己,而不是它的複製品。內存
下面分析一下程序執行的過程:
(1)程序從mian()方法開始執行:
var dw=new DataWrap();
dw.a=6;
dw.b=9;
這裏建立了一個DataWrap對象,並賦給引用變量dw。堆內存保存該對象自己,棧內存保存的該對象的引用變量。
(2)執行swap(dw);
接下來main()方法開始調用swap()方法,mian(0方法並未結束,系統會爲main()和swap()開闢兩個棧區,用於存放mian()和swap()方法裏的局部變量。調用swap(0方法時,dw做爲實參傳入swap()方法,一樣採用值傳遞:把main()方法裏的dw變量賦值給swap()方法裏的dw形參,從而完成swap()方法的dw形參初始化。下圖顯示main()方法中實參dw傳入swap()方法後的存儲示意圖:
系統只複製了dw變量,但未複製DataWrap對象。
無論程序在swap()方法中仍是在mian()方法的操做dw變量時,實際操做的都是堆內存中的DataWrap對象,他們引用的是同一個變量。所以在swap()方法中交換了dw所引用的a、b兩個成員變量後,可看到在main()方法中dw引用變量引用的a、b變量的值也發生了改變。
實際上,咱們在建立swap()方法時,將
public static void swap(DataWrap dw);中的dw換個符號表示理解起來就更容易,不易混淆。
Java容許定義形參個數可變的參數,從而容許爲方法指定數量不肯定的形參。若是在定義方法時,在最後一個形參的類型後增長三點(...),則表示該形參能夠接受多個參數值,多個參數被看成數組傳入。
1 class VarArgs 2 { 3 public void test(int a,String... names) 4 { 5 System.out.println("a參數:"+a); 6 System.out.println("names數組的長度:"+names.length); 7 for(int i=0;i<names.length;i++) 8 { 9 System.out.println(names[i]); 10 } 11 } 12 public static void main(String... args) 13 { 14 VarArgs va=new VarArgs(); 15 va.test(2,"efdf","fdfs","fjgd"); 16 va.test(34,new String[]{"孫悟空","豬八戒"}); 17 } 18 } 19 class VarArgs 20 { 21 public void test(int a,String... names) 22 { 23 System.out.println("a參數:"+a); 24 System.out.println("names數組的長度:"+names.length); 25 for(int i=0;i<names.length;i++) 26 { 27 System.out.println(names[i]); 28 } 29 } 30 public static void main(String... args) 31 { 32 VarArgs va=new VarArgs(); 33 va.test(2,"efdf","fdfs","fjgd"); 34 va.test(34,new String[]{"孫悟空","豬八戒"}); 35 } 36 } 37 ---------- 運行Java捕獲輸出窗 ---------- 38 a參數:2 39 names數組的長度:3 40 efdf 41 fdfs 42 fjgd 43 a參數:34 44 names數組的長度:2 45 孫悟空 46 豬八戒 47 48 輸出完成 (耗時 0 秒) - 正常終止
va.test(2,"efdf","fdfs","fjgd"); va.test(34,new String[]{"孫悟空","豬八戒"});
這兩種多形參傳入方法均可以,可是第一種方法更加簡潔。
類型[] 形參名
類型...寫法的好處是:
調用方法時更加方便,便可直接傳入多個元素,系統會自動將它們封裝爲數組
也可直接傳入數組
肯定:類型... 這種寫法只能做爲形參列表的最後一個形參
【暗示】一個方法只能由一個形參個數可變的形參
再看一個例子:
1 class VarIntTest 2 { 3 public int add(int... num) 4 { 5 int result=0; 6 for (int i=0;i<num.length;i++) 7 { 8 result+=num[i]; 9 } 10 return result; 11 } 12 public static void main(String[] args) 13 { 14 var p=new VarIntTest(); 15 System.out.println(p.add(1,2,3,4)); 16 } 17 } 18 ---------- 運行Java捕獲輸出窗 ---------- 19 10 20 21 輸出完成 (耗時 0 秒) - 正常終止