面向對象(下)


1、繼承

一、概念:把多個類中相同的屬性和行爲進行向上抽取獲得另外一個類,以後定義這些類的時候就再也不用定義這些相同的屬性和行爲,只要讓這些類繼承抽取出來的類便可。這樣一來,這具備相同屬性和行爲的類稱爲子類,抽取出來的是父類,二者之間的關係叫作繼承。例如:要定義一個描述貓的類,首先定義一個動物類,讓後讓貓類繼承動物類,因此貓的描述類就是子類,動物類就是父類。Java中的繼承用extends來表示,格式爲——class 子類 extends 父類。
二、特色:
    1)提升了代碼的複用性。
    2)讓類與類之間產生了關係,有了繼承關係,纔有了多態的特性。
    3)java 語言中java 只支持單繼承,不支持多繼承(由於多繼承容易帶來安全隱患)。
    4)java 支持多層繼承,也就是一個繼承體系。
    5)父類的私有成員不能被子類繼承;父類的構造方法不能被繼承(也就是子類能夠繼承父類中非私有成員)。
    繼承關係出現以後,由於父類中定義的是子類所共有的東西,因此要使用繼承體系中的一個功能,就要查閱父類功能,建立子類對象使用功能。而繼承體系中的子父類的成員也具備必定的特色,能夠從類中的變量、函數、構造函數分析。
三、變量
    若是子類中出現非私有的同名成員變量時,子類要訪問本類中的變量,用 this;子類要訪問父類中的同名變量,用 super。
    1)super 的使用和 this 的使用幾乎一致,this 表明的是本類對象的引用,super 表明的是父類存儲空間。
    2)在子類方法中使用一個變量時:(就近原則)首先,在方法的局部變量中找這個變量,有則使用。不然,在本類中找成員變量,有則使用。不然,在父類中找成員變量,有則使用,不然,報錯。
四、函數 
    1)當子類出現和父類如出一轍的函數時,若子類對象調用該函數,會運行子類函數,如同父類的函數被覆蓋(重寫)同樣。
    2)當子類繼承父類,沿襲了父類的功能,到子類中,可是子類雖具有該功能,可是功能的內容卻和父類不一致,這時,沒有必要定義新功能,而是使用覆蓋特殊,保留父類的功能定義,並重寫功能內容。
Note:
   用子類對象使用一個方法時。首先,在子類中找這個方法,有則使用。不然,在父類中找這個方法,有則使用。不然,報錯。
五、構造函數
    1)在對子類對象進行初始化時,父類的構造函數也會運行,那是由於子類的構造函數默認第一行有一條隱式的語句 super();
    2)super();會訪問父類中空參數的構造函數。並且子類中全部的構造函數默認第一行都是 super();
Note:
    子類的全部構造函數,默認都會訪問父類中空參數的構造函數。由於子類每個構造函數內的第一行都有一句隱式super();當父類中沒有空參數的構造函數時,子類必須手動經過supe語句或者this語句形式來指定要訪問的構造函數。固然子類的構造函數第一行也能夠手動指定this語句來訪問本類中的構造函數。子類中至少會有一個構造函數會訪問父類中的構造函數。
六、final關鍵字
    繼承的出現,打破了對象的封裝性,使得子類能夠隨意複寫父類中的功能。這也是繼承的一大弊端。那麼怎麼解決這個問題呢?這裏就引出了一個新的關鍵字——final(最終)。
final做爲一個修飾符。具備如下特色:
    1)能夠修飾類、函數、變量。
    2)被final修飾的類不能夠被繼承。這樣就能夠避免被繼承、被子類複寫功能。
    3)被final修飾的方法不能夠被複寫。
    4)被final修飾的變量是一個常量只能賦值一次,既能夠修飾成員變量,又能夠修飾局部變量。
    當在描述事物時,一些數據的出現值是固定的,那麼這時爲了加強閱讀性,都給這些值起個名字。方便於閱讀。而這個值不須要改變,因此加上final修飾。做爲常量:常量的書寫規範全部字母都大寫,若是由多個單詞組成,單詞間經過「_」鏈接。
    5)內部類定義在類中的局部位置上時,只能訪問該局部被final修飾的局部變量。
Note:
    1)final不能修飾構造函數。
    2)static final 用來修飾成員變量和成員方法,可簡單理解爲「全局量」。對於變量,表示一旦給值就不可修改,而且經過類名能夠訪問。對於方法,表示不可覆蓋,而且能夠經過類名直接訪問。
2、抽象類(abstract關鍵字)
一、定義:當多個類中出現相同功能,可是功能主體不一樣,這時能夠進行向上抽取。這時,只抽取功能定義,而不抽取功能主體。
二、特色:
    1)抽象方法必定在抽象類中。
    2)抽象方法和抽象類都必須被abstract關鍵字修飾。
    3)抽象類不能夠用new建立對象。由於調用抽象方法沒意義。
    4)抽象類中的抽象方法要被使用,必須由子類複寫其全部的抽象方法後,創建子類對象調用。若是子類只覆蓋了部分抽象方法,那麼該子類仍是一個抽象類。
    說了這麼多,下面用一個實例來講明抽象類的使用: java

