第三章 面向對象(上)
第三講 面向對象
理解面向對象的概念
● 面向過程
在一個結構體中定義窗口的大小,位置,顏色,背景等屬性,對窗口操作的函數與窗口本身的定義沒有任何關系,如HideWindow,MoveWindow,MinimizeWindow,這些函數都需要接受一個代表要被操作的窗口參數,是一種謂語與賓語的關系。
● 面向對象
定義窗口時,除了要指定在面向過程中規定的那些屬性,如大小,位置,顏色,背景等外,還要指定該窗口可能具有的動作,如隱藏,移動,最小化等。這些函數被調用時,都是以某個窗口要隱藏某個窗口要移動的語法格式來使用的,這是一種主語與謂語的關系。
● 面向對象的三大特征
▂封裝
▂繼承
▂多態
類與對象
類是對某一類事物的描述,是抽象的,概念上的定義;對象是實際存在的該類事物的每個個體,因而也稱實例(instance)。
如果將對象比作汽車,那么類就是汽車的設計圖紙。所以面向對象程序設計的重點是類的設計,而不是對象的設計。
類的定義
public class Person()
{
int age;
void shout()
{
System.out.println("I am age "+age);
}
}
● age是類的屬性,也叫類成員變量
● shout是方法也叫類的成員函數。
● shout方法可以直接訪問同一類中的age變量,如果一個方法中有與成員同名的局部變量,該方法中對這個
變量名的訪問是局部變量,而不是成員變量。
在類中創建的成員變量會被初始化,局部變量不會被初始化。
對象的使用
創建新的對象之后,我們就可以使用“對象名.對象成員”的格式,來訪問對象的成員(包括屬性和方法)
class Person
{
int age;
void shout()
{
System.out.println("age="+age);
}
}
class TestPerson
{
public static void main(String[]args)
{
Person p1=new Person();
p1.age=20;
p1.shout();
Person p2=new Person();
p2.shout();
}
}
上面程序運行的內存布局如下:
對象的比較
● “==”運算符與equals()方法的區別
“==”用來比較值是否相等,equals()方法用來比較兩個對象的內容是否相等
● 怎樣比較兩個數組對象的內容是否相等
arrays.equals(ary1[],ary2[]);
匿名對象
● 我們也可以不定義對象的句柄,而直接調用這個對象的方法。這樣的對象叫做匿名對象,
如:new Person().shout();
● 如果對一個對象只需要進行一次方法調用,那么就可以使用匿名對象。
● 我們經常將匿名對象作為實參傳遞給一個函數調用。
實現類的封裝性
● 如果外面的程序可以隨意修改一個類的成員變量,會造成不可預料的程序錯誤,就象一個人身高,不能被外部隨意修改,只能通過各種攝取營養的方法去修改這個屬性。
● 在定義一個類的成員(包括變量和方法)時,使用private關鍵字說明這個成員的訪問權限,這個成員成了 類的私有成員,只能被這個類其他成員方法調用,而不能被其他類中的方法所調用。
● 為了實現良好的封裝性,我們通常將類的成員變量聲明為private,再通過public方法來對這個變量進行訪問。對一個變量操作,一般都有讀取和賦值操作,我們分別定義兩個方法來實現這兩種操作,一個是getXxx()方法(Xxx表示要訪問的成員變量的名字),用來讀取這個成員變量操作,另外一個是setXxx()用來對這個變量賦值。
● 一個類通常就是一個小的模塊,我們應該讓模塊僅僅公開必須要讓外界知道的內容,而隱藏其它一切內容。我們在進行程序的詳細設計時,應盡量避免一個模塊直接修改或操作另外一個模塊的數據,模塊設計追求強內聚(許多功能盡量在類的內部獨立完成,不讓外面干預),弱耦合(提供給外部盡量少的方法調用)。
class Person
{
private int age;
void shout()
{
System.out.println(age);
}
public void setAge(int x)
{
if(x<0)
return;
age=x;
}
public int getAge()
{
return age;
}
}
class TestPerson
{
public static void main(String[]args)
{
Person p=new Person();
p.setAge(18);
p.shout();
System.out.println(p.getAge());
}
}
構造函數的定義與作用
● 構造函數的特征
▁它具有與類相同的名稱;
▁它不含返回值
▁它不能在方法中用return語句返回一個值
注意:在構造方法里不含返回值的概念是不同于“void”的,在定義構造方法時加了”voiid”,結果這個方法就不再被自動調用。
● 構造方法的作用:當一個類的實例對象剛產生時,這個類的構造方法就會被自動調用,我們可以在這個方法中加入要完成初始化工作的代碼。
構造方法的重載
● 和一般的方法重載一樣,重載的構造方法具有不同個數或不同類型的參數,編譯器就可以根據這一點判斷出用new 關鍵字產生對象時,該調用哪個構造方法了。產生對象的格式是:new 類名(參數列表);
● 重載構造方法可以完成不同初始化的操作,如:p3=new Person(“Tom”18);語句,會做這樣幾件事:創建指定類的新實例對象,在堆內存中為實例對象分配內存空間,并調用指定類的構造方法,最后將實例對象的首地址賦值給引用變量p3。
This引用句柄的應用
● 一個類中成員方法可以直接調用同類中的其他成員,其實我們在一個方法內部使用“this.其他成員”的引用方式和直接使用“其他成員”的效果是一樣的,那this還有多大的作用呢?在有些情況下,我們是非得用this關鍵字不可的:
▁讓類的成員變量名和對其進行賦值的成員方法的形參變量同名是必要的,這樣的代碼誰看了都能明白這兩個變量是彼此相關的。
▁假設我們有一個容器類和一個部件類,在容器類的某個方法中創建部件類的實例對象,而部件類的構造方法要接收一個代表其所在容器的參數。
▁構造方法是在產生對象時被java系統自動調用的,我們不能在程序中象調用其他方法一樣去調用構造方法。但我們可以在一個構造方法里調用其他重載的構造方法,不是用構造方法名,而是用this(參數列表)形式,根據其中的參數列表,選擇相應的構造方法。
垃圾回收過程分析
● c++中的析構方法
● java中的finalize()方法
● System.gc的作用
Static靜態變量
當我們編寫一個類時,其實就是在描述其對象的屬性和行為,而并沒有產生實質上的對象,只有通過new關鍵字才會產生出對象,這時系統才會分配內存空間對象,其方法才可以供外部調用。我們有時候希望無論是否產生了對象或無論產生了多少對象的情況下,某些特定的數據在內存空間里只有一份。
編寫使用靜態變量統計一個類產生的實例對象的個數的程序。
class Person
{
private String name;
private static int count=0;
static String country="中國";
public Person()
{
System.out.println(name+":"+ ++count);
}
public Person(String name)
{
this.name=name;
System.out.println(name+":"+ ++count);
}
void shout()
{
System.out.println(name);
}
}
class TestPerson
{
public static void main(String[]args)
{
Person p=new Person("張三");
new Person();
p.shout();
new Person("李四").shout();
System.out.println(Person.country);
}
}
運行結果:
張三:1
null:2
張三
李四:3
李四
中國
Static靜態方法
● 在靜態方法里只能直接調用同類中其它的靜態成員(包括變量和方法),而不能直接訪問類中的非靜態成員。這是因為,對于非靜態的方法和變量,需要先創建類的實例對象后才可使用,而靜態方法在使用前不用創建任何對象。
● 靜態方法不能以任何方式引用this和super關鍵字。與上面的道理一樣,因為靜態方法在使用前不用創建任何實例對象,當靜態方法被調用時,this所引用的對象根本就沒有產生。
● main()方法是靜態的,因此JVM在執行main方法時不創建main方法所在的類的實例對象,因而在main()方法中,我們不能直接訪問該類中的非靜態成員,必須創建該類的一個實例對象后,才能通過這個對象去訪問類中的非靜態成員。
單態設計模式
● 設計模式是在大量的實踐中總結和理論化之后優選的代碼結構、編程風格、以及解決問題的思考方式。
● 所謂類的單態設計模式,就是采取一定的方法保證在整個的軟件系統中,對某個類只能存在一個對象實例,并且該類只提供一個取得其對象實例的方法。如果我們要讓類在一個虛擬機中只能產生一個對象,我們首先必須將類的構造方法的訪問權限設置為private,這樣就不能用new操作符在類的外部產生類的對象了,但在類的內部仍可以產生該類的對象。因為在類的外部開始還無法等到類的對象,只能調用該類的某個靜態方法以返回類內部創建的對象,靜態方法只能訪問類中的靜態成員變量,所以,指向類內部產生的該類對象的變量也必須定義成靜態的。
class Chinese
{
static Chinese obj=new Chinese();
public static Chinese getInstance()
{
return obj;
}
private Chinese()
{
System.out.println("ss");
}
}
class TestChinese
{
public static void main(String[]args)
{
Chinese obj1=Chinese.getInstance();
Chinese obj2=Chinese.getInstance();
System.out.println(obj1==obj2);
//如果相等返回true,否則返回false.
}
}
運行結果:
ss
true
內部類
——在類中直接定義的內部類(嵌套類)
● 內部類(嵌套類)可以直接訪問外部類(嵌套它的類)的成員,包括private成員,但是,內部類(嵌套類)的成員卻不能被外部類(嵌套它的類)直接訪問。
● 在內部類對象保存了一個對外部類對象的引用,當內部類的成員方法中訪問某一變量時,如果在該方法和內部類中都沒有定義過這個變量,內部類中對this的引用會被傳遞給那個外部類對象的引用。
● 如果用static修飾一個內部類,這個類就相當于是一個外部定義的類,所以static的內部類中可聲明static成員,但是,非static的內部類中的成員是不能聲明為static。Static的內部類不能再使用外層封裝的非static的成員變量,這個道理不難想象,所以static嵌套類很少使用。
class Outer
{
int outer_i=100;
void test()
{
Inner inner=new Inner();
inner.display();
}
class Inner
{
void display()
{
System.out.println(outer_i);
}
}
public static void main(String[]args)
{
Outer outer=new Outer();
outer.test();
}
}
● 如果函數的局部變量(函數的參數也是局部變量)、內部類的成員變量、外部類的成員變量重名,我們應該按下面的程序代碼所使用的方式來明確指定我們真正要訪問的變量。
public class Outer
{
private int size;
public class Inner
{
private int size;
public void doStuff(int size)
{
size++;//引用的是doStuff函數的形參
this.size++;//引用的是Inner類中的成員變量
Outer.this.size++;//引用的是Outer類中的成員變量
}
}
}
內部類如何被外部引用
class Outer
{
private int size=100;
public class Inner
{
public void doStuff()
{
System.out.println(++size);
}
}
}
public class TestInner
{
public static void main(String[]args)
{
Outer outer=new Outer();
Outer.Inner inner=outer.new Inner();
inner.doStuff();
}
}
在方法中定義的內部類
● 嵌套類并非只能在類中定義,也可以在幾個程序塊的范圍之內定義內部類。例如,在方法中,或甚至在for循環體內部,都可以定義嵌套類。
● 在方法中定義的內部類只能訪問方法的fianl類型的局部變量,用final定義的局部變量相當于是一個常量,它的生命周期超出方法運行的生命周期。
posted on 2007-06-07 23:33 大頭劍客 閱讀(395) 評論(0) 編輯 收藏 所屬分類: 學習筆記