我的Thinking in Java學習筆記(六)
來源:互聯網
上載者:User
第4章 初始化和清理
我個人理解初始化和清理的關係就是吃飯和上廁所,正是有了初始化的對象,我們才能使用清理。但是為什麼要清理呢?想象一下一個人光吃不拉,是個什麼情況?:)難道我們的程式也要像吃飯一樣光產生對象,而不去清理使用完畢的對象?任由我們的對象堆積如山,佔用系統資源?
以建構函式確保初始化的進行
什麼建構函式?建構函式就是一種特殊的函數,當對象產生時,他會被系統自動的調用起來,並且這個函數名稱和class名相同。
class ConstructorTest
{
ConstructorTest()//建構函式是沒有傳回值的,注意不是void的!
{
System.out.println("nothing!");
}
ConstructorTest(String s)
{
System.out.println(s);
}
public static void main(String args[])
{
new ConstructorTest();//當對象產生的時候,系統會自動的調用他的建構函式
new ConstructorTest("hello"); //並且建構函式還可以接受引數,產生你所希望的特定的對象。假如ConstructorTest(String s)是唯一的建構函式,那麼編譯器不允許你以任何其他的方式開產生對象
}
}
有的人看到這裡就是要問了,為什麼我的程式就根本沒有定義過建構函式,但是我為什麼在建立對象的時候依然可以使用他呢?
例如
class test
{
public static void main(String args[])
{
new test(); //沒定義過任何建構函式,但是可以使用,原因就是,當你沒有定義任何建構函式時,系統會自動為你定義一個不接受引數的預設建構函式
}
}
雖然說,系統會幫你定義一個最簡單的,沒有引數的建構函式,但是有一點你必須記住:假如你定義了建構函式,那麼系統就不會自動幫你產生一個預設建構函式,你也休想去調用這個預設的建構函式,你只能調用你自己定義的建構函式!
函數的重載(overloading)
其實我個人老是搞不清重載和覆寫的名稱,並不是我不明白他們之間的差別,而是,我覺得他們的名字太相近了,容易混淆,呵呵~我們用一句最短的話來形容重載------同名稱,不同引數的函數。
舉個小例子,我們大家都很喜歡玩cs的吧,我們會說:大家沖a門,殺了他們。這個"殺"是什麼意思?當然不是現實生活中的殺了,而是遊戲中的定義。這個時候,你就可以把殺作為一個函數來看,例如
class person
{
}
class cs
{
}
class man
{
public void kill(person p)
{
System.out.println(p+" was killed!");
}
public void kill(cs c)
{
System.out.println(c+" was killed");
}
public static void main(String args[])
{
person p=new person();
cs c=new cs();
man m=new man();
m.kill(p);
m.kill(c);
}
}
這裡我們定義了2中’殺‘的的方法, 一種是殺真的人,一種是殺cs中的人,我們在遊戲中喊叫‘殺啊’,我估計沒人會想到你要殺真的人,大家都知道你是要殺遊戲中的人物。如果你說,我要用殺cs中人物的殺的方法來殺捍匪。估計人家都會認為你是神經病。就是因為人的話即使少說幾個字都是無所謂的,因為我們的人工智慧會幫我們分析的,但是電腦不會這樣,你必須指派一個具體的函數給編譯器,於是我們就使用同名稱,但是不同引數的函數,你只要在調用函數的時候傳遞進去相對應的對象就行,而不必寫上一大堆的名字不相同的函數,來分別調用,這樣一個精心挑選的名稱能夠協助你自己和別人編寫、閱讀、剖析器,使同一個函數具有多種不同的意義
在java中,建構函式是必須重載的(也就是系統自動產生預設建構函式的原因),假如你想根據自己的意願來產生不同的對象
那麼,重載建構函式就是閉不可少的了
class person
{
String sex="man";
person()
{
System.out.println("this is a "+sex);
}
person(String s)
{
sex=s;
System.out.println( "this is a "+sex );
}
public static void main(String args[])
{
new person();
new person("woman");
}
}
這裡我們定義了2個建構函式,通過這2個重載的建構函式,我們可以產生不同的的person對象,一個男人,一個女人
區分重載函數
重載的函數具有相同的名字,那麼編譯器怎麼能知道你調用的是那一個呢?其實很簡單,聰明的人估計已經看出來了:每個重載的函數都具備一個獨一無二的引數,即便是引數的順序不同,也足以區分幾個名字相同的重載函數(但是不推薦,因為這樣會讓你的程式難以閱讀和維護)
搭配基本類型進行重載
因為基本類型可以自動由較小的類型轉換為較大的類型,所以當使用重載機制的時候,容易產生混淆,也就是說當你有幾個函數分別是void test(int i) void test(byte b) void test(short s),如果你調用test(3)的時候,你就會發現,3被視為int,而能接受int引數的函數會被喚起,而如果你就只有void test(double d)這麼一個函數,你就會發現int 3自動獲得提升,變為double的值,而當你傳進函數的值大於函數的引數時候,你就必須使用強制轉換才能調用
class Myclass
{
static int i=100;
void test(double d)
{
System.out.println(d);
}
void test(char c)
{
System.out.println(c);
}
public static void main(String args[])
{
Myclass p=new Myclass();
p.test(i); //引數大於傳遞進來的值,自動轉換,輸出100.0
p.test((char)i); //引數小於傳遞進來的值,強制轉換,輸出d
}
}
以傳回值作為重載的基準
注意,java中無法以函數的傳回值作為重載標準之一
default建構函式
default建構函式就是一種不帶有任何引數的建構函式,並且他是在你沒有定義任何建構函式(無論是否有引數)的時候,由系統自動產生的,如果你已經自己定義了建構函式,那麼系統是不會幫你產生建構函式的,你也沒辦法去調用他們
關鍵字this
this的作用主要有
1、在函數中使用,他所代表的是調用此函數的那個控制代碼(object reference)
例如 class test
{
void method1()
{
System.out.println("method1");
}
void method2()
{
System.out.println("method2");
}
void method3()
{
this.method1(); //在函數中調用同一個class中的另外一個函數,其實沒有必要使用this的,直接調用就行
this.method2(); //編譯器會自己偷偷的傳入這個this控制代碼的
System.out.println("method3");
}
public static void main(String args[])
{
test t =new test();
t.method3();
}
}
我們都知道在物件導向的語言中,函數的調用大多數是要同過對象來調用的,那麼這裡的this是幹嗎的呢?其實這個this就是當前對象的控制代碼,你可以採取對物件控點一樣的處理方式來處理這裡的this,例如
class test
{
int i=10;
void method1()
{
int i=20;
System.out.println(i); //這裡列印的是局部變數20
System.out.println(this.i); //這裡列印的全域變數10
this.i=i; //這裡把局部變數的值賦給全域變數
System.out.println(this.i); //這裡列印出改變後的全域變數20
}
public static void main(String args[])
{
test t = new test();
t.method1();
}
}
你可以把這裡的this.i看成是test.i(只是舉個例子,你要是這樣寫的話是編譯不過去的),這樣你就能明白我上面說的"你可以採取對物件控點一樣的處理方式來處理這裡的this"這句話的意思了!
還有一種情況也是需要明確的指出this關鍵字的,就是當你必須明確指出當前的物件控點究竟是誰的時候
class test
{
int i=0;
public test go()
{
i++;
return this;
}
public void show()
{
System.out.println(i);
}
public static void main(String args[])
{
new test().go().go().go().show();
}
}
由於go(通過關鍵字this返回了當前的對象,所以我們可以輕易的在用一個對象身上執行多次操作
2、在建構函式中調用建構函式
也許你編寫的類中,有多個建構函式,興許他們中間有很多相同的地方,那麼我們為了避免寫重複的代碼,可以在構造
class person
{
person()
{
System.out.println("speak chinese");
}
person(String s)
{
this(); //這裡調用的就是person()建構函式
System.out.println("speak english");
}
person(int i)
{
//this();這個是個錯誤!因為只能由this調用一個建構函式!另外,調用建構函式的語句必須放在first statement in constructor
this("man"); //這裡調用的就是person(String s)建構函式
System.out.println("we have "+i+" persons!!!");
}
void show()
{
//this();編譯器不允許你在建構函式之外的任何函數內調用建構函式
}
public static void main(String args[])
{
person p=new person(10);
}
}
static的意義
在我們系統的學習了this之後,我們就應該能比較深刻全面的瞭解什麼是static函數了。他的意思是:對於這個已經被聲明為static的函數來說,你沒辦法在static的函數中直接調用非static的函數,因為他沒有我們上面所講的this,只能使用對象來調用非static函數。但是我們還可以使用class本身來調用他自身的static函數,不用通過任何對象。通過static,你可以想象static的函數就是java中的全域函數,他可以提供對其他static函數和static資料成員的訪問。但是請大家不要大量的使用static的函數和變數,因為這樣讓人感覺好象不是oop的語言(因為oop的語言是使用對象來調用函數的)