第5章 訊息、繼承與多型
一.訊息
在物件之間的聯絡是通過訊息來傳遞的
訊息應該含有:物件名、方法名、實際引數、返回值或操作結果
共有訊息和私有訊息
特定於物件的訊息可以分為以下三種類型:可以返回物件內部狀態的訊息,可以改變物件內部狀態的訊息,可以做一些特性操作改變系統狀態的訊息。
class Student{ public String name; public char sex; public int no; public int age; Student(int cno,String cname,char csex,int cage){ name=cname; sex=csex; no=cno; age=cage; } public void showNo(){ System.out.println("No:"+no); } public void showName(){ System.out.println("Name:"+name); } public void showSex(){ System.out.println("Sex:"+sex); } public void showAge(){ System.out.println("Age:"+age); } } class StudentScore{ private int no; private double score; public void sendScore(int cno,double cscore){ no=cno; score=cscore; } void printScore(){ System.out.println("No:"+no+" score:"+score); } } public class C5_1 { public staticvoid main(String[] args){ int m; Student st1=new Student(101,"Zhang li",'F',18); Student st2=new Student(102,"hong bing",'M',17); StudentScore sc1=new StudentScore(); StudentScore sc2=new StudentScore(); st1.showNo(); st1.showName(); st1.showAge(); st1.age=20; m=st1.age; System.out.println("m="+m); st2.showNo(); st2.showName(); sc1.sendScore(101,97); sc2.sendScore(102,84); sc1.printScore(); sc2.printScore(); } }
非訪問控制
類:final,obstract
資料成員:final,static
二.訪問控制
1.公共訪問控制符public
import這個public類就能訪問這個類內部可見的資料成員和引用它的可見方法,只有當public類的資料成員和成員方法的訪問控制符也被宣告為public時,這個類的所有用public修飾的資料承運和成員方法才同時對其它類可見。但是安全性下降。
2.預設訪問控制符
預設訪問控制特性稱為“友好訪問”,只有在同一個包中的物件才能訪問和引用這些類。
同一個包中用private修飾的父類的資料成員不能被子類的例項物件引用
class P1{ private int n=9; int nn; P1(){ nn=n++; } void ma(){ System.out.println("n="+n); } } public class C5_3 extends P1 { public static void main(String[] args){ P1 m1=new P1(); System.out.println("m1.nn="+m1.nn); //System.out.println("m1.n="+m1.n);這計劃是錯誤的,不能呼叫private m1.ma(); } }
當父類的資料成員用protected修飾時,不能被其他包的例項物件訪問
三.多型機制
1.Java提供兩種多型機制,過載與覆蓋
同命不同參的成員方法->不同響應
2.過載
主要通過形式引數列表中引數的個數,引數的資料型別和引數的順序等方面的不同來區分
過載方法區別:引數個數、引數順序、引數型別
編譯器根據實際引數選擇並執行對應的過載方法
public class C5_5{ static int add(int a,int b){ return a+b; } static double add(double x,double y){ return x+y; } static double add(double x,double y,double z){ return x+y+z; } public static void main(String[] args){ System.out.println("Sum is:"+add(8.5,2.3)); System.out.println("Sum is:"+add(21,35)); System.out.println("Sum is:"+add(8.5,2.3,8.5+2.3)); } }
四.繼承機制
1.繼承的概念
把一般類的物件例項和所有特殊類的物件例項都共同具有的屬性和操作一次性的在一般類中進行顯式定義,在特殊類中不再重複的定義一般類中已經定義的東西,但是在語義上,特殊類自動的銀行的擁有他的一般類中定義的屬性和操作。
2.繼承的特性
(1)關係是傳遞的
(2)能清晰地體現相關類間的層次結構關係
(3)提供軟體複用功能
(4)減少介面和介面
(5)提供多繼承,Java僅僅支援單繼承,二通過介面機制實現多繼承
3.Java用extends指明繼承關係
繼承機制通過extends關鍵字實現,新定義的子類可以繼承父類的所有非private屬性和方法
(1)資料成員的繼承:子類可以繼承父類的所有非私有的資料成員
class A1{ int x=25; private int z; } public class C5_6 extends A1{ public static void main(String[] args){ C5_6 p=new C5_6(); System.out.println("p.x="+p.x); } }
(2)資料成員的隱蔽
資料成員的隱蔽是指子類中重新定義一個與父類中已定義的資料成員名完全相同的資料成員
class A11{ int x=8; } public class C5_7 extends A11 { int x=24; public static void main(String[] args){ int s1,s2; A11 p=new A11(); C5_7 p1=new C5_7(); s1=p.x; s2=p1.x; System.out.println("s1="+s1); System.out.println("s2="+s2); } }
(3)成員方法的繼承
子類可以繼承父類的非私有成員方法
class A2{ int x=0,y=1; void Myp(){ System.out.println("x="+x+" y="+y); } private void Printme(){ System.out.println("x="+x+" y="+y); } } public class C5_8 extends A2{ public static void main(String[] args){ int z=3; C5_8 p1=new C5_8(); p1.Myp(); //p1.Printme();錯的,無法呼叫private型別方法 } }
(4)成員方法的覆蓋
方法的覆蓋與資料成員的隱藏的不同之處在於:子類隱藏父類的資料成員使其不可見,父類同名的資料成員在子類物件中仍然站有自己獨立的記憶體空間,子類方法對父類同名方法的覆蓋將清除父類方法佔用的記憶體,從而使父類方法在子類物件中不復存在。
class A3{ int x=10; int y=31; public void Printme(){ System.out.println("x="+x+" y="+y); } } public class C5_9 extends A3{ int z=35; public void Printme(){ System.out.println("z="+z); } public static void main(String[] args){ A3 p2=new A3(); C5_9 p1=new C5_9(); p1.Printme(); p2.Printme(); } }
子類再重新定義父類已有方法的時候,應保持與父類完全相同的方法名,返回值型別和引數列表,否則就不是方法覆蓋,而是子類定義自己特有的方法,與父類方法無關。
4.this與super
this使用場合
用來訪問當前物件的資料成員:this.資料成員
用來訪問當前物件的成員方法:this.成員方法(引數)
當有過載的構造方法時,用來引用同類的其他構造方法:this(引數)
this的使用
class A4{ int x=0; int y=1; public void Printme(){ System.out.println("x="+x+" y="+y); System.out.println("I am an "+this.getClass().getName()); } } public class C5_10 extends A4{ public static void main(String args[]){ C5_10 p1=new C5_10(); p1.Printme(); } }
當類的資料成員名和成員方法的形參名相同時,藉助this來表示引用的是類資料成員
class AlassArea{ double x,y; double area(double x,double y){ double s; this.x=x; this.y=y; s=this.x*this.y; return s; } } public class C5_11 extends AlassArea{ public static void main(String[] args){ double a=2.2,b=3.1,z; C5_11 ss=new C5_11(); z=ss.area(a,b); System.out.println("z="+z); } }
super的使用場合
表示的是當前物件的直接父類物件,是當前物件的直接父類物件的引用。
使用方法:
(1)用來訪問直接父類隱藏的資料成員:super.資料成員
(2)用來呼叫直接父類中被覆蓋的成員方法:super.成員方法(引數)
(3)用來呼叫直接父類的構造方法:super(引數)
class A5{ int x=4; int y=1; public void printme(){ System.out.println("x="+x+" y="+y); System.out.println("class name: "+this.getClass().getName()); } } public class C5_13 extends A5 { int x; public void printme(){ int z=super.x+6; super.printme(); System.out.println("I am an "+this.getClass().getName()); x=5; System.out.println("z="+z+" x="+x); } public static void main(String[] args){ int k; A5 p1=new A5(); C5_13 p2=new C5_13(); p1.printme(); p2.printme(); } }
5.構造方法的過載與繼承
過載:這個呼叫語句應該是整個構造方法的第一條可執行語句
class Addclass{ public int x=0,y=0,z=0; Addclass(int x){ this.x=x; } Addclass(int x,int y){ this(x); this.y=y; } Addclass(int x,int y,int z){ this(x,y); this.z=z; } public int add(){ return x+y+z; } } public class C5_14 { public static void main(String[] args){ Addclass p1=new Addclass(2,3,5); Addclass p2=new Addclass(10,20); Addclass p3=new Addclass(1); System.out.println("x+y+z="+p1.add()); System.out.println("x+y="+p2.add()); System.out.println("x="+p3.add()); } }
繼承:
子類無條件地繼承父類的不含引數的構造方法
如果子類自己沒有構造方法,則它將繼承父類的無引數構造方法。如果子類自己定義了構造方法,則在建立新物件時,他將限制性繼承自弗雷德無引數構造方法,然後再執行自己的構造方法
對於父類的含引數構造方法,子類是可以通過在自己的構造方法中使用super關鍵字呼叫它,但是這個呼叫語句必須是子類構造方法的第一條可執行語句
class Addclass2{ public int x=0,y=0,z=0; Addclass2(int x){ this.x=x; } Addclass2(int x,int y){ this.x=x; this.y=y; } Addclass2(int x,int y,int z){ this.x=x; this.y=y; this.z=z; } public int add(){ return x+y+z; } } public class C5_15 extends Addclass2{ int a=0,b=0,c=0; C5_15(int x){ super(x); a=x+7; } C5_15(int x,int y){ super(x,y); a=x+5; b=y+7; } C5_15(int x,int y,int z){ super(x,y,z); a=x+4; b=y+4; c=z+4; } public int add(){ System.out.println("super:x+y+z="+super.add()); return a+b+c; } public static void main(String[] args){ C5_15 p1=new C5_15(2,3,5); C5_15 p2=new C5_15(10,20); C5_15 p3=new C5_15(1); System.out.println("a+b+c="+p1.add()); System.out.println("a+b="+p2.add()); System.out.println("a="+p3.add()); } }
6.向方法傳遞物件
傳遞給方法的引數若是變數,則只能有實參傳遞給形參,而不能有形參帶回
在引用過程中,對於形參變數值的修改並不影響實參變數值
傳遞給方法的引數若是物件,則是參與形參的物件的引用指向同一個變數,因此成員方法中對物件的資料成員的修改,會使實參物件的資料成員之也發生同樣的變化
這種引數的傳遞方式被稱為雙向地址傳遞
7.繼承與封裝的關係
繼承是一種靜態共享程式碼的手段
封裝機制所提供的是一種動態共享程式碼的手段,通過封裝到一個類,建立該類的例項,同樣也能達到共享的目的
五.抽象類、介面與包
1.抽象類
是所有子類公共屬性特徵的集合
在抽象類派生的子類中必須實現抽象類中定義的所有抽象方法
(1)凡是用abstract修飾符修飾的類被稱為抽象類。凡是用abstract修飾符修飾的成員方法被稱為抽象方法
(2)抽象類中可以有0個或多個抽象方法,也可以包含非抽象的方法
(3)抽象類中可以沒有抽象方法,但是,由抽象方法的類必須是抽象類
(4)對於抽象方法來說,在抽象類中只指定其方法名及其型別,而不書寫其實現程式碼
(5)抽象類可以派生子類,在抽象類派生的子類中必須實現抽象類中定義的所有抽象方法
(6)抽象類不能建立物件,建立物件的工作由抽象類派生的子類來實現
(7)如果父類中已經有同名的abstract方法,則子類中就不能再用同名的抽象方法
(8)abstract不能與final並列修飾同一個類
(9)abstract不能與private、static、final或native並列修飾同一個方法
2.介面
多重繼承是指一個子類可以有多個直接父類,該子類可以全部或部分繼承所有直接父類的資料成員及成員方法。
[修飾符]interface 介面名[extends 父介面名列表] { 常量資料成員宣告 抽象方法宣告 }
interface是宣告介面的關鍵字,可以把它看成一個特殊類
介面名要求符合Java識別符號規定
修飾符有兩種:public和預設
父介面名列表。定義一個介面時可以通過extends關鍵字宣告該介面是某個已經存在的父介面的派生介面,他將繼承父介面的所有屬性和方法
常量資料成員執勤可以有也可以沒有修飾符,是public static和final static,介面中的資料成員都是用final修飾的常量:修飾符 資料成員型別 資料成員名=常量值 或 資料成員名=常量值
抽象方法宣告,介面中的方法都是用abstract修飾的抽象方法
定義介面注意事項:
介面定義用關鍵字interface而不是class
介面中定義的資料成員全是final static修飾的,即常量
介面中沒有自身的構造方法,所有成員方法都是抽象方法
介面也具有繼承性,可以通過extends關鍵字宣告該介面的父介面
類實現介面的注意事項
用implements關鍵字就可以呼叫介面,一個類若要呼叫多個介面,可在implements後用逗號隔開多個介面的名字
如果實現某介面的類不是abstract的抽象類,則在類的定義部分必須實現指定介面的所有抽象方法
如果實現某介面的類是abstract的抽象類,則它可以不實現該介面所有的方法
介面的抽象方法的訪問限制符都已指定為public,所以類在實現方法時,必須顯式地使用publilc修飾符,否則將被系統警告為縮小了介面中定義的方法的訪問控制訪問