/*
假如咱們在開發一個系統時須要對員工進行建模,員工包含 3 個屬性:
姓名、工號以及工資。經理也是員工,除了含有員工的屬性外,另爲還有一個
獎金屬性。請使用繼承的思想設計出員工類和經理類。要求類中提供必要的方
法進行屬性訪問。

員工類:name id pay
經理類:繼承了員工,並有本身特有的bonus。
*/
//員工類,也是父類
abstract class Employee
{
	private String name;//姓名
	private String id;  //工號
	private double pay; //工資
	
	//自定義構造函數初始化
	Employee(String name,String id,double pay)
	{
		this.name = name;
		this.id = id;
		this.pay = pay;
	}
	
	public abstract void work();//抽象的工做方法

}

//經理類,繼承員工類
class Manager extends Employee
{
	private int bonus;//特有的獎金屬性
	Manager(String name,String id,double pay,int bonus)//子類的構造方法
	{
		super(name,id,pay);//調用超類中的構造器
		this.bonus = bonus;
	}
	public void work()//經理類的工做方法內容
	{
		System.out.println("manager work");
	}
}

//普通員工類,繼承員工類
class Commoner extends Employee
{
	Commoner (String name,String id,double pay)
	{
		super(name,id,pay);
	}
	public void work()//普通員工類的工做方法內容
	{
		System.out.println("commoner work");
	}
}

class  AbstractDemo 
{
	public static void main(String[] args) 
	{
		new Manager("manager","007",10000,2000).work();
		new Commoner("commoner","012",5000).work();
	}
}

三、抽象類與通常類的區別:
    1)抽象類和通常類沒有太大的不一樣。只是要描述的事物中出現了一些不知道具體內容的方法部分。這些不肯定的部分,也是該事物的功能,須要明確出來,可是沒法定義主體,因此經過抽象方法來表示。
    2)抽象類比通常類多了個抽象函數,就是在類中能夠定義抽象方法。
    3)抽象類不能夠實例化。
    4)抽象類雖然不能建立對象,可是也有構造函數,供子類實例化調用。

Note:abstract 不能與 private、static、final 等同時修飾一個成員方法,由於:
        final:被 final 修飾的類不能有子類。而被 abstract 修飾的類必定是一個父類。
        private:  抽象類中的私有的抽象方法,不被子類所知,就沒法被複寫。而抽象方法出現的就是須要被複寫。
        
static:若是 static 能夠修飾抽象方法,那麼連對象都省了,直接類名調用就能夠了,但是抽象方法運行沒意義。
3、接口
一、概述:初期理解,能夠認爲是一個特殊的抽象類當抽象類中的方法都是抽象的,那麼該類能夠經過接口的形式來表示。class用於定義類,interface 用於定義接口。
二、格式特色:
    1)接口中常見定義:常量,抽象方法。
    2)接口中的成員都有固定修飾符(接口中的成員都是public)。
      常量:public static final
      方法:public abstract 
Note:
    1)與類相同,接口也是一種數據類型。接口中的方法所有都是抽象方法。
    2)使用關鍵字 interface
    3)接口中的成員變量:一概用公共的、靜態的、最終的,相應關鍵字能夠省略不寫。
    4)成員變量至關於已被修飾爲常量,必須在聲明的時候賦值
    5)接口中的成員方法:一概用公共的、抽象的,相應關鍵字能夠省略不寫。
    6)接口並無繼承 Object 類,全部的接口都默認具有 Object 中的方法的抽象形式,以備給子類使用。
    接口是不能夠建立對象的,由於有抽象方法。須要被子類實現,子類對接口中的抽象方法全都覆蓋後,子類才能夠實例化。不然子類是一個抽象類。接口能夠被類多實現,也是對多繼承不支持的轉換形式。java支持多實現。
三、接口的特色與相關說明
1)特色:
    a)接口是對外暴露的規則,下降了耦合性,緊密聯繫在一塊兒。
    b)接口是程序的功能擴展
    c)接口能夠用來多實現(類與接口的關係是實現關係,類能夠繼承一個類的同時實現多個接口)
    d)java 中只有接口與接口之間存在多繼承。
2)相關說明:
    a)若是一個類在實現接口時沒有實現其中的所有抽象方法,那麼這個類就是抽象類,必須用 abstract 關鍵字聲明。
    b)實現接口中的方法時應注意:接口中的抽象方法都是默認的 public 公共的,所以在實現接口的類中,重寫接口的方法必須明確寫出 pubilc 修飾符。這是由於繼承關係中不容許縮小訪問權限範圍。
    c)類能夠在使用 extends 繼承某一父類的同時使用 implements 實現接口。
    d)類能夠實現多個接口,用逗號將各接口名稱分開便可。
    e)接口之間用 extends 實現繼承關係。子接口無條件繼承父接口全部內容。 
