面向物件---方法傳參與構造器
方法詳解
方法是類或物件的行為特徵的抽象,方法是類或物件的重要組成部分。Java裡的方法不能單獨存在,在邏輯上要麼屬於類,要麼屬於物件。
方法的所屬性:
Java語言是靜態的,一個類定義完成後,只要不在重新編譯這個類檔案,該類和該類的物件所擁有的方法是固定的,永遠都不會改變。執行方法時必須使用類或物件來作為排程者。
注意:同一個類中的方法之間相互排程時實際上還是this或者來作為排程者,只不過有時侯會省略,但實際上還是存在。
方法的引數傳遞機制:
Java中方法傳遞方式只有一種:值傳遞。所謂值傳遞就是將實際引數值的副本傳入方法內,而引數本身不會受到任何影響。
package org.westos.practice; public class valuetransform { public static void swap(int a,int b){ int tmp; tmp=a; a=b; b=tmp; System.out.println("a="+a+";"+"b="+b); //a=9;b=6 } public static void main(String[] args) { int a=6; int b=9; System.out.println("a="+a+";"+"b="+b); //a=6;b=9 swap(a,b); System.out.println("a="+a+";"+"b="+b); //a=6;b=9 } }
可以看到最終a,b的值並沒有交換,只是傳入及交換函式swap的a,b的兩個副本值發生交換。
引用資料型別傳參:
public class DataWrap {
int a;
int b;
}
測試類,交換a,b的值
package org.westos.practice; public class DataWrapTest { public static void main(String[] args) { DataWrap dw=new DataWrap(); dw.a=6; dw.b=9; swap(dw); System.out.println("a="+dw.a+";b="+dw.b); } private static void swap(DataWrap dw) { int tmp=dw.a; dw.a=dw.b; dw.b=tmp; System.out.println("a="+dw.a+";b="+dw.b); } } /*a=9;b=6 a=9;b=6*/
其中dw作為一個實際引數傳入swap函式,其實是採用值傳遞的方式。複製了dw的副本傳入swap,而dw只是一個引用變數,而並沒有複製實際物件。所以傳入之後相當於在main棧中有一個dw指向實際物件,同時在swap棧中也有一個dw指向實際物件。所以在swap函式中操作的是實際物件,而並非副本。
形參個數可變的方法:
JDK1.5之後,java允許定義形參個數可變的引數,從而允許為方法指定數量不確定的形參。
例項如下:
package org.westos.practice; public class Varages { public static void test(int a,String... books){ //books被當做陣列處理 for (String tmp:books){ System.out.println(tmp); } //輸出整形變數a的值 System.out.println(a); } public static void main(String[] args) { test(5,"Java","c++","python"); } } /*Java c++ python 5*/
可以看出形參個數可變的引數本質就是一個數組引數
public static void test(int a,String... books)
public static void test(int a,String[] books)
這兩段程式碼效果完全一樣,但是呼叫的時候存在差別,形參個數可變的這種方法呼叫更加簡潔。但是它只能放在形參最後傳入,而陣列可以放在任意位置傳入。
- 類名作為形參
先定義一個類,在測試類中再定義一個需要類傳入的方法;
Animal.class
package org.westos.practice;
public class Animal {
public void eat(){
System.out.println("我是普通類的方法");
}
}
- 抽象類作為形參
同上
AbsAnimal.class
package org.westos.practice;
public abstract class AbsAnimal {
public abstract void show();
}
Cat類實現該抽象類;
Cat.class
package org.westos.practice;
public class Cat extends AbsAnimal{
@Override
public void show() {
System.out.println("我是抽象類子類的重寫方法");
}
}
- 介面類作為引數傳遞
MyInterface.class
package org.westos.practice;
public interface MyInterface {
void intershow();
}
Dog類實現該抽象類;
Dog.class
package org.westos.practice;
public class Dog implements MyInterface {
@Override
public void intershow() {
System.out.println("我是介面子類實現的方法");
}
}
測試類中:
package org.westos.practice;
public class MyTest {
public static void main(String[] args) {
//如果方法需要傳入一個類,你就傳入這個類的物件
methodClass(new Animal());
//如果方法需要傳入一個抽象類,你就傳入這個抽象類子類的物件
//Cat類實現了抽象類的方法
//AbsAnimal absan= new Cat();
methodAbsClass(new Cat());
//如果方法需要傳入一個介面類,你就傳入這個介面類實現的子類物件
//Dog類實現了介面方法
methodInterClass(new Dog());
}
public static void methodClass(Animal an){
an.eat();
}
public static void methodAbsClass(AbsAnimal absan){
absan.show();
}
public static void methodInterClass(MyInterface inface){
inface.intershow();
}
}
成員變數和區域性變數
注意事項:
- 成員變數又可分為類變數(被static修飾)和例項變數(沒有被static修飾)。
類變數隨著類的建立而建立,銷燬而銷燬;這個類普遍相同的屬性,如人都有兩個眼睛,一個嘴巴。
例項變數隨著物件的建立而建立,銷燬而銷燬,對於同一個類,不同物件屬性不同,如每個人的身高體重。 - 在一個方法中同名的區域性變數會覆蓋成員變數,不過可以通過this或指定類名作為呼叫者來訪問被覆蓋的成員變數。不過大部分時候應該避免這種重名情況。
- 在程式中使用區域性變數,應該儘可能的縮小區域性變數的範圍,區域性變數的作用範圍越小,它在記憶體中停留的時間就越短,程式執行效能就越好。
深入構造器
構造器是一個特殊的方法,這個方法用於建立例項時執行初始化。構造器是建立物件的重要途徑。
使用構造器執行初始化
當建立一個物件時系統為這個物件的例項變數進行預設初始化,這種預設的初始化把所有基本型別的例項變數設為0或false。把所有引用型別的例項變數設為null。如果想改變這種預設的初始化,想讓系統建立物件時就為該物件的例項變數顯式指定初始值,就可以通過構造器來實現。
注意:如果程式設計師沒有為java提供任何構造器,則系統會為這個類提供一個無引數的構造器,這個構造器為空,不做任何事,但無論如何如何java類至少包含一個構造器。
package org.westos.practice1;
public class ConstructorTest {
public String name;
public int count;
//提供自定義的構造器,該構造器包含兩個引數
public ConstructorTest(String name,int count){
//構造器裡的tjis代表它進行初始化的物件
//將傳入的兩個引數賦值給this代表物件的name和count
this.name=name;
this.count=count;
}
public static void main(String[] args){
//系統將會對該物件執行自定義的初始化
ConstructorTest tc=new ConstructorTest("java",3);
System.out.println(tc.name);
System.out.println(tc.count);
}
}
注意:雖然說構造器是建立物件的途徑,但實際上當程式設計師呼叫構造器的時候,系統先為該物件分配記憶體空間,併為這個物件執行預設初始化,這個物件已經產生了,這些操作在構造器執行之前就都完成了。也就是說,當系統開始執行構造器之前,系統已經建立了一個物件,只是這個物件還不能被外部程式訪問,只能在該構造器中用this來引用。當構造器執行完之後,這個物件會作為構造起的返回值被返回,通常會賦給另一個引用變數,從而讓外部程式可以訪問該物件。
通常把構造器設定成public訪問許可權,從而允許系統中的任何位置的類都能建立該類的物件。
構造器過載
構造器過載和之前的方法過載一樣,每個過載的構造器使用與類相同的名字。只是需要傳入的引數個數和型別不一樣;
例項如下:
package org.westos.practice1;
public class Constructer {
String name;
int age;
//預設的構造器,由於還要定義其他過載構造器,所以得讓他顯式,而不被覆蓋
public Constructer(){
}
public Constructer(String name){
this.name=name;
}
public Constructer(int age){
this.age=age;
}
public static void main(String[] args) {
Constructer ct=new Constructer();
System.out.println(ct.name);
System.out.println(ct.age);
/*null
0*/
String name="Liming";
Constructer ct1=new Constructer(name);
System.out.println(ct1.name);
System.out.println(ct1.age);
/*Liming
0*/
int age=4;
Constructer ct2=new Constructer(age);
System.out.println(ct2.name);
System.out.println(ct2.age);
/*null
4*/
}
}
本例使用方法過載一共建立了三個物件。