第四章 面向對象(下)
第四講
面向對象(下)
類的繼承
● 通過繼承可以簡化類的定義
● Java只支持單繼承,不允許多重繼承。
● 可以有多層繼承,即一個類可以繼承某一個類的子類,如類B繼承了類A,類C又可以繼承類B,那么類C也間接繼承了類A。
● 子類繼承父類所有的成員變量和成員方法,但不繼承父類的構造方法。在子類的構造方法中可使用語句super(參數列表)調用父類的構造方法。
● 如果子類的構造方法中沒有顯式地調用父類的構造方法,也沒有使用this關鍵字調用重載的其它構造方法,則在產生子類的實例對象時,系統默認調用父類無參數的構造方法。
class Person
{
private String name="unknown";
private int age=0;
public Person()
{
}
public Person(String name,int age)
{
this.name=name;
this.age=age;
}
void getInfo()
{
System.out.println("姓名:"+name+"\n"+"年齡:"+age);
}
}
class Student extends Person
{
String school="unknown";
public Student()
{
//super();
super("張三",18);
}
}
class TestStudent
{
public static void main(String[]args)
{
Student st=new Student();
st.school="小學";
System.out.println("學校:"+st.school);
st.getInfo();
st.school="中學";
System.out.println("學校:"+st.school);
new Person("李四",20).getInfo();
}
}
運行結果:
學校:小學
姓名:張三
年齡:18
學校:中學
姓名:李四
年齡:20
子類對象的實例化過程
● 分配成員變量的存儲空間并進行默認的初始化,就是用new關鍵字產生對象后,對類中的成員變量按第三章的表3.1中的對應關系對對象中的成員變量進行初始化賦值。
● 綁定構造方法參數,就是new Person(實際參數列表)中所傳遞進的參數賦值給構造方法中的形式參數變量。
● 如有this()調用,則調用相應的重載構造方法(被調用的重載構造方法雙從步驟2開始執行這些流程),被調用的重載構造方法的執行流程結束后,回到當前構造方法,當前構造方法直跳轉到步驟6執行。
● 顯式或隱式追溯調用父類的構造方法(一直到Object類為止,Object是所有Java類的最頂層父類,在本章后面部分有詳細講解),父類的構造方法雙從步驟2開始對父類執行這些流程,父類的構造方法的執行流程結束后,回到當前構造方法,當前構造方法繼續往下執行。
● 進行實例變量的顯式初始化操作,也就是執行在定義成員變量時就對其進行賦值的語句。、
● 執行當前構造方法的方法體中的程序代碼
class Person
{
public String name="unknown";
public int age=0;
public Person()
{
}
public Person(String name,int age)
{
this.name=name;
this.age=age;
}
void getInfo()
{
System.out.println("姓名:"+name+"\n"+"年齡:"+age);
}
}
class Student extends Person
{
String school="unknown";
public Student()
{
//super();
super("張三",18);
}
public Student(String name,int age)
{
super(name,age);
}
public Student(String name,int age,String school)
{
//super(name,age);
this(name,age);
this.school=school;
}
public void getInfo()
{
System.out.println("姓名:"+name+" 年齡:"+age+" 學校:"+school);
}
}
class TestStudent
{
public static void main(String[]args)
{
new Student().getInfo();
Student st=new Student("李四",16);
st.getInfo();
new Student("王二麻子",21,"清華").getInfo();
}
}
運行結果:
姓名:張三 年齡:18 學校:unknown
姓名:李四 年齡:16 學校:unknown
姓名:王二麻子 年齡:21 學校:清華
注意看下面代碼的粗體部分及運行結果:
class Person
{
public String name="unknown";
public int age=0;
public Person()
{
}
public Person(String name,int age)
{
this.name=name;
this.age=age;
}
void getInfo()
{
System.out.println("姓名:"+name+"\n"+"年齡:"+age);
}
}
class Student extends Person
{
String school="unknown";
public Student()
{
//super();
super("張三",18);
}
/*public Student(String name,int age)
{
super(name,age);
}*/
public Student(String name,int age,String school)
{
super(name,age);
//this(name,age);
this.school=school;
}
public void getInfo()
{
System.out.println("姓名:"+name+" 年齡:"+age+" 學校:"+school);
}
}
class TestStudent
{
public static void main(String[]args)
{
new Student().getInfo();
Student st=new Student("李四",16);
st.getInfo();
new Student("王二麻子",21,"清華").getInfo();
}
}
姓名:張三 年齡:18 學校:unknown
姓名:unknown 年齡:0 學校:unknown
姓名:王二麻子 年齡:21 學校:清華
注意:super()和this()調用語句不能同時在一個構造函數中出現。super()和this()調用語句只能作為構造函數中的第一句出現。
覆蓋父類的方法
● 覆蓋方法必須和被覆蓋的方法具有相同的方法名稱,參數列表和返回值類型。
● 如果在子類中想調用父類中的那個被覆蓋的方法,我們可以用super.方法的格式。
● 覆蓋方法時,不能使用比父類中被覆蓋的方法更嚴格的訪問權限。
class Person
{
public String name="unknown";
public int age=-1;
public Person()
{
}
public Person(String name,int age)
{
this.name=name;
this.age=age;
}
public void getInfo()
{
System.out.println("name="+name+",age="+age);
}
}
class Student extend Person
{
public String school="unknown";
public Student()
{
//super();
super("wangwu",18);
}
public Student(String name,int age)
{
super(name,age);
}
public Student(String name,int age,String school)
{
//super(name,age);
this(name,age);
this.school=school;
}
public void getInfo()
{
System.out.print(/*"name="+name+",age="+age+*/"school="+school);
super.getInfo();//調用父類的成員方法
}
public void study()
{
}
}
class TestStudent
{
public static void main(String[]args)
{
Student st=new Student("zhangsan",18,"大學");
/*st.name="zhangsan";
st.age=20;*/
st.getInfo();
}
}
Final關鍵字
● 在Java中聲明類、屬性和方法時,可使用關鍵字final來修飾。
● final標記的類不能被繼承。
● final標記的方法不能被子類重寫。
● final標記的變量(成員變量或局部變量)即成為常量,只能賦值一次。
● 方法中定義的內置類只能訪問該方法內的final類型的局部變量,用final定義的局部變量相當于是一個常量,它的生命周期超出方法運行的生命周期,將一個形參定義成final也是可以的,這就限定了我們在方法中修改形式參數的值。
● public static final共同標記常量時,這個常量就成了全局的常量。
抽象類
java中可以定義一些不含方法體的方法,它的方法體的實現交給該類的子類根據自己的情況實現,這樣的方法就是抽象方法,包含抽象方法的類就叫抽象類。
● 抽象類必須用abstract關鍵字來修飾;抽象方法也必須用abstract來修飾。
● 抽象類不能被實例化,也就是不能用new關鍵字去產生對象。
● 抽象方法只需聲明,而不需實現。
● 含有抽象方法的類必須被聲明為抽象類,抽象類的子類必須覆蓋所有的抽象方法后才能被實例化,否則這個子類還是個抽象類。
接口(interface)
如果一個抽象類中的所有方法都是抽象的,我們就可以將這個類用另外一種方式來定義,就是接口的定義。接口是抽象方法和常量值的定義的集合,從本質上講,接口是一種特殊的抽象類,這種抽象類中只包含常量和方法的定義,而沒有變量和方法的實現。
● 接口中的成員都是public訪問類型的,接口里的變量默認是用public static final標識的。
● 我們可以定義一個新的接口用extends關鍵字去繼承一個已有的接口
● 我們也可以定義一個類用implements關鍵字去實現一個接口中的所有方法,我們還可以定義一個抽象類用implements關鍵字去實現一個接口中定義的部分方法。
● 一個類可以繼承一個父類的同時,實現一個或多個接口,extends關鍵字必須位于implements關鍵字的之前。
interface Runner
{
/*public static final*/ int ID=05;
void run();
}
interface Animal extends Runner
{
public void breathe();//必須為public類型,以下如同
}
abstract class LandAnimal implements Animal
{
public void breathe()
{
System.out.println("LandAnimal ......");
}
}
class Fish implements Animal
{
public void run()
{
System.out.println("The fish jogs the way is the swimming");
}
public void breathe()
{
System.out.println("The fish breath way is the bubbling");
}
}
class TestAnimal
{
public static void main(String[]args)
{
Fish f=new Fish();
f.run();
f.breathe();
int j=0;
//f.ID=2;無法為最終變量 ID 指定值
System.out.println(f.ID);
System.out.println(Fish.ID);
//LandAnimal la=new LandAnimal(); LandAnimal 是抽象的;無法對其進行實例化
}
}
對象的類型轉換
● 子類對象可以自動轉換成父類
● 父類轉換成子類必須使用強制轉換
● instanceof操作符可以用來判斷一個實例對象是否屬于一個類。
class A
{
public void func1()
{
System.out.println("A fun1 is calling");
}
public void func2()
{
func1();
}
}
class B extends A
{
public void func1()
{
System.out.println("B func1 is calling");
}
public void func3()
{
System.out.println("B func3 is calling");
}
}
class C
{
public static void main(String[]args)
{
B b=new B();
callA(b);
A a=b;
callA(new A());
}
public static void callA(A a)
{
if(a instanceof B)//如果a是B類的一個實例對象
{
B b=(B)a;
b.func1();
b.func2();
b.func3();
}
else
{
a.func1();
a.func2();
}
}
}
● Object類及equals方法
class Student
{
String name;
int age;
public Student(String name,int age)
{
this.name=name;
this.age=age;
}
public boolean equals(Object obj)
{
Student st=null;
if(obj instanceof Student)
{
st=(Student)obj;
if(st.name==name && st.age==age)
return true;
else
return false;
}
else
return false;
}
public static void main(String[]args)
{
Student stud1=new Student("zhangsan",20);
Student stud2=new Student("zhangsan",18);
if(stud1.equals(stud2))
System.out.println("equals");
else
System.out.println("not equals");
}
}
接口實例:
interface PCI
{
void start();
void stop();
}
class SoundCard implements PCI
{
public void start()
{
System.out.println("hollo");
}
public void stop()
{
System.out.println("ByeBye");
}
}
class NetWork implements PCI
{
public void start()
{
System.out.println("send...");
}
public void stop()
{
System.out.println("stop...");
}
}
class MainBoard
{
public void usePCICard(PCI p)
{
p.start();
p.stop();
}
}
class Assembler
{
public static void main(String[]args)
{
MainBoard mb=new MainBoard();
NetWork nw=new NetWork();
SoundCard sc=new SoundCard();
mb.usePCICard(nw);
mb.usePCICard(sc);
}
}
匿名內置類
interface PCI
{
void start();
void stop();
}
class SoundCard implements PCI
{
public void start()
{
System.out.println("hollo");
}
public void stop()
{
System.out.println("ByeBye");
}
}
class NetWork implements PCI
{
public void start()
{
System.out.println("send...");
}
public void stop()
{
System.out.println("stop...");
}
}
class MainBoard
{
public void usePCICard(PCI p)
{
p.start();
p.stop();
}
}
class Assembler
{
public static void main(String[]args)
{
MainBoard mb=new MainBoard();
NetWork nw=new NetWork();
SoundCard sc=new SoundCard();
mb.usePCICard(nw);
mb.usePCICard(sc);
mb.usePCICard(new PCI()
{
public void start()
{
System.out.println("test start");
}
public void stop()
{
System.out.println("test stop");
}
});
}
}
異常
● 異常定義了程序中遇到的非致命的錯誤,而不是編譯時的語法錯誤,如程序要打開一個不存在的文件、網絡連接中斷、操作數越界、裝載一個不存在的類等。
● try,catch語句
● throws關鍵字
● 自定義異常與throw關鍵字
● 如何對多個異常作出處理
● 我們可以在一個方法中使用throw,try…catch語句業實現程序的跳轉
● 一個方法被覆蓋時,覆蓋它的方法必須扔出相同的異常或異常的子類。
● 如果父類扔出多個異常,那么重寫(覆蓋)方法必須扔出那些異常的一個子集,也就是說不能扔出新的異常
class Test
{
public int devide(int x,int y) throws DevideByMinusException,ArithmeticException
{
if(y<0)
throw new DevideByMinusException("devide is "+y);
return x/y;
}
//以下是實現程序的跳轉功能。
/*void fun()
{
try
{
if(x==0)
throw new XxxException("xxx");
else
throw new YxxException("yyy");
......
}
catch(XxxException e)
{
}
catch(YyyException e)
{
......
}
}*/
}
class DevideByMinusException extends Exception
{
public DevideByMinusException(String msg)
{
super(msg);
}
}
class TestException
{
public static void main(String[]args)
{
Test tt=new Test();
try
{
tt.devide(4,0);
}
catch(ArithmeticException e)
{
System.out.println("Program is running into Arithmetic");
e.printStackTrace();
}
catch(DevideByMinusException e)
{
System.out.println("Program is running into DevideByMinusException");
e.printStackTrace();
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
finally
{
System.out.println("finally");
}
System.out.println("The program is running here.");
}
}
訪問控制
類本身也有訪問控制,即在定義類的class關鍵字前加上訪問控制符,但類本身只有兩種訪問控制,即public和默認,父類不能是private和protected,否則子類無法繼承。Public修飾的類能被所有的類訪問,默認修飾(即class關鍵字前沒有訪問控制符)的類,只能被同一包中的所有類訪問。
posted on 2007-06-07 23:35 大頭劍客 閱讀(367) 評論(0) 編輯 收藏 所屬分類: 學習筆記