470 likes | 591 Views
類別與物件概念. 類別的定義 : class class_name { 類別成員宣告 }. 物件導向 程式設計 (Object Oriented Programming, OOP ):. 將一組彼此相關的方法( Method )和屬性( Properties )封裝起來,變成一個「 類別 」。 類別的「方法」 ( Method ) 類別的「 屬性 」( Properties ) 「物件」是「類別的實例( an instance of a class )」
E N D
類別與物件概念 • 類別的定義: class class_name{類別成員宣告}
物件導向程式設計(Object Oriented Programming, OOP): • 將一組彼此相關的方法(Method)和屬性(Properties)封裝起來,變成一個「類別」。 • 類別的「方法」 (Method) • 類別的「屬性」( Properties) • 「物件」是「類別的實例(an instance of a class)」 • 類別有 封裝(encapsulation)、多型(polymorphism) 、繼承(inheritance) 的特性. • 類別間以相互傳遞訊息(message) {以get方法,set方法}來溝通,每一種訊息在物件中的反應程序稱為方法(method).
物件導向的三大特性 • 封裝 • 封裝是將類別中的程式碼或是資料保護起來,避免受到外界不當的干擾或是使用。 • 繼承 • 繼承的概念來自於階層式的分類。主要的目的是在定義新類別時,不需要重覆的定義相同的屬性或是方法。 • 多型 • 「一個介面,多種使用方法」。
封裝(encapsulation) 根據類別成員的特性分成 private、protected和public等三個封裝等級,也就是存取類別成員的權限等級。 • 在 private 區域的屬性或方法 • 不能被繼承 • 外部程式不能直接存取 • 當需要存取 private 的成員時,只能透過 public 區提供的(get, set)方法。 • 在 protected 區的成員 • 可以被繼承。被指定成protected的屬性或方法,同套件(目錄)中的所有類別均可使用。 • 在 public 區的成員 • 外部程式可以直接存取。 • 沒有指定修飾子的欄位或方法,識同private。
encapsulation (封裝) 示意圖 • 物件的屬性(Properties)都被method所包圍,以確定得到正確的操作
物件與類別的初體驗: • (Class)是產生物件的模板,不同的模板可以產生不同特性的物件。 • (Object)是物件導向程式語言的基本元件。 • Java 程式是由類別所組成 因此完整的程式至少要有一個類別 • 字串 String就是一種類別 (class),而利用 String 類別就可以產生具有 String 特性的物件。程式碼如下:
類別基本架構: • 在一個 *.java 檔裡只能有一個 public 類別,而且此檔名必須與此public類別同名。若檔案中無public類別, 則檔名可以不必和類別同名。 • main() 一定要宣告成 public staticstatic 表示main() 在沒有建立物件的情況下仍然可以被執行 • 類別基本架構:類別通常包括三個成員,屬性、方法、建構子(方法)。 • 在物件導向程式語言中,將專屬於類別的函數稱之為方法(Methods)。 class 類別名稱 { class properties; //屬性 instance properties;//屬性 class methods; //方法 instance methods; //方法 類別名稱(); //建構子 public static void main(String args[]); } 回Java物件導向
存取權限 一個類別中只有被宣告為public 的成員可以被此類別所宣告的物件直接存取 類別內的方法, 可以放心地 存取類別內的 private成員 雖是用 ClassA 宣告成的物件, 但是卻不能存取 其 private 成員
物件的空間配置 • 將類別實體化出多個物件時,每個物件都會有獨立的儲存空間。例如以下的程式碼: class Vehicle //定義的類別 { int wheel; } //定義一個實體變數 Vehicle newCar1= new Vehicle();//實體化一個類別 Vehicle newCar2 = new Vehicle();//再實體化一個類別 Vehicle rCar= newCar1; //只是一個參考
建立資料存set取get的方法 • 除了特殊的情況之外,類別中的資料成員不太可能讓外界直接的存取。否則,使用者可能在未經核對的情況下,任意的修改資料的內容。 • 存取資料成員一般是透過類別中設計的方法來達成,我們也可以在方法中加上資料存取的限制。 • 設定資料成員的值 public void setWheel(int n) //定義方法,設定wheel的值 { if (n>0) wheel = n; } • 取出資料成員的值 public int getWheel() //定義方法,傳回wheel的值 { return wheel; }
類別 中的資料欄稱為屬性(Properties)。 類別 中的屬性可分為兩個大類,1.專屬於物件的 instance屬性2.屬於類別的 static屬性 類別的屬性 • 例如:當我們建立一個整數物件v1如下: • Integer v1=new Integer(95); • 則v1物件包含MAX_VALUE、MIN_VALUE、TYPE等三個類別屬性。 • 使用物件和屬性時以 “.”隔開,格式如下: • 物件名稱.屬性名稱ex: v1. MIN_VALUE • Integer . MIN_VALUE
建構子的使用 • 建構子在物件建立時立即會執行,所以,我們可以在建構子中初始化相關的成員。 • 建構子的名稱必需和類別的名稱相同,建構子可以有傳入的參數,但建構子不能自訂回傳的型態 。 • 因為建構子的回傳型態就是物件本身。 • 定義建構子: class Vehicle //定義的類別 { private int wheel; //定義一個實體變數 public Vehicle() //類別的建構子 { wheel = 4; } }
靜態(static)屬性 • static欄位的重要觀念 • 同一類別中, 使用含有static屬性之類別所建立的物件,彼此可以共同存取同一個靜態屬性。不論您對 該類別建立多少個物件,屬於靜態的屬性只保存一份而已 • static屬性除了物件可使用之外,也可以直接使用類別呼叫 • 這種 變數稱為類別變數 (class variable),也稱為靜態屬性欄 (static field),靜態屬性的使用 物件名稱.靜態屬性名稱;或 類別名稱.靜態屬性名稱; public class Circle{ static double PI=3.14159;//不論是何種圓其圓周律皆同double x; double y; double radius;} 含有靜態變數的類別必須獨立於方法之外(不可放在方法內),就像宣告全域變數時,必須在方法之外宣告一樣。 回Java物件導向
靜態(static)方法 • 靜態(static)方法並不屬於任何一個物件,我們不需要事先建立一個新的物件,就能直接使用該method。 • 因為static方法不需物件就可執行,因此這種方法不能存取instance變數,您若存取instance變數會產生語法錯誤。 • static方法的宣告 static 資料型態 類別方法名稱() { 靜態方法程式碼 } • static方法的使用 類別名稱.靜態方法名稱();//EX:Math.sin(45) (Math is a classname) • static方法為該類別所有的物件所共同擁有,不論您對 該類別建立多少個物件,屬於類別的方法只保存一份而已,這種 方法稱為類別方法 (class method),也稱為靜態方法 (static method), /* 程式裡的 main() 方法的前頭都冠上一個 static 關鍵字,表 示不須建立物件就可執行 main() 方法。*/ 回Java物件導向
建立類別基本架構例( 點類別) • 撰寫一個Point類別,內部有1.平面的位置(x,y)屬性2.建構函數3.x的設定方法void setX(int x) • 4.y的設定方法void setY(int y)5.x的傳回方法int getX() • 6.y的傳回方法int getY()7.顯示點物件內容的方法
Point.java public class Point { protected int x, y; public Point() {} public void setX(int x) { this.x=x;} public void setY(int y) { this.y=y; } public int getX() { return x; } public int getY() { return y; } public String toString() { return ("(x,y)=("+x+","+y+")"); } public static void main(String args[]) { //建立Point類別的物件 Point p1=new Point(); p1.setX(20); p1.setY(10); System.out.println(p1.toString()); } }
建立類別基本架構例(矩形的周長和面積) • 撰寫一個Rectangle類別,內部有1.建構函數 • 2.屬性有長 ,寬, 左上方的頂點 • 3.設定與傳回屬性的兩種方式, • 4.分別計算顯示矩形的周長和面積。
建立Rectangle類別 public class Rectangle { public Point a=new Point(); int l; int w; //instance私有成員 public Rectangle() { } //建構函數 public void setL(int length) { this.l=length; } public void setW(int width) { this.w=width; } public int getL() { return l;} public int getW() { return w;} public int area() { return l*w;} public int girth() { return 2*(l+w); } public String toString() { return "(x,y)=("+a.getX()+","+a.getY()+")"+ ",(L,W)=("+l+","+w+"),area ="+area();} public static void main(String argv[]) { Rectangle rc=new Rectangle(); a.setX(10);a.setY(20); rc.setL(30);rc.setW(40); System.out.println(rc.toString()); } }
Circle.java public class Circle { final static double PI=3.14159; //靜態常數 Public a=new Point(); int r;//radius public Circle() {}//(constructor) public void setR(int r) { this.r=r;} public int getR() { return r; } public double area() { return PI*r*r; } public double girth() { return 2*PI*r; } public String toString() { return "(x,y)=("+a.getX()+","+a.getY()+"),r="+ r +",a="+this.area(); } public static void main(String argv[]) { Circle c=new Circle(); a.setX(10); a.setY(10); c.setR(10); System.out.println(c.toString()); } }
建構函數或(建構子): • 建構函數(Constructor Function)是類別資料成員中的特殊函數,它的名稱與類別名稱相同。 • 當建立新的物件時,會自動執行建構函數一次,利用這個特性,可以用來設定物件的初值。 • 建構函數不能傳回值,所以不必宣告函數的型態。
參數化的建構子 • 類別中可以同時定義多個建構子,而您也可以將參數傳入建構子中,自行決定資料成員的值。例如: • 使用方式: class Vehicle //定義的類別 { private int wheel; //定義一個實體變數 public Vehicle() //類別的建構子 { wheel = 4;} public Vehicle(int n) //定義有參數的建構子 { this(); wheel = n*4; } } Vehicle newCar1 = new Vehicle(); //實體化一個類別 Vehicle newCar2 = new Vehicle(6); //實體化一個類別,並傳入參數
預設建構子的使用 • 如果類別未曾定義建構子,則該類別在實體化時JVM會自動建立一個不做任何事的建構子,該建構子如下: • 但如果類別中自行建立了建構子,JVM就「不會」再幫類別建立建構子。 public Vehicle() { }
方法多載 (Method Overloading) • 方法多載,又可以稱為「重載」、「覆載」,主要目的在於實現物件導向中的「多形」的精神。 • 物件導向程式中允許同一個類別中可以定義相同名稱的方法,這種現象就是「同名異式」。例如: public void sasayHello(int nyHello() public int)
方法多載… • 當方法多載時,各方法的「簽名 (signature) 」不可以相同。 • 所謂的「簽名」是指方法中參數的個數或是型態,但不包含方法回傳值的型態或是方法的封裝型態。 • 一旦類別中發生了此種現象,我們稱該方法被「多載 (overloaded) 」。 public int add (int i1, int i2) {…} public float add(float f1, float f2) {…} public long add(long l1, long l2) {…}
this • 是一個指向物件本身的參考(亦即『指標』) • 「this」這個字眼我們可以直接把它翻譯成「這個」,在類別中使用時,就可以翻譯成「這個類別」。 • this使用方式 (1)this.類別屬性 (2)this.類別方法 (3)this.實體屬性 (4)this.實體方法 • 注意事項 只能在成員方法中使用,不可寫在主程式中。
this() • 「this()」我們直接翻譯成「這個類別的建構子()」。 • this()規則 (1)只能在建構子中使用this() 。 (2)只能寫在建構子中的第一行敘述。 (3)建構子內呼叫另一建構子時,要用this()這個關鍵字來呼叫。 (4)static method內不可以用this()這個關鍵字來呼叫。
我們來看看下面這個建構函數例子: public class Std_dat { String id=new String(); String name= new String(); //學生姓名 int math,eng; //數學和國文成績 public Std_dat( ) { } //建構函數一 public void setID(String id) { this.id=id; } public void setName( String name) { this.name=name; } public void setMath(int score) { math = score; } //設定數學成績 public void setEng (int score) { eng = score;}//設定英文成績 public String getName() { return name; }//取得學生姓名 public String getID() { return id; } //取得學生ID public int getMath() { return math; }//取得數學成績 public int getEng () { return eng; }//取得英文成績 public double getAvg() { return(math+eng)/2; } //取得英文和數學成績的平均 public static void main(String args[]) { Std_dat s1= new Std_dat(); s1.setID ("01"); s1.setName ("小明"); s1.setMath(80); s1.setEng (70); System.out.println("學號"+s1.getID()); System.out.println("姓名"+s1.getName()); System.out.println("數學成績"+s1.getMath()); System.out.println("英文成績"+s1.getEng ()); System.out.println("平均成績"+s1.getAvg()); } }
建立物件陣列 • 要建立物件陣列,首先要建立物件陣列指標,例如: • Std_dat std[ ] =new Std_dat[100]; • 接著再分別指定每一個物件指標對應的物件內容,例如: • std[0]=new Std_dat();//陣列元素0指向的物件 • std[1]=new Std_dat();//陣列元素1指向的物件
Java 之陣列與物件 • myObject 物件的實體:
以物件為method的參數 // 將Circle 類別中加入 compare()方法 class Circle // 定義類別Circle { . . . // Compare() method public Circle compare(Circle cir1) { if(this.r > cir1.getR()) return this; else return cir1; } }
public class Circle { . . . public Circle compare(Circle cir1) { if(this.r > cir1.getR()) return this; else return cir1; } public static void main(String args[]) { Circle cir1=new Circle(); Circle cir2=new Circle(); cir1.setR(2); cir2.setR(1); Circle temp; temp=cir1.compare(cir2); if(cir1==temp) System.out.println("radius of cir1 is larger"); else System.out.println("radius of cir2 is larger"); } }
將物件解構 • 只要設定為 null,就可以將物件解構,並釋放出記憶體,程式碼如下: obj4=null; null跟Null完全不同,沒有Null這種東西
java常用的類別庫 類別庫名稱 說 明 java.applet 存放和applet相關的類別。 java.awt 存放java視窗元件相關的類別。 java.lang Java基本類別,此類別會自動載入。 java.io 存放和I/O相關的類別。 java.net 存放和網路連線相關的類別。 java.util 存放utility相關的類別。
作業: 設計一個 MyTime 類別,包含三個實體變數 h、m、s,分別表示時,分,秒,一個建構子,三個 get 方法,三個 set 方法,以及一個 toString()方法。請使用 MyTime類別中的 set 方法設定為 12 時 34 分 56 秒,然後使用 toString() 顯示。 public class MyTime { private int h, m, s; public MyTime() { } public int getHour() { return h; } public int getMinute() { return m; } public int getSecond() { return s; } public void setHour(int h) { if (h<=24 && h>=1) this.h=h; } public void setMinute(int m) { if (m>=0 && m<60) this.m=m; } public void setSecond(int s) { if (s>=0 && s<60) this.s=s; } public String toString() { return h+":"+m+":"+s; } }
(接上題)。在 MyTime 類別中增加一個 addSecond() 方法(每執行一次加一秒),addSecond() 方法格式如下: (請考慮 分 與 時 的變化) public int addSecond() { //寫出您的程式碼 } • 然後寫一TestTime.java程式類別,使用set 方法設定為 12 時 58 分 59 秒,然後以for迴圈呼叫 addSecond() 方法100次,同時將時間顯示出來(請注意 時 與 分 的變化)。
設計一個 MyDate類別,包含三個實體變數 y、m、d,分別表示年月日,一個建構子 MyDate(),一個私用方法 checkDay(),以及一個 toString() 方法。請設計一個程式使用 MyDate 類別的建構子設定為 2003 年4 月 30 日,然後使用 toString() 顯示。 public class MyDate { private int y, m, d; public MyDate(int y, int m, int d) { this.y = y; if (m >= 1 && m <= 12) this.m = m; else this.m = 1; this.d = checkDay(d); } private int checkDay(int d) { int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; if (d > 0 && d <= days[mm]) return d; if (m==2 && d==29 && (this.y%400==0 || (this.y%4==0 && this.y%100!=0))) return d; return 1; } public String toString() { return y + "/" + m + "/" + d; } } }
(接上題) 在 MyDate 類別中增加一個 addDay() 方法, addDay() 方法格式如下:(請考慮 年 與月 的變化) public int addDay() { //寫出您的程式碼 } • 然後設計一個TestDate.java程式使用 MyDate 類別的建構子設定為 2003 年 11 月 30 日,然後以for迴圈呼叫 addDay() 方法50次,同時將日期顯示出來(請注意 年與 月 的變化)。
使用 講義中的MyDate 及 MyTime類別設計一個test.java程式 • 設定日期為 2003 年12 月 25 日,時間為 15 時 45 分 30 秒,然後使用addSecond() 8640000次後,用 toString() 將 日期及時間顯示出來,請問應該為何年何月何日何時何分何秒。
p.44-p48 為MyTime 之範例 Second.java public class Second { private int s; public Second() { s=0; } public void setSec(int s) { if ((s<0)||(s>=60)) s=0; else this.s=s; } public int getSec() { return s; } public int addSec() { s++; if (s==60) { s=0; return 1; } else return 0; } public String toString() { if (s<10) return "0"+s+"."; else return s+"."; } }
Minute.java public class Minute { private int m; public Minute() { m=0; } public void setMin(int m) { if ((m<0)||(m>=60)) m=0; else this.m=m; } public int getMin() { return m; } public int addMin() { m++; if (m==60) { m=0; return 1; } else return 0; } public String toString() { if (m<10) return "0"+m+":"; else return m+":"; } }
Hour.java public class Hour { private int h; public Hour() { h=1; } public void setHour(int h) { if ((h<=0)||(h>24)) h=0; else this.h=h; } public int getH() { return h; } public int addHour() { h++; if (h==24) { h=0; return 1; } else return 0; } public String toString() { if (h<10) return "0"+h+":"; else return h+":"; } }
Mytime.java // 使此檔與 Second.java, Minute.java, Hour.java 同一目錄(檔案夾) public class Mytime { private Hour h=new Hour(); private Minute m=new Minute(); private Second s=new Second(); int sc; int mc; public void Mytime() { } public Hour getHour() { return h; } public Minute getMin() { return m; } public Second getSec() { return s; } public void setHour(Hour h) { this.h=h; } public void setMin(Minute m) { this.m=m; } public void setSec(Second s) { this.s=s; } public void Next() { sc=s.addSec(); if (sc==1) { mc=m.addMin(); if (mc==1) h.addHour(); } } public String toString() { return h.toString()+m.toString()+s.toString(); } }
Test.java // 使此檔與 Second.java, Minute.java, Hour.java, MyTime.java 同一目錄(檔案夾) public class Test { static public void main(String args[]) { Second s=new Second(); Minute m=new Minute(); Hour h=new Hour(); s.setSec(56); m.setMin(58); h.setHour(11); Mytime a=new Mytime(); a.setSec(s); a.setMin(m); a.setHour(h); System.out.println(a.toString()); for (int i=0;i<10000;i++) { a.Next(); System.out.println(a.toString()); } } }
MyDate.java package ClassLib; public class MyDate { private int y, m, d; int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; public MyDate() { } public void setDate(int y, int m, int d) { this.y=y; this.m=m; this.d=d; } private int checkYear() { if (y%400==0 || (y%4==0 && y%100!=0)) { return 1; } else { return 0; } } private int checkDay(int d) { if (d > 0 && d <= days[m]) { return d; } if (m==2 && d==29 && (this.y%400==0 || (this.y%4==0 && this.y%100!=0))) { return d; } return 1; } public String toString() { return y + "/" + m + "/" + d; } public void decDate() { d=d-1; if (d==0) { m=m-1; switch(m) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: d = 31; break; case 4: case 6: case 9: case 11: d = 30; break; case 2: if (checkYear()==1) d=29; else d=28; break; case 0: y=y-1; m=12; d=31; break; } } }
Continue public void incDate() { d=d+1; { switch(m) { case 1: case 3: case 5: case 7: case 8: case 10: { if (d== 32) { d=1; m=m+1; } } break; case 12: { if (d== 32) { d=1; y=y+1; m=1; } } break; case 4: case 6: case 9: case 11: if (d== 31) { d=1; m=m+1; } break; case 2: if (checkYear()==1) { if (d==30) { d=1; m=3; } } else { if (d==29) { d=1; m=3; } } break; } } } public void IncNDate(int n) { for (int i=0; i<=n; i++) { incDate(); } } public void DecNDate(int n) { for (int i=0; i<=n; i++) { decDate(); } } static public void main(String args[]) { MyDate date=new MyDate(); date.setDate(2008,2,5); date.IncNDate(100); System.out.println(date.toString()); } }