Java---接口、繼承與多態

目錄

 

一、類的繼承

二、Object類

1. getclass()方法

2. toString()方法

3. equals()方法

三、對象類型的轉換

四、使用instanceof操作符判斷對象類型

五、方法的重載

定義不定長參數方法

六、多態

七、抽象類與接口

1、抽象類

2. 接口

3. 接口與繼承


一、類的繼承

在subroutine.java中:

class Parent{
	Parent(){
		System.out.println("調用父類的Parent()構造方法");
	}
}

class SubParent extends Parent{
	SubParent(){
		System.out.println("調用子類的subParent()構造方法");
	}
}

public class subroutine extends SubParent {
	subroutine(){
		System.out.println("調用子類的subroutine()構造方法");
	}
	public static void main(String[] args) {
		subroutine obj = new subroutine();
	}
}

運行結果爲:

在實例化子類對象時,父類無參構造方法將被自動調用,但又參構造方法不能被自動調用。只能依賴於super關鍵字顯式調用父類的構造方法。創建一個子類對象,將包含一個父類子對象。當實例化子類對象時,父類對象也相應被實例化。


(以下具體代碼)

class text{
	text(){
		System.out.println("call the constructor of text()");
	}
	public void doSomething() {
		System.out.println("doSomething");
	}
	protected text dolt() {
		return new text();
	}
}
public class text2 extends text{
	text2(){
		super();
		System.out.println("call the constructor of text2()");
	}
	public void doSomething() {
		System.out.println("doSomething in class text2");
	}
	public void doNew() {
		System.out.println("doNew here");
	}
	protected text2 dolt() {
		return new text2();
	}
	
	public static void main(String[] args) {
		text2 obj = new text2();
		obj.doSomething();  //執行text2類中的方法
		obj.doNew();
		obj.dolt();   //執行text2類中的方法
	}

}

結果爲:

call the constructor of text() 創建父類對象
call the constructor of text2() 創建子類對象
doSomething in class text2 調用text2中的重寫方法
doNew here 調用text2中新添加的方法
call the constructor of text() 調用text2中的dolt()方法,創建對象,先創建一個父類對象
call the constructor of text2() 再創建一個子類對象

1. super關鍵字:

可以在子類的構造方法中調用super()語句調用父類的構造方法;也可以在子類中使用super關鍵字調用父類的成員方法(僅public、protected)。

2. 重寫(覆蓋)父類的成員方法:

將父類成員方法的名稱保留,                  

1)重寫成員方法的實現內容  
2)更改成員方法的存儲權限: 只能從小範圍改到大範圍
3)修改成員方法的返回類型: 遵循:重寫的返回值類型必須是父類該方法的返回值類型的子類

重寫方法的調用:

   
1)用實例化對象是調用不到父類的 在內存中仍爲子類對象  
2)只能用super關鍵字

1)且只能在類方法中調用

2)在main(類外部)是調用不到的

 
  (最初overrride的設計意圖之一)  
class Father{
	Father(){}
	public void doSth() {
		System.out.println("doFather");
	}
}
public class overrideDemo extends Father {
	overrideDemo(){}
	public void doSth() {
		System.out.println("doOverride");
	}
	public void callFatherdoSth() {
		super.doSth();               //用super關鍵字在子類類方法中調用父類重寫方法
	}
	
	public static void main(String[] args) {
		overrideDemo obj = new overrideDemo();
		obj.doSth();                 //調用子類方法
		obj.callFatherdoSth();       //通過子類中的方法,調用父類重寫方法
                                             //不是用實例化對象調用的
                                             //子類方法中用super關鍵字調用了重寫方法
	}

}

結果爲:

如果要調用父類的重寫方法,就在子類中加一個方法,該方法用super關鍵字調用父類重寫方法。若多重繼承,也可以這樣調用,在每個子類中都加上這樣的方法就可以了。

如果要調用

3. 重構:

子類與父類的成員方法:返回值相同、方法名稱相同、參數類型及個數相同;僅方法實現內容不同。

二、Object類

在Java中,所有類都直接或間接繼承了java.lang.Object類。Object類是所有類的父類,是java類層中最高層類。

1)在Object類中主要包括equals()、toString()、clone()、finalize()等方法。由於所有類都是Object類的子類,所以任何類都可以重寫Object類中的方法。

2)Object類中的getClass()、notify()、notifyAll()、wait()等方法不能被重寫,因爲這些方法被定義爲final類型。

1. getclass()方法

返回對象執行時的Class,然後使用此實例調用getName()方法,可以獲得類的名稱。還可與toString()方法聯合使用

2. toString()方法

