[Java入門筆記] 物件導向編程基礎(二):方法詳解,java物件導向編程
什麼是方法?簡介
在上一篇的blog中,我們知道了方法是類中的一個組成部分,是類或對象的行為特徵的抽象。
無論是從文法和功能上來看,方法都有點類似與函數。但是,方法與傳統的函數還是有著不同之處:
在結構化程式設計語言裡,函數是基本的程式組成單元,一個程式由一個個函數組成;
在物件導向程式設計語言裡,類才是程式的基本單元,方法是屬於類或對象的,不能獨立存在;
Java語言裡方法的特徵主要在以下幾個方面:
方法不能夠獨立的存在,方法只能夠定義在類裡面,所屬與某個類或對象;
方法不能夠被獨立地執行,必須使用類或者對象作為調用者;
方法的分類,在Java中,方法主要分為以下幾類:
Java中的方法,主要可以分為構造方法和普通方法,而普通方法可以分為類方法和對象方法;
方法的定義
在前面一篇blog,我們已經知道了方法的定義方式,我們再來回顧一下:
構造方法:
[修飾符] 類名([形參 參數名]){ //功能代碼}
構造方法是你一種特殊的方法,它與普通方法有兩個不同之處:方法的名字必須和類名相同,它沒有傳回值
普通方法:
[修飾符] 傳回值 方法名([形參 參數名]){ //功能代碼}
我們可以看到,普通方法的結構主要分為5個部分,
修飾符:設定方法的存取權限,可以是public、protected、private、或者是不填;
傳回值:調用該方法完成之後返回的內容,可以是基本的資料類型,可以是參考型別,也可以沒有傳回值,當沒有傳回值時,使用void
方法名:自訂的標識符,主要是調用時使用,在類外部或非子類中調用時使用 類.方法名 或者 對象名.方法名
形參:形參調用該方法時所需要傳遞的參數,可以有0個或多個
方法體{}:方法體內主要用於定義實現功能的代碼
看一個完整的例子:
定義一個Person類:
public class Person{ //定義一個Person類 public String name; //String類型的屬性name public int age; //int類型的屬性age public Person(String n, int a){ //構造方法,有兩個參數n和a,在建立對象是如果調用了該構造方法就會將name屬性設定為傳進來的n,age為a。 name = n; age = a; } public void showName(){ //普通方法,主要功能是顯示對象的name System.out.println("我的名字是" + name); } public void setAge(int a){ //普通方法,主要功能是設定對象的age,有一個參數,將對象的age設定為傳遞進來的a變數 age = a; } public int getAge(){ //普通方法,有一個傳回值,返回對象的age return age; }}
使用:
public class Test{ public static void main(String[] args){ Person p = new Person("張三", 20); //執行個體化一個對象,調用構造方法,傳遞進去兩個參數,將參數設定給了對象的name屬性和age屬性 p.showName(); //調用p對象的showName方法,執行了方法體裡面的代碼,列印出了p對象的name p.setAge(25); //調用了p對象的setAge方法,重新設定了p對象的age屬性值為25 int pAge = p.getAge(); //調用了p對象的getAge方法,該方法有一個傳回值,將p對象的age屬性值返回了出來,並將傳回值賦值給了pAge變數 }}
方法的調用與參數的傳遞在記憶體中的機制
不在關鍵點上追根問底的程式猿不是一個好廚師,下面我們開看看方法的調用與參數傳遞在程式啟動並執行記憶體中是一個什麼樣子滴情況:
對於JVM運行機制,有興趣的可以看看這幾篇文章:
java運行時記憶體配置詳解
深入理解JVM—JVM記憶體模型
《深入理解Java虛擬機器》筆記
java運行記憶體配置圖
當然,有興趣的並且有一定基礎的童鞋推薦大家看看一本好書《深入理解Java虛擬機器》
我們來看看上面一個例子的代碼:
Person p = new Person("張三", 20);
建立對象的分析我們在上篇blog中分析了,有興趣的可以圍觀:[Java入門筆記] 物件導向編程基礎(一):類和對象 在最後面
對象建立完畢後,在記憶體中是這樣的一個樣子:
程式繼續向下執行:
p.showName();
調用p對象的showName方法,執行裡面的代碼:
println也是一個方法,這個是JavaApi中定義的方法,執行在記憶體中有點麻煩,現在先不看這個,執行完這句話後列印出“我的名字是張三”
繼續下下執行
p.setAge(25);
調用p對象的setAge方法
執行到這一步我們發現,這個方法有一個int類型的形參,名字為a,值為25
繼續執行setAge方法,將a的值賦值給age
此時p對象的age屬性值變化為為25,方法執行完成後清除完成代碼的引用,繼續下面的代碼
int pAge = p.getAge();
執行到這一句會將p對象的age返回,並且賦值給int類型變數pAge,所以pAge的值此時也為25:
方法的重載什麼是方法的重載?
方法重載是指在一個類中定義多個同名的方法,但要求每個方法具有不同的參數的類型或參數的個數。調用重載方法時,Java編譯器能通過檢查調用的方法的參數類型和個數選擇一個恰當的方法。方法重載通常用於建立完成一組任務相似但參數的類型或參數的個數不同的方法。
如何?方法的重載?
方法的重載要求兩同一不同,三不受影響,兩同指的是同一個類中相同的方法名,一不同是方法的形參不同,這個不同主要體現在參數個數不同或者類型不同、參數位置不同。
兩不受影響是:
修飾符不同不影響方法重載。
方法的傳回值類型不能用於區分方法的重載,也就是說,無論傳回值相同或者不同,都對判斷方法是否重載沒有影響。
形參的名字不能用於區分方法是否重載,也就是說,如果形參的類型和個數都相同,只有參數的名字不同,則不構成重載。
構造方法的重載:
構造方法也是一種方法類型,也可以實現重載,也遵循上面的規定。
例:
public class Person{ public String name; public int age; public Person(){} public Person(String n, int a){ name = n; age = a } public void setInfo(){ name = "張三"; age = 20; } public void setInfo(String n){ name = n; } public void setInfo(int a){ age = a; } public void setInfo(String n, int a){ name = n; age = a; } public void setInfo(int a, String n){ name = n; age = a; }}
上面的2個構造方法和4個setInfo都是重載的方法,因為它們滿足了重載的要求:相同的類中相同的方法名,不同的參數類型或個數。
如果在上面的例子中添加下面的方法,不是重載:
private int setInfo(){} //修飾符和傳回值不同,但是上面已經有一個沒有參數的setInfo方法,所以不是重載
public void set(){} //方法名不同,不是重載
public void setInfo(int b){} //參數名不同,類型上面有相同的,不是重載
重載方法的使用:
public class Test{ public static void main(String[] args){ Person p1 = new Person(); Person p2 = new Person("李四", 30); //這兩個對象被執行個體化時第一個沒有傳遞參數,所以調用第一個構造方法,第二個有兩個參數,所以調用第二個構造方法 p1.setInfo(); //沒有參數,調用第一個setInfo方法 p1.setInfo("王五"); //有一個String類型的參數,調用第二個setInfo方法 }}
形參個數可變的方法
如果我們在實現某個方法不確定方法有多少個參數數,我們應該怎麼定義這個方法?
比如,如果我們要寫一個實現加法的方法,而我們不僅僅是要實現2個數相加,而是無論是有多少個數,我們都需要將它們加起來,我們應該怎樣定義這個方法?顯然,用普通的形式定義或者重載都不能很好的實現,而我們可以使用jdk1.5之後增加的一種形參傳遞方法定義這個方法。
例:
public class Operation{ public static int add(int... num){ int result = 0; for(int i = 0; i < num.length; i++){ result += num[i]; } return result; }}
這個例子中我們可以看到,定義一個可變的形參的方法,只需要在類型後面加三個點即可,調用這個方法時既可傳遞多個相同類型的是參數。
在使用num參數時我們可以明顯的看到,就是用數組的形式在使用,因此這個可變的參數在本質上來說其實就是一個數組,不過在調用時可以比較方便,請看:
public class Test{ public static void main(String[] args){ Operation ope = new Operation(); ope.add(1,2); //計算1加2 ope.add(3,4,5); //計算3加4加5 }}
我們在使用時不需要再建立一個數組對象。