實驗三 面向對象的編程基礎
【開發(fā)語言及實現平臺或實驗環(huán)境】Windows2000 或XP,JDK1.5以上版本與Eclipse集成開發(fā)環(huán)境
【實驗目的】
理解Java語言是如何體現面向對象編程基本思想,
了解類的封裝方法,以及如何創(chuàng)建類和對象.
了解成員變量和成員方法的特性。
掌握OOP方式進行程序設計的方法
了解類的繼承性和多態(tài)性的作用。
了解Java 中包(package)、接口(interface)的作用。
掌握包、接口的使用方法。
【實驗任務】
編寫一個體現面向對象思想的程序。
編寫一個創(chuàng)建對象和使用對象的方法程序。
編寫不同成員變量修飾方法的程序。
編寫不同成員方法修飾的程序。
編寫體現類的繼承性(成員變量,成員方法,成員變量隱藏)的程序。
編寫體現類多態(tài)性(成員方法重載,構造方法重載)的程序。
了解Java 系統(tǒng)包的結構。
掌握創(chuàng)建自定義包的方法。
掌握使用系統(tǒng)接口的技術和創(chuàng)建自定義接口的方法。
【實驗內容或實驗步驟】
1.程序功能:通過兩個類StaticDemo、LX3_4 說明靜態(tài)變量/方法與實例變量/方法的區(qū)別。
2.編寫類文件LX3_4.java,程序源代碼如下。
class StaticDemo {
static int x;
int y;
public static int getX() {
return x;
}
public static void setX(int newX) {
x = newX;
}
public int getY() {
return y;
}
public void setY(int newY) {
y = newY;
}
}
public class LX3_4 {
public static void main(String[] args) {
System.out.println("靜態(tài)變量x="+StaticDemo.getX());
System.out.println("實例變量y="+StaticDemo.getY()); // 非法,編譯時將出錯
StaticDemo a= new StaticDemo();
StaticDemo b= new StaticDemo();
a.setX(1);
a.setY(2);
b.setX(3);
b.setY(4);
System.out.println("靜態(tài)變量a.x="+a.getX());
System.out.println("實例變量a.y="+a.getY());
System.out.println("靜態(tài)變量b.x="+b.getX());
System.out.println("實例變量b.y="+b.getY());
}
}
3.對上面的源程序進行編譯,會出現如圖3.4 所示的出錯提示。
4.將源程序中的出錯語句刪除或使用解釋符//隱藏起來,例如,
//System.out.println("實例變量y="+StaticDemo.getY());
5.重新編譯并運行該程序,結果如圖3.5 所示。
static 聲明的成員變量/方法被視為類的成員變量/方法,而不把它當作實例對象的成員變量/方法。換句話說,靜態(tài)變量/方法是類固有的,可以直接引用,其它成員變量/方法僅僅被聲明,生成實例對象后才存在,才可以被引用。基于這樣的事實,也把靜態(tài)變量/方法稱為類變量/方法,非靜態(tài)變量稱為實例變量/方法。
從實驗結果可以得出以下幾點結論:
·類的靜態(tài)變量可以直接引用,而非靜態(tài)變量則不行。類的靜態(tài)變量相當于某些程序語言的全局變量。
·靜態(tài)方法只能使用靜態(tài)變量,不能使用實例變量。因為對象實例化之前,實例變量不可用。
·類的靜態(tài)變量只有一個版本,所有實例對象引用的都是同一個版本。
·對象實例化后,每個實例變量都被制作了一個副本,它們之間互不影響。
(四) 方法中參數傳遞的練習
在其它語言中,函數調用或過程調用時參數有傳值調用和傳地址調用之分。在Java 中,方法中的參數傳遞可以分為傳值調用或對象方法調用等方式。傳值調用即傳遞的參數是基本數據類型,調用方法時在方法中將不能改變參數的值,這意味著只能使用它們。對象調用是指先調用對象,再調用對象的方法,這種方式可以修改允許存取的成員變量。所以,如果不想改變參數的值,可以采用傳值調用的方法。如果想改變參數的值,可采用對象調用的方法,間接修改參數的值。
1.編寫一個傳值調用的程序文件LX3_5.java。
(1)程序功能:程序首先給整型變量x 和y 賦一個初值10,然后使用傳值調用方式調用方法ff1對x 和y 做乘方及輸出x 和y 的乘方值,最后再輸出x 和y 的乘方值。
(2)程序源代碼如下。
class LX3_5 {
public static void main(String[] args) {
int x=10, y=10;
ff1(x, y);
System.out.println("x="+x+", y="+y);
}
static void ff1(int passX, int passY) {
passX=passX*passX;
passY=passY*passY;
System.out.println("passX="+passX+", passY="+passY);
}
}
(3)編譯LX3_5.java,其運行結果如圖3.6 所示。
(4)分析其運行結果
這個程序沒有實現預期的結果,原因是ff1 方法采用了傳值調用。調用ff1 方法時,將產生兩個參數passX 和passY,x 和y 的值被傳遞給這兩個參數。盡管在方法中計算了參數的平方,但從ff1方法返回后,參數消失,此時x 和y 的值仍是初值。
2.編寫一個調用對象方法的程序文件LX3_6.java。
(1)程序功能:通過調用對象的方法在方法調用后修改了成員變量的值。
(2)LX3_6.java 程序源代碼如下。
class LX3_6 {
public static void main(String[] args) {
Power p=new Power();
p.ff2(10,10);
System.out.println("方法調用后 x="+p.x+", y="+p.y);
}
}
class Power{
int x=10, y=10;
void ff2(int passX, int passY) {
System.out.println("初始時 x="+x+", y="+y);
x=passX*passX;
y=passY*passY;
System.out.println("方法調用中 x="+x+", y="+y);
}
}
(3)編譯LX3_6.java,其運行結果如圖3.7 所示。
(五) 類的繼承性練習
1. 進一步理解繼承的含義
新類可從現有的類中產生,并保留現有類的成員變量和方法并可根據需要對它們加以修改。新類還可添加新的變量和方法。這種現象就稱為類的繼承。
當建立一個新類時,不必寫出全部成員變量和成員方法。只要簡單地聲明這個類是從一個已定義的類繼承下來的,就可以引用被繼承類的全部成員。被繼承的類稱為父類或超類(superclass),這個新類稱為子類。
Java 提供了一個龐大的類庫讓開發(fā)人員繼承和使用。設計這些類是出于公用的目的,因此,很少有某個類恰恰滿足你的需要。你必須設計自己的能處理實際問題的類,如果你設計的這個類僅僅實現了繼承,則和父類毫無兩樣。所以,通常要對子類進行擴展,即添加新的屬性和方法。這使得子類要比父類大,但更具特殊性,代表著一組更具體的對象。繼承的意義就在于此。
2. 創(chuàng)建公共類LX3_7_P
(1)編寫程序文件LX3_7_P.java,源代碼如下。
public class LX3_7_P
{
protected String xm; //具有保護修飾符的成員變量
protected int xh;
void setdata(String m,int h) //設置數據的方法
{
xm =m;
xh = h;
}
public void print() //輸出數據的方法
{
System.out.println(xm+", "+xh);
}
}
(2)編譯LX3_7_P.java,產生類文件LX3_7_P.class。
3.創(chuàng)建繼承的類
(1)程序功能:通過LX3_7_P 類產生子類LX3_8,其不僅具有父類的成員變量xm(姓名)、xh(學號),還定義了新成員變量xy(學院)、xi(系)。在程序中調用了父類的print 方法,同時可以看出子類也具有該方法。
(2)編寫LX3_8.java 程序,源代碼如下。
class LX3_8 extends LX3_7_P{
protected String xy;
protected String xi;
public static void main(String args[])
{
LX3_7_P p1 = new LX3_7_P();
p1.setdata("帥零",12321) ;
p1.print();
LX3_8 s1 = new LX3_8() ;
s1.setdata("郭麗娜",12345); //調用父類的成員方法
s1.xy="經濟管理學院"; //訪問本類的成員變量
s1.xi="信息管理系"; //訪問本類的成員變量
s1.print();
System.out.print(s1.xm+", "+s1.xy+", "+s1.xi);
}
}
(3)編譯并運行程序,其結果如圖3.8 所示。
3.了解成員變量的隱藏方式
所謂隱藏是指子類重新定義了父類中的同名變量,在子類Line 中重新定義了x 為x1,y 為y1,隱藏了父類Point 中的兩個成員變量x 和y。子類執(zhí)行自己的方法時,操作的是子類的變量,子類執(zhí)行父類的方法時,操作的是父類的變量。在子類中要特別注意成員變量的命名,防止無意中隱藏了父類的關鍵成員變量,這有可能給程序帶來麻煩。
4.了解成員方法的覆蓋方式
(1)方法覆蓋的定義與作用
通過繼承子類可以繼承父類中所有可以被子類訪問的成員方法,但如果子類的方法與父類方法同名,則不能繼承,此時稱子類的方法覆蓋了父類的方法,簡稱為方法覆蓋(override)。方法覆蓋為子類提供了修改父類成員方法的能力。例如,子類可以修改層層繼承下來的Object 根類的toString 方法,讓它輸出一些更有用的信息。下面的程序顯示了在子類Circle 中添加toString 方法,用來返回圓半徑和圓面積信息。
(2)編寫覆蓋Object 類toString 方法的程序文件LX3_9.java,源代碼如下。
class Circle {
private int radius;
Circle(int r) {
setRadius(r);
}
public void setRadius(int r) {
radius=r;
}
public int getRadius() {
return radius;
}
public double area() {
return 3.14159*radius*radius;
}
public String toString() {
return "圓半徑:"+getRadius()+" 圓面積:"+area();
}
}
public class LX3_9{
public static void main(String args[]) {
Circle c=new Circle(10);
System.out.println(""n"+c.toString());
}
}
(3)編譯并運行程序,其結果如圖3.9 所示
(4)程序結構分析。
程序添加了toString 方法并修改了它的返回值。由于toString 和繼承下來的Object 類的方法名相同、返回值類型相同,因此覆蓋了超類Object 中的toString 方法。
方法覆蓋時要特別注意:
用來覆蓋的子類方法應和被覆蓋的父類方法保持同名、相同的返回值類型,以及相同的參數個數和參數類型。
5.This、super 和super()的使用
(1)程序功能:說明this、super 和super()的用法。程序首先定義Point(點)類,然后創(chuàng)建點的子類Line(線)。最后通過LX3_10 類輸出線段的長度。
程序中通過super(a,b)調用父類Point 的構造方法為父類的x 和y 賦值。在子類Line 的setLine方法中,因為參數名和成員變量名相同,為給成員變量賦值,使用this 引用,告訴編譯器是為當前類的成員變量賦值。在length 和toString 方法中使用父類成員變量時,使用super 引用,告訴編譯器使用的是父類的成員變量。
(2)使用this、 super 和super()的程序文件LX3_10.java,源代碼如下。
class Point {
protected int x, y;
Point(int a, int b) {
setPoint(a, b);
}
public void setPoint(int a, int b) {
x=a;
y=b;
}
}
class Line extends Point {
protected int x, y;
Line(int a, int b) {
super(a, b);
setLine(a, b);
}
public void setLine(int x, int y) {
this.x=x+x;
this.y=y+y;
}
public double length() {
int x1=super.x, y1=super.y, x2=this.x, y2=this.y;
return Math.sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
}
public String toString() {
return "直線端點:[" + super.x + "," + super.y + "] [" +
x + "," + y + "] 直線長度:" + this.length();
}
}
public class LX3_10{
public static void main(String args[]) {
Line line=new Line(50, 50);
System.out.println(""n"+line.toString());
}
}
(3)編譯并運行程序,結果如圖3.10 所示。
六 類的多態(tài)性練習
1. 理解類的多態(tài)性
類的繼承發(fā)生在多個類之間,而類的多態(tài)只發(fā)生在同一個類上。在一個類中,可以定義多個同名的方法,只要確定它們的參數個數和類型不同。這種現象稱為類的多態(tài)。
多態(tài)使程序簡潔,為程序員帶來很大便利。在OOP 中,當程序要實現多個相近的功能時,就給相應的方法起一個共同的名字,用不同的參數代表不同的功能。這樣,在使用方法時不論傳遞什么參數,只要能被程序識別就可以得到確定的結果。
類的多態(tài)性體現在方法的重載(overload)上,包括成員方法和構造方法的重載。
2. 方法的重載
方法的重載是指對同名方法的不同使用方式。
(1)程序功能:對不同的數進行排序輸出。在IntSort 類中定義3 個同名的方法sort,
(2)編寫LX3_11.java 文件,源代碼如下(自己編寫程序代碼)。
3.構造方法的重載
構造方法的名稱和類同名,沒有返回類型。盡管構造方法看起來和一般的成員方法沒有差別,但它不是方法,也不是類的成員。因此,構造方法不能直接調用,只能由new 操作符調用。
構造方法對于類是十分重要的,對象的初始化任務要靠構造方法來完成。
重載構造方法的目的是提供多種初始化對象的能力,使程序員可以根據實際需要選用合適的構造方法來初始化對象。
(1) 編寫構造方法RunDemo 的重載程序文件LX3_12,源代碼如下。
class RunDemo {
private String userName, password;
RunDemo() {
System.out.println("全部為空!");
}
RunDemo(String name) {
userName=name;
}
RunDemo(String name, String pwd) {
this(name);
password=pwd;
check();
}
void check() {
String s=null;
if (userName!=null)
s="用戶名:"+userName;
else
s="用戶名不能為空!";
if (password!="12345678")
s=s+" 口令無效!";
else
s=s+" 口令:********";
System.out.println(s);
}
}
public class LX3_12 {
public static void main(String[] args) {
new RunDemo();
new RunDemo("劉新宇");
new RunDemo(null,"邵麗萍");
new RunDemo("張馳","12345678");
}
}
(2)編譯并運行程序,結果如圖3.12 所示。
(3)三個構造方法,其中
第一個無參構造方法RunDemo() 的實際作用是對成員變量賦缺省初值,由于userName和password都是String 類,所以它們的缺省初值為null。
第二個構造方法RunDemo(String) 只有一個參數,用來對成員變量userName 賦初值。
第三個構造方法RunDemo(String, String) 有兩個參數,并有更多的內容,首先調用this(name),其實際作用就是調用當前類的構造方法RunDemo(String name);然后對成員變量password 賦值;最后調用check 方法來檢查userName 和password,類似于一般程序的口令驗證。重載構造方法的執(zhí)行由對象根據實際參數的個數、類型和順序確定。
【思考】
2.程序的結構。類與對象的關系。對象創(chuàng)建、使用、銷毀的過程。
3. 方法的參數傳遞有哪些方式?區(qū)別時什么?
4. 說明什么是構造方法。
5. 說明程序中有多個類時如何確定源程序文件的名稱。
6. 說明類的繼承和多態(tài)有什么作用,在使用上應該注意什么問題。
posted on 2010-04-15 14:36 libifeng 閱讀(1017) 評論(0) 編輯 收藏 所屬分類: Java實驗指導書