將一個對象返回爲欸字符串形式,返回類型爲String,返回一個String實例。實際中通常根據需要重寫toString方法。

當對象轉換爲欸字符串或與字符串連接時,將自動調用重寫的toString()方法。

public class ObjectInstance{
    public String toString(){        //toString()返回一個String實例
        return "在" + getClass().getName() + "類中重寫toString()方法";
    }

    public static void main(String[] args){
        ObjectInstance obj = new ObjectInstance();
        System.out.println(obj);        //自動調用重寫的toString()方法
    }
}    //輸出爲:“在ObjectInstance類中重寫toString()方法”

3. equals()方法

“==”比較的時兩個引用是否相等,而equals()方法比較的是實際內容。

而在比較兩個自定義類的實例化對象時,因爲equals()方法的默認實現是使用“==”運算符比較兩個對象的引用地址,而不是比較對象的內容,因此通常需要在自定義類中重寫equals()方法。

class V_one{
	public String name;
	V_one(){}
	V_one(String str){name = str;}
}

class V_two{
	public String name;
	V_two(){}
	V_two(String str){name = str;}
	
	public Boolean equals(V_two v) {
		return name.equals(v.name);
	}
}
public class OverWriteEquals {
	public static void main(String[] args) {
		String str1 = new String("123");
		String str2 = new String("123");
		
		V_one one1 = new V_one("ab");
		V_one one2 = new V_one("ab");
		
		V_two two1 = new V_two("cd");
		V_two two2 = new V_two("cd");
		
		System.out.println(str1.equals(str2));    //true
		System.out.println(one1.equals(one2));    //false
		System.out.println(two1.equals(two2));    //true,因爲調用了重寫的equals()方法
	}
}

三、對象類型的轉換

向上轉型(將子類對象視爲父類對象,自動)。子類對象都可以被看作是一個父類對象。

向下轉型,往往會報錯,要顯式類型轉換。在執行向下轉型操作時,如果父類對象不是子類對象的實例,就會發生ClassCastException異常。

四、使用instanceof操作符判斷對象類型

就像上面說的,此時,就要在執行向下轉型之前,要習慣判斷父類對象是否爲子類對象的實例。

可以使用instanceof操作符判斷是否一個類實現了某個接口(接口在後文),也可以用它來判斷一個實例對象是否屬於一個類。

myobject instanceof ExampleClass

myobject:某類的對象引用

ExampleClass:某個類

返回值爲布爾值

class AA{
    //……
}
class BB extends AA{
    //……
}
class CC{
    //……
}
public class DD extends AA{
    public static voiid main(String[] args){
        AA a = new AA();

        if(a instanceof DD){
            DD d = (DD)a;    //向下轉型操作
        }
        if(a instanceof BB){
            BB b = (BB)a;    //向下轉型操作
        }
        if(a instanceof CC){    //實例對象a不屬於CC類
            //……
        }
    }
}

五、方法的重載

方法的重載在就是在同一個類中允許同時存在一個以上的同名方法,只要這些方法的參數個數或類型不同即可。但只有返回類型不同也不行,還需要通過參數以及參數的類型來設置。(常規略)

定義不定長參數方法

不定長方法語法:

返回值 方法名(參數數據類型 ...參數名稱)    //3個英文句號
public class UncertainLengthAdd {
	public static int add(int...a) {
		int sum = 0;
		for(int i=0;i<a.length;i++) {
			sum += a[i];
		}
		return sum;
	}
	public static void main(String[] args) {
		System.out.println(add(1,2,3));    //6
		System.out.println(add(1,2,3,4,5,6));    //21
	}
}

六、多態

如果定義一個四邊形類,讓它處理所有繼承該類的對象,根據”向上轉型“原則可以使每個繼承四邊形類的對象作爲draw()方法的參數,然後再draw()方法中作一些限定就可以根據不同圖形類對象繪製相應的圖形,從而以更爲通用的四邊形類來取代具體的正方形類和平行四邊形類。這樣處理就能夠很好地解決代碼冗餘的問題,同時也易於維護。使得無需在所有子類中定義執行相同功能的方法。

在多態機制中,並不需要將弗雷初始化對象,需要的只是子類對象。會把子類對象都向上轉型爲父類對象來調用父類方法。

創建Quadrangle類,再分別創建兩個內部類Square和Parallelogramgle,它們都繼承了Quadrangle類。編寫draw()方法,該方法接受Quadrangle類的對象作爲參數,即使用這兩個內部類的父類作爲方法參數。在住方法中分別以兩個內部類的實例對象作爲參數執行draw()方法。

