【課前思考】 1. 什麼是對象?什麼是類?什麼是包?什麼是接口?什麼是內部類? 2. 面向對象編程的特性有哪三個?它們各自又有哪些特性? 3. 你知道Java語言在面向對象編程方面有何獨特的特色嗎?
難點: 1. 理解方法重載和方法重寫,不要混淆了二者的使用。 2. 類變量和類方法的使用。 3. 接口的使用。 3.1 面向對象技術基礎
3.1.1 面向對象的基本概念 面向對象的基本思想 面向對象是一種新興的程序設計方法,或者是一種新的程序設計規範(paradigm),其基本思想是使用對象、類、繼承、封裝、消息等基本概念來進行程序設計。從現實世界中客觀存在的事物(即對象)出發來構造軟件系統,而且在系統構造中儘量運用人類的天然思惟方式。開發一個軟件是爲了解決某些問題,這些問題所涉及的業務範圍稱做該軟件的問題域。其應用領域不只僅是軟件,還有計算機體系結構和人工智能等。
1. 對象的基本概念 對象是系統中用來描述客觀事物的一個實體,它是構成系統的一個基本單位。一個對象由一組屬性和對這組屬性進行操做的一組服務組成。
主動對象是一組屬性和一組服務的封裝體,其中至少有一個服務不須要接收消息就能主動執行(稱做主動服務)。 2. 類的基本概念 類是具備相同屬性和服務的一組對象的集合,它爲屬於該類的全部對象提供了統一的抽象描述,其內部包括屬性和服務兩個主要部分。在面向對象的編程語言中,類是一個獨立的程序單位,它應該有一個類名幷包括屬性說明和服務說明兩個主要部分。
3. 消息
消息就是向對象發出的服務請求,它應該包含下述信息:提供服務的對象標識、服務標識、輸入信息和回答信息。服務一般被稱爲方法或函數。
3.1.2 面向對象的基本特徵
1.封裝性 封裝性就是把對象的屬性和服務結合成一個獨立的相同單位,並儘量隱蔽對象的內部細節,包含兩個含義: ◇ 把對象的所有屬性和所有服務結合在一塊兒,造成一個不可分割的獨立單位(即對象)。 ◇ 信息隱蔽,即儘量隱蔽對象的內部細節,對外造成一個邊界〔或者說造成一道屏障〕,只保留有限的對外接口使之與外部發生聯繫。 封裝的原則在軟件上的反映是:要求使對象之外的部分不能隨意存取對象的內部數據(屬性),從而有效的避免了外部錯誤對它的"交叉感染",使軟件錯誤可以局部化,大大減小查錯和排錯的難度。
2.繼承性 特殊類的對象擁有其通常類的所有屬性與服務,稱做特殊類對通常類的繼承。
一個類能夠是多個通常類的特殊類,它從多個通常類中繼承了屬性與服務,這稱爲多繼承。
在java語言中,一般咱們稱通常類爲父類(superclass,超類),特殊類爲子類(subclass)。
3.多態性 對象的多態性是指在通常類中定義的屬性或服務被特殊類繼承以後,能夠具備不一樣的數據類型或表現出不一樣的行爲。這使得同一個屬性或服務在通常類及其各個特殊類中具備不一樣的語義。例如:"幾何圖形"的"繪圖"方法,"橢圓"和"多邊形"都是"幾何圖"的子類,其"繪圖"方法功能不一樣。 3.1.3 面向對象程序設計方法 OOA-Object Oriented Analysis 面向對象的分析 OOD-Object Oriented Design 面向對象的設計 OOI-Object Oriented Implementation 面向對象的實現 3.2 Java語言的面向對象特性
3.2.1 類 類是java中的一種重要的複合數據類型,是組成java程序的基本要素。它封裝了一類對象的狀態和方法,是這一類對象的原形。一個類的實現包括兩個部分:類聲明和類體
1.類聲明: [public][abstract|final] class className [extends superclassName] [implements interfaceNameList] {……} 其中,修飾符public,abstract,final 說明了類的屬性,className爲類名,superclassName爲類的父類的名字,interfaceNameList爲類所實現的接口列表。 2.類體 類體定義以下: class className {[public | protected | private ] [static] [final] [transient] [volatile] type variableName; //成員變量 [public | protected | private ] [static] [final | abstract] [native] [synchronized] returnType methodName([paramList]) [throws exceptionList] {statements} //成員方法 } 3.成員變量 成員變量的聲明方式以下: [public | protected | private ] [static] [final] [transient] [volatile] type variableName; //成員變量 其中, static: 靜態變量(類變量);相對於實例變量 final: 常量 transient: 暫時性變量,用於對象存檔,用於對象的串行化,見對象的串行化一節 volatile: 貢獻變量,用於併發線程的共享 4.成員方法 方法的實現包括兩部份內容:方法聲明和方法體。 [public | protected | private ] [static] [final | abstract] [native] [synchronized] returnType methodName([paramList]) [throws exceptionList] //方法聲明 {statements} //方法體 方法聲明中的限定詞的含義: static: 類方法,可經過類名直接調用 abstract: 抽象方法,沒有方法體 final: 方法不能被重寫 native: 集成其它語言的代碼 synchronized: 控制多個併發線程的訪問 ◇ 方法聲明 方法聲明包括方法名、返回類型和外部參數。其中參數的類型能夠是簡單數據類型,也能夠是複合數據類型(又稱引用數據類型)。 對於簡單數據類型來講,java實現的是值傳遞,方法接收參數的值,但不能改變這些參數的值。若是要改變參數的值,則用引用數據類型,由於引用數據類型傳遞給方法的是數據在內存中的地址,方法中對數據的操做能夠改變數據的值。 例3-1說明了簡單數據類型與引用數據的區別。 【例3-1】 import java.io.*; public class PassTest{ float ptValue; public static void main(String args[]) { int val; PassTest pt=new PassTest(); val=11; System.out.println("Original Int Value is:"+val); pt.changeInt(val); //值參數 System.out.println("Int Value after Change is:" +val); /*值參數 值的修改,沒有影響值參數的值*/ pt.ptValue=101f; System.out.println("Original ptValue is:"+pt.ptValue); pt.changeObjValue(pt); //引用類型的參數 System.out.println("ptValue after Change is:"+pt.ptValue);/* 引用參數值的修改,改變了引用參數的值*/ } public void changeInt(int value){ value=55; //在方法內部對值參數進行了修改 } public void changeObjValue(PassTest ref){ ref.ptValue=99f; //在方法內部對引用參數進行了修改 } }
◇ 方法體 方法體是對方法的實現,它包括局部變量的聲明以及全部合法的Java指令。方法體中聲明的局部變量的做用域在該方法內部。若局部變量與類的成員變量同名,則類的成員變量被隱藏。 爲了區別參數和類的成員變量,咱們必須使用this。this-----用在一個方法中引用當前對象,它的值是調用該方法的對象。返回值須與返回類型一致,或者徹底相同,或是其子類。當返回類型是接口時,返回值必須實現該接口。 5.方法重載 方法重載是指多個方法享有相同的名字,可是這些方法的參數必須不一樣,或者是參數的個數不一樣,或者是參數類型不一樣。返回類型不能用來區分重載的方法。 參數類型的區分度必定要足夠,例如不能是同一簡單類型的參數,如int與long。編譯器會根據參數的個數和類型來決定當前所使用的方法。
6. 構造方法 ◇ 構造方法是一個特殊的方法。Java 中的每一個類都有構造方法,用來初始化該類的一個對象。 ◇ 構造方法具備和類名相同的名稱,並且不返回任何數據類型。 ◇ 重載常常用於構造方法。 ◇ 構造方法只能由new運算符調用
3.2.2 對象 類實例化可生成對象,對象經過消息傳遞來進行交互。消息傳遞即激活指定的某個對象的方法以改變其狀態或讓它產生必定的行爲。一個對象的生命週期包括三個階段:生成、使用和消除。
對象的清除 當不存在對一個對象的引用時,該對象成爲一個無用對象。Java的垃圾收集器自動掃描對象的動態內存區,把沒有引用的對象做爲垃圾收集起來並釋放。 System.gc( ); System.exit();//terminate the current JVM 當系統內存用盡或調用System.gc( )要求垃圾回收時,垃圾回收線程與系統同步運行。 3.2.3 面向對象特性 java語言中有三個典型的面向對象的特性:封裝性、繼承性和多態性。
1. 封裝性 java語言中,對象就是對一組變量和相關方法的封裝,其中變量代表了對象的狀態,方法代表了對象具備的行爲。經過對象的封裝,實現了模塊化和信息隱藏。經過對類的成員施以必定的訪問權限,實現了類中成員的信息隱藏。 ◇ java類中的限定詞 java語言中有四種不一樣的限定詞,提供了四種不一樣的訪問權限。 1) private 類中限定爲private的成員,只能被這個類自己訪問。 若是一個類的構造方法聲明爲private,則其它類不能生成該類的一個實例。 2) default 類中不加任何訪問權限限定的成員屬於缺省的(default)訪問狀態:friend,能夠被這個類自己和同一個包中的類所訪問。 3) protected 類中限定爲protected的成員,能夠被這個類自己、它的子類(包括同一個包中以及不一樣包中的子類)和同一個包中的全部其餘的類訪問。 4) public 類中限定爲public的成員,能夠被全部的類訪問。 【表3-1】 java中類的限定詞的做用範圍比較
同一個類 同一個包 不一樣包的子類 不一樣包非子類
private *
default * *
protected * * *
public * * * *
2. 繼承性 經過繼承實現代碼複用。Java中全部的類都是經過直接或間接地繼承java.lang.Object類獲得的。繼承而獲得的類稱爲子類,被繼承的類稱爲父類。子類不能繼承父類中訪問權限爲private的成員變量和方法。子類能夠重寫父類的方法,及命名與父類同名的成員變量。但Java不支持多重繼承,即一個類從多個超類派生的能力。 ◇ 成員變量的隱藏和方法的重寫 子類經過隱藏父類的成員變量和重寫父類的方法,能夠把父類的狀態和行爲改變爲自身的狀態和行爲。 例如: class SuperClass{ int x; … void setX( ){ x=0; } … } class SubClass extends SuperClass{ int x; //隱藏了父類的變量x … void setX( ) { //重寫了父類的方法 setX() x=5; } …. } 注意:子類中重寫的方法和父類中被重寫的方法要具備相同的名字,相同的參數表和相同的返回類型,只是函數體不一樣。 ◇ super java中經過super來實現對父類成員的訪問,super用來引用當前對象的父類。Super 的使用有三種狀況: 1)訪問父類被隱藏的成員變量,如: super.variable; 2)調用父類中被重寫的方法,如: super.Method([paramlist]); 3)調用父類的構造函數,如: super([paramlist]);
【例3-5】 import java.io.*; class SuperClass{ int x; SuperClass( ) { x=3; System.out.println("in SuperClass : x=" +x); } void doSomething( ) { System.out.println("in SuperClass.doSomething()"); } } class SubClass extends SuperClass { int x; SubClass( ) { super( ); //調用父類的構造方法 x=5; //super( ) 要放在方法中的第一句 System.out.println("in SubClass :x="+x); } void doSomething( ) { super.doSomething( ); //調用父類的方法 System.out.println("in SubClass.doSomething()"); System.out.println("super.x="+super.x+" sub.x="+x); } } public class Inheritance { public static void main(String args[]) { SubClass subC=new SubClass(); subC.doSomething(); } }
3. 多態性 在java語言中,多態性體如今兩個方面:由方法重載實現的靜態多態性(編譯時多態)和方法重寫實現的動態多態性(運行時多態)。 1) 編譯時多態 在編譯階段,具體調用哪一個被重載的方法,編譯器會根據參數的不一樣來靜態肯定調用相應的方法。 2) 運行時多態 因爲子類繼承了父類全部的屬性(私有的除外),因此子類對象能夠做爲父類對象使用。程序中凡是使用父類對象的地方,均可以用子類對象來代替。一個對象能夠經過引用子類的實例來調用子類的方法。 ◇ 重寫方法的調用原則:java運行時系統根據調用該方法的實例,來決定調用哪一個方法。對子類的一個實例,若是子類重寫了父類的方法,則運行時系統調用子類的方法;若是子類繼承了父類的方法(未重寫),則運行時系統調用父類的方法。 在例3-6中,父類對象a引用的是子類的實例,因此,java運行時調用子類B的callme方法。
【例3-6】 import java.io.*; class A{ void callme( ) { System.out.println("Inside A''s callme()method"); } } class B extends A{ void callme( ) { System.out.println("Inside B''s callme() Method"); } } public class Dispatch{ public static void main(String args[]) { A a=new B(); a.callme( ); } } ◇ 方法重寫時應遵循的原則: 1)改寫後的方法不能比被重寫的方法有更嚴格的訪問權限(能夠相同)。 2)改寫後的方法不能比重寫的方法產生更多的例外。 4. 其它 ◇ final 關鍵字 final 關鍵字能夠修飾類、類的成員變量和成員方法,但final 的做用不一樣。 1) final 修飾成員變量: final修飾變量,則成爲常量,例如 final type variableName; 修飾成員變量時,定義時同時給出初始值,且之後不能被修改,而修飾局部變量時不作要求。 2) final 修飾成員方法: final修飾方法,則該方法不能被子類重寫 final returnType methodName(paramList){ … }
3) final 類: final修飾類,則類不能被繼承 final class finalClassName{ … } ◇ 實例成員和類成員 用static 關鍵字能夠聲明類變量和類方法,其格式以下: static type classVar; static returnType classMethod({paramlist}) { … } 若是在聲明時不用static 關鍵字修飾,則聲明爲實例變量和實例方法。 1) 實例變量和類變量 每一個對象的實例變量都分配內存,經過該對象來訪問這些實例變量,不一樣的實例變量是不一樣的。 類變量僅在生成第一個對象時分配內存,全部實例對象共享同一個類變量,每一個實例對象對類變量的改變都會影響到其它的實例對象。類變量可經過類名直接訪問,無需先生成一個實例對象,也能夠經過實例對象訪問類變量。 2) 實例方法和類方法 實例方法能夠對當前對象的實例變量進行操做,也能夠對類變量進行操做,實例方法由實例對象調用。 但類方法不能訪問實例變量,只能訪問類變量。類方法能夠由類名直接調用,也可由實例對象進行調用。類方法中不能使用this或super關鍵字。 例3-7 是關於實例成員和類成員的例子。 【例3-7】 class Member { static int classVar; int instanceVar; static void setClassVar(int i) { classVar=i; // instanceVar=i; // 類方法不能訪問實例變量 } static int getClassVar() { return classVar; } void setInstanceVar(int i) { classVar=i; //實例方法不但能夠訪問類變量,也能夠實例變量 instanceVar=i; } int getInstanceVar( ) { return instanceVar; } } public class MemberTest{ public static void main(String args[]) { Member m1=new member(); Member m2=new member(); m1.setClassVar(1); m2.setClassVar(2); System.out.println("m1.classVar="+m1.getClassVar()+" m2.ClassVar="+m2.getClassVar()); m1.setInstanceVar(11); m2.setInstanceVar(22); System.out.println("m1.InstanceVar="+m1.getInstanceVar ()+" m2.InstanceVar="+m2.getInstanceVar()); } } ◇ 類java.lang.Object 類java.lang.Object處於java開發環境的類層次的根部,其它全部的類都是直接或間接地繼承了此類。該類定義了一些最基本的狀態和行爲。下面,咱們介紹一些經常使用的方法。 equals() :比較兩個對象(引用)是否相同。 getClass():返回對象運行時所對應的類的表示,從而可獲得相應的信息。 toString():用來返回對象的字符串表示。 finalize():用於在垃圾收集前清除對象。 notify(),notifyAll(),wait():用於多線程處理中的同步。
3.2.4抽象類和接口
1. 抽象類 java語言中,用abstract 關鍵字來修飾一個類時,這個類叫作抽象類,用abstract 關鍵字來修飾一個方法時,這個方法叫作抽象方法。格式以下: abstract class abstractClass{ …} //抽象類 abstract returnType abstractMethod([paramlist]) //抽象方法 抽象類必須被繼承,抽象方法必須被重寫。抽象方法只需聲明,無需實現;抽象類不能被實例化,抽象類不必定要包含抽象方法。若類中包含了抽象方法,則該類必須被定義爲抽象類。
若一個類繼承了一個抽象類,則抽象類的抽象方法必須被實現,不然子類必須聲明爲abstract. 2. 接口 接口是抽象類的一種,只包含常量和方法的定義,而沒有變量和方法的實現,且其方法都是抽象方法。它的用處體如今下面幾個方面: ◇ 經過接口實現不相關類的相同行爲,而無需考慮這些類之間的關係。 ◇ 經過接口指明多個類須要實現的方法。 ◇ 經過接口瞭解對象的交互界面,而無需瞭解對象所對應的類。 1)接口的定義 接口的定義包括接口聲明和接口體。 接口聲明的格式以下: [public] interface interfaceName[extends listOfSuperInterface] { … } extends 子句與類聲明的extends子句基本相同,不一樣的是一個接口可有多個父接口,用逗號隔開,而一個類只能有一個父類。 接口體包括常量定義和方法定義 常量定義格式爲:type NAME=value; 該常量被實現該接口的多個類共享; 具備public ,final, static的屬性。在接口中只能聲明常量,不能夠聲明變量。 方法體定義格式爲:(具備 public和abstract屬性,不能聲明爲protected) returnType methodName([paramlist]);
注意:在接口的實現類中,實現的接口方法必須聲明爲public ,由於接口中定義的方法爲public(默認)。因此其實現必須聲明爲public.不然編譯不會經過。 2)接口的實現 在類的聲明中用implements子句來表示一個類使用某個接口,在類體中可使用接口中定義的常量,並且必須實現接口中定義的全部方法。一個類能夠實現多個接口,在implements子句中用逗號分開。 3) 接口類型的使用 接口做爲一種引用類型來使用。任何實現該接口的類的實例均可以存儲在該接口類型的變量中,經過這些變量能夠訪問類所實現的接口中的方法。 3.2.5 內部類
1. 內部類的定義和使用: 內部類是在一個類的內部嵌套定義的類,它能夠是其它類的成員,也能夠在一個語句塊的內部定義,還能夠在表達式內部匿名定義。 內部類有以下特性: ◇ 通常用在定義它的類或語句塊以內,在外部引用它時必須給出完整的名稱.名字不能與包含它的類名相同。 ◇ 可使用包含它的類的靜態和實例成員變量,也可使用它所在方法的局部變量。 ◇ 能夠定義爲abstract。 ◇ 能夠聲明爲private或protected。 ◇ 若被聲明爲static,就變成了頂層類,不能再使用局部變量。 ◇ 若想在Inner Class中聲明任何static成員,則該Inner Class必須聲明爲static。 例3-8】 import java.awt.*; import java.awt.event.*; public class TwoListenInner { private Frame f; private TextField tf; public static void main(String args[]) { TwoListenInner that=new TwoListenInner(); that.go(); } public void go() { f=new Frame("Two listeners example"); f.add("North",new Label("Click and drag the mouse")); tf=new TextField(30); f.add("South",tf); f.addMouseMotionListener(new MouseMotionHandler()); f.addMouseListener(new MouseEventHandler()); f.setSize(300,300); f.setVisible(true); } public class MouseMotionHandler extends MouseMotionAdapter { public void mouseDragged(MouseEvent e){ String s="Mouse dragging:X="+e.getX()+"Y="+e.getY(); tf.setText(s); } } public class MouseEventHandler extends MouseAdapter { public void mouseEntered(MouseEvent e){ String s="The mouse entered"; tf.setText(s); } public void mouseExited(MouseEvent e){ String s="The mouse left the building"; tf.setText(s); } } }
說明:Frame類的add方法來自於其祖先類Container類,addMouseMotionListener和addMouseListener方法來自於其祖先類Component, addMouseListener方法的參數爲MouseListener接口,MouseAdapter類是實現了MouseListener接口的類。可見圖形界面對於外部事件的響應是經過添加listener實現的 2. 匿名類的定義和使用: 匿名類是一種特殊的內部類,它是在一個表達式內部包含一個完整的類定義。經過對例6-7中go()部分語句的修改,咱們能夠看到匿名類的使用狀況。 public void go() { f=new Frame("Two listeners example"); f.add("North",new Label("Click and drag the mouse")); tf=new TextField(30); f.add("South",tf); f.addMouseMotionListener(new MouseMotionHandler(){ /*定義了一個匿名類,類名沒有顯式地給出,只是該類是 MouseMotionHandler類的子類*/ public void mouseDragged(MouseEvent e){ String s="Mouse dragging:X="+e.getX()+"Y ="+e.getY(); tf.setText(s); } }); f.addMouseListener(new MouseEventHandler()); f.setSize(300,300); f.setVisible(true); } 3. 內部類的優缺點: ◇ 優勢:節省編譯後產生的字節碼文件的大小 ◇ 缺點:使程序結構不清楚
習題:
1 :造型不能夠從父類向子類造型,只能從子類向父類造型。不然編譯 時能夠經過,執行時會報錯
如:SubClass sc = new SubClass(); BaseClass bc = (BaseClass)sc ;---是正確的
而 BaseClass bc = new BaseClass(); SubClass sc = (SubClass)bc ;---是錯誤的
BaseClass bc = new SubClass()也是正確的,而且在調用bc中的方法時執行的方法體是子類的方法體,但該方法必須同時在子類,父類中同時存在,若子類中有,而父類中沒有,則不能夠這樣調用bc.subMethod();
若兩個類都繼承於同一個類(必須是直接繼承,不然不對),則這兩個類能夠互相賦值,如:Panel和Frame 同繼承於Container,因此Panel p = new Frame() ;和Frame f = new Panel()都是正確的, java 轉自:http://publishblog.blogchina.com/blog/tb.b?diaryID=4634513編程 |