四、接口與抽象類的比較:
1)共性:都是不斷向上抽取出來的抽象的概念。
2)區別:
    a)抽象類體現繼承關係,一個類只能單繼承。
       接口體現實現關係,一個類能夠多實現。同時接口與接口之間有繼承關係。
    b)抽象類是繼承,是 "is a "關係。
       接口是實現,是 "like a"關係。|
    c)抽象類中能夠定義非抽象方法,供子類直接使用。
       接口的方法都是抽象,接口中的成員都有固定修飾符。
    d)抽象類中能夠私有變量或方法。
       接口中的常量和方法都是public修飾的權限。
如下演示接口的使用及相關特色:
安全

interface Inter
{
	public static final int NUM = 3;
	public abstract void show();
}

interface InterA
{
	public abstract void show();
}

class Demo
{
	public void function(){}
}

class Test extends Demo implements Inter,InterA
{
	public void show(){}
}


interface A
{
	void methodA();
}
interface B //extends A
{
	void methodB();
}

interface C extends B,A //接口與接口之間存在多繼承
{
	void methodC();
}

class D implements C
{
	public void methodA(){}
	public void methodC(){}
	public void methodB(){}
}

class InterfaceDemo 
{
	public static void main(String[] args) 
	{
		Test t = new Test();
		System.out.println(t.NUM);
		System.out.println(Test.NUM);
		System.out.println(Inter.NUM);

	}
}
       結果以下所示:

4、多態
一、概述:
    定義:多態能夠理解爲事物存在(具有)的多種體現形態。
    體現:父類的引用指向了本身的子類對象。父類的引用也能夠接收本身的子類對象。
    前提:類與類之間必須有關係,繼承、實現(接口);必須存在覆蓋(或複寫) 
    好處:多態的出現大大的提升了程序的擴展性。
    弊端:雖然提升了擴展性,但只能使用父類的引用,去訪問父類中的成員。
二、在多態中成員的特色:
a)(非靜態)成員函數:
    在編譯時期:參閱引用型變量所屬的類中是否有調用的方法。若是有,編譯經過,若是沒有編譯失敗。
    在運行時期:參閱對象所屬的類中是否有調用的方法。
Note:成員函數在多態調用時,編譯看左邊,運行看右邊。
b)成員變量:不管編譯和運行,都參考左邊(引用型變量所屬的類)。
c)(靜態)成員函數:不管編譯和運行,都參考左邊。
三、類型轉換
    多態中每每是父類引用指向子類對象,這樣就會出現類型的轉換。
    向上轉型(類型提高,轉成父類型):子類對象——>父類對象(程序會自動完成)
       格式:父類  父類對象  =  子類實例;
    向下轉型:父類對象——>子類對象
       格式:子類  子類對象=(子類)父類實例;
Note:發生向下轉型關係以前必須先發生向上轉型關係;對於向下轉型時,必須明確的指明要轉型的子類類型。此處要想知道類的類型用instanceof關鍵字判斷。
四、instanceof:
用於判斷某個對象是不是某種類型。 
格式:對象名  instanceof  子類(實現)名
      對象  intanceof  類型(類類型  接口類型)       <前提是子類對象是有限的>
多態是自繼承後類的又一大特性,而且使用時每每涉及到方法重載和方法覆蓋,此處也做出一些比較。
五、方法重載與方法覆蓋
方法重載與方法覆蓋均是實現多態的機制。
重載方法必須知足的條件:     
    1)方法名必須相同
    2)方法的參數列表必須不相同
    3)方法的返回類型能夠不相同
    4)方法的修飾符能夠不相同
    5)方法重載能夠在同一個類內部進行,也能夠在子類裏對父類的方法進行重載。
方法覆蓋必須知足的條件:
    1)子類方法的名稱及參數表必須與所覆蓋的方法相同
    2)子類方法的返回類型必須與所覆蓋方法相同
    3)子類方法不能縮小所覆蓋方法的訪問權限
    4)子類方法不能拋出比所覆蓋方法更多的異常
    5)方法覆蓋限於子類對父類方法進行,不能在同一個類內部完成。
說了多態這麼多的特色的使用,一下用代碼演示:
ide

/*
 * 貓和狗都屬於動物,使用多態完成貓和狗各自的動做
 */
abstract class Animal {
	abstract void eat();

	abstract void method();
}

class Cat extends Animal {

	@Override
	public void eat() {
		System.out.println("Cat eat");
	}

	@Override
	public void method() {
		System.out.println("吃魚");
	}

	public void catchMouse() {
		System.out.println("抓老鼠");
	}
}

class Dog extends Animal {

	@Override
	public void eat() {
		System.out.println("Dog eat");
	}

	@Override
	public void method() {
		System.out.println("啃骨頭");
	}

	public void lookHome() {
		System.out.println("看家");
	}
}

public class DuotaiDemo {

	public static void main(String[] args) {
		Animal animal = new Cat();
		animal.eat();
		if (animal instanceof Dog) {
			Dog dog = (Dog) animal;
			dog.lookHome();
		} else if (animal instanceof Cat) {
			Cat cat = (Cat) animal;
			cat.catchMouse();
		}
		Animal animal2 = new Dog();
		animal2.eat();
		Dog dog = (Dog) animal2;
		dog.lookHome();
	}

}
        結果以下所示:

    本篇幅所描述的僅表明我的見解,若有出入請諒解。 函數

相關文章
相關標籤/搜索