//定義一個正方形類,繼承四邊形類
class Square extends Quadrangle{
	public Square() {
		System.out.println("正方形");
	}
}
//定義一個平行四邊形類,繼承四邊形類
class Parallelogramgle extends Quadrangle{
	public Parallelogramgle() {
		System.out.println("平行四邊形");
	}
}
public class Quadrangle {
	//實例化保存四邊形對象的數組對象
	private Quadrangle[] qtest = new Quadrangle[6];
	private int nextIndex = 0;
	public void draw(Quadrangle q) {
		if(nextIndex<qtest.length) {
			qtest[nextIndex] = q;
			System.out.println(nextIndex);
			nextIndex++;
		}
	}
	public static void main(String[] args) {
		//實例化兩個四邊形對象,用於調用draw()方法
			Quadrangle q = new Quadrangle();
			q.draw(new Square()); 		//以正方形對象爲參數調用draw()方法
			q.draw(new Parallelogramgle());		//以平行四邊形對象爲參數調用draw()方法
	}
}

結果爲:

七、抽象類與接口

1、抽象類

一般將父類定義爲抽象類,需要使用這個父類進行繼承與多態處理。在多態機制中,並不需要將父類初始化對象,需要的只是子類對象。所以java中,抽象類不可以實例化對象,其子類可以。

抽象類語法:------抽象類關鍵字abstract

public abstract class Test{
    abstract void testAbstract();    //定義抽象方法
}

1、使用absract關鍵自定義的類稱爲抽象類,使用這個關鍵字定義的方法稱爲抽象方法。

2、抽象方法沒有方法體。抽象方法只能定義在抽象類中。

3、承載抽象方法的抽象類必須被繼承。

4、繼承抽象類的所有子類必須重寫抽象類中的所有抽象方法。保證相同的方法名稱、參數列表和相同返回值類型。子類可以創建出非抽象方法,或者抽象方法。

---->當子類中的一部分需要一個方法,而另一部分不需要這一方法時(如果在父類抽象類中定義該方法,那麼不需要這個方法的子類也必須重寫該方法)

---->解決方法:接口

2. 接口

1、接口是抽象類的延伸,可看作純粹的抽象類。

2、接口中所有方法都沒有方法體。

3、可將上述(一部分子類需要一部分不需要的)方法封裝到一個接口中,使需要這些方法的那一部分類實現該接口,同時所有類都繼承父類抽象類。

4、接口使用interface關鍵字進行定義:

public interface drawTest{
    void draw();    //接口內的方法,省略abstract關鍵字
}

5、一個類實現一個接口可以使用implements關鍵字:

public class 子類名 extends 父類抽象類名 implements 接口名{
    ……//
}

6、在接口中定義的方法必須被定義爲 public 或 abstract 形式,其他修飾權限不被java編譯器認可。即使不將該方法聲明爲public形式,它也是public。

7、在接口中定義的任何字段都自動是 static 和 final 的。

3. 接口與繼承

Java中不允許多重繼承,即不允許一個子類同時繼承一個或多個父類(即同時extends多個類)。

實現方法:使用接口可以實現多重繼承(即可以同時implements多個接口,同時實現多個接口)。

多重繼承語法:

class 類名 implements 接口1,接口2,...,接口n 

在定義一個接口時使該接口繼承另外一個接口:

interface intf1{
    ...//
}
interface intf2 extends intf1{
    ...//
}

1、一個類只能繼承一個類:class A extends B{}

2、一個類可以實現多個接口:class A implements B,C,...{}

3、一個接口可以繼承多個接口:interface intf1 extends intf2,intf3,...{}

4、在繼承類的同時也可以繼承接口:class A extends B implements intf1,intf2,...{}

這就是選擇用接口而不選擇抽象類的原因。

(具體代碼示例:)

interface drawTest{		//定義接口
	public void draw();		//定義方法,沒有方法體
}
class ParallelogramgleUseInterface extends QuadrangleUseInterface implements drawTest{
	public void draw() {		//因爲該類實現了接口,所以需要覆蓋draw()方法
		System.out.println("平行四邊形.draw()");
	}
	public void doAnything() {		//覆蓋父類方法
		//……
	}
}
class SquareUseInterface extends QuadrangleUseInterface implements drawTest{
	public void draw() {
		System.out.println("正方形.draw()");
	}
	public void doAnything() {
			//……	
	}
}
public class QuadrangleUseInterface {
	public void doAnything() {
		//……
	}
	public static void main(String[] args) {
		//接口也可以進行向上轉型操作
		drawTest[] d = {new SquareUseInterface(), new ParallelogramgleUseInterface()};
		for(int i=0;i<d.length;i++) {
			d[i].draw();		//調用draw()方法
		}
	}
}

 

結果爲:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章