java抽象類,接口(接口定義,實現接口,instanceof運算符,對象轉換)


抽象類

  在面向對象的概念中,所有的對象都是通過類來表述的,但並不是所有的類都能夠完整的描繪對象,如果一個類中沒有包含足夠的信息來描繪一類具體的對象,這樣的類就是抽象類.抽象類往往用來表征對問題領域進行分析,設計中的出的抽象概念.  是對一系列看上去不同,但本質上相同的具體概念的抽象.例如:定義一個平面圖形Shape . 任何平面圖形都有周長和面積,在Shape類中定義兩個方法用於計算圖形的面積和周長

  

public class Shape{
    //計算圓的面積
    public void callArea(){}    
    //計算圓的周長
    public void callPerimeter(){}
}

   通過分析,可以發現平面圖形領域存在着園,三角形,長方形等這樣一些具體的圖形,計算它們的面積和周長是不同的,因此在Shape類中無法統一定義callArea()和callPerimeter()方法 , 但是它們都屬於平面領域,都需要這兩個方法.

  有事定義類的"骨架",對其共同行為提供規范,但並不實現,具體的實現將放在它的子類來完成.這種骨架類在java中叫做 抽象類,通過abstract關鍵字來描述

[訪問符] abstract class 類名{
    [訪問符] abstract <返回類型> 方法名([參數列表]);
}

  定義抽象類需要注意一下幾點:

  1、abstract放在class前面,指明該類是抽象類;

  2、abstract放在方法聲明中,則該方法是抽象方法,抽象方法沒有方法體,即未實現;

  3、一個抽象類可以含有多個抽象方法,也可以含有已經實現的方法;

  例子:抽象類的定義與使用

package 抽象類;
    //定義圖形抽象類
public abstract class Shape {
    double dim;
    public Shape(double dim) {
        this.dim = dim;
    }
    //抽象方法,獲得面積
    public abstract double callArea();
    //抽象方法,獲得周長
    public abstract double callPerimeter();
}

 

   上面的例子是定義了一個抽象類Shape,並且聲明了兩個抽象方法callArea()和callPerimeter(),這兩個抽象方法沒有方法體.在這里需要注意,抽象方法是沒有方法體,它和空方法是兩個不同的概念

    public abstract void callAreas(); //抽象方法,沒有 {}括起來的方法體
    public void callArea() {};  //空方法,有{}括起來的方法體,但方法體中沒有任何語句

  抽象類還可以包含具體數據和具體方法,也可以包括構造方法,定義抽象類的目的是提供可由其子類共享的一般形式,子類可以根據自身需要擴展抽象類

  例子:定義Shape抽象類的一個子類Circle來演示抽象類的使用

package 抽象類;

public class Circle extends Shape{
    public Circle(double dim) {
        super(dim);
    }
    //實現抽象方法callArea();
    public double callArea() {
        //返回圓的面積
        return 3.14 * dim * dim;
    }
    public double callPerimeter() {
        //返回圓的周長
        return 2 * 3.14 * dim;
    }
    public static void main(String args[]) {
        //聲明一個Shape對象,指向實現它的子類對象
        Shape shape = new Circle(10);
        //調用callArea()求出圓的面積並輸出
        System.out.println("圓的面積為:" + shape.callArea());
        //調用callPerimeter()求出圓的周長並輸出
        System.out.println("圓的周長為:" + shape.callPerimeter());
    }
} 

 

   執行結果:

圓的面積為:314.0
圓的周長為:62.800000000000004

  從執行的結果來看,當調用Shape類型的變量shape時,實際上是調用了Circle類型對象的方法,即通過基類調用派生類的方法,這也是一種多態的體現  

  一個類在繼承抽象類時,如果沒有實現所有抽象類方法,那么該類也必須聲明為抽象類:

  例子:

  

package 抽象類;

public abstract class Square extends Shape{
    public Square(double dim) {
        super(dim);
    }
    //實現抽象方法callArea()
    public double callArea() {
        return dim * dim;
    }
    //沒有實現抽象方法callPerimeter(),Square類中仍然包含抽象方法,所以Square依然是抽象類
}

 

  注意:1、抽象類不能實例化,既不能直接new一個抽象類,但可以指向一個實現它的子類對象 

     2、抽象方法沒有方法體,抽象類提供了子類的規范模板,抽象方法必須在子類中給出具體實現。

     3、abstract不能與final同時修飾一個類,abstract不能和static、private、final或者native並列修飾同一方法。

接口 

  java只支持單一繼承,不支持多重繼承,即一個類只能繼承另一個類,不能繼承兩個或兩個以上的類。單一繼承限制了類的多重體現,為了彌補這一缺陷,模仿C++中的多重繼承,java語言的設計者提出了一種折中的解決辦法,即使用接口:一個類可以實現多個接口。接口的引入,使java擁有了強大的面向對象編程能力,為面向接口編程提供了廣泛的擴展空間 。

定義接口

<訪問符> interface 接口名{
    [訪問符] <返回類型> 方法名([參數列表])
    ......
}

 

  1、interface是定義接口的關鍵字;

  2、接口是一種特殊的抽象類型,是對抽象類的進一步強化,是方法聲明和常量的定義集合,因此接口中的方法都沒有方法體,即接口中的方法都是未實現的方法,且不需要abstract關鍵字進行指明

  例子:演示接口的定義和使用

package 接口;

public interface MyInterface {
    public void add(int x, int y);
    public void volume(int x, int y, int z);
}

  上述代碼定義了一個接口MyInterface,在接口 中聲明了兩個方法,但這兩個方法都沒有實現,與抽象類中的抽象方法類似,接口中的方法沒有方法體,當然也可以定義既包含常量也包含方法的接口

package 接口;

public interface MultiInterface {
    //在接口中定義一個靜態常量PI
    public static final double PI = 3.1415926;
    public void callArea();
}

  在定義接口的時候,接口中的所有方法和常量自動定義為public,可以省略public關鍵字.

實現接口

   實現接口的語法格式如下:

<訪問符> class 類名 implements 接口名[接口列表]{
}

 

  1、implement關鍵字可以實現多個接口,接口之間用逗號隔開。

  2、一個類實現接口時,必須實現接口中定義的所有方法,除非將該類定義為抽象類。

  例子:定義一個類Myclass實現MyInterface接口,演示接口的實現過程

package 接口;

public class MyClass implements MyInterface{
    //實現接口中的add()方法
    public void add(int x, int y) {
        System.out.println("x + y = " +(x+y));
    }
    //實現接口中的volume()方法
    public void volume(int x, int y, int z) {
        System.out.println("X * y * z = " + (x*y*z));
    }
    
    public static void main(String args[]) {
        //聲明一個MyInterface對象,指向MyClass類的對象
        MyInterface mi = new MyClass();
        //調用add方法,傳遞兩個參數
        mi.add(1, 2);
        //調用volume()方法,傳遞三個參數
        mi.volume(1, 2, 3);    
    } 
}

  執行結果為:

x + y = 3
X * y * z = 6

  上面代碼中Myclass類實現MyInterface接口 ,並實現該接口中定義的add()和volume()方法.在main()方法中,先聲明一個MyInterface接口類型的變量mi  ,  new一個實現該接口的Myclass類的對象,並將其引用賦值給mi  ,最后通過mi調用方法.

  與抽象類一樣,接口是一種更加虛擬的類結構,因此不能對接口實例化

  接口與抽象類有很多相似之處,但要注意這幾點區別:

  1、抽象類中可以有已經實現的方法,而接口不能有

  2、接口中定義的變量默認為public static final 型,且必須賦初值,其實現類中不能重新定義,也不能改變其值,即接口中定義的變量都是最終的靜態常量;而抽象類中定義的變量 和普通類一樣,默認是friendly,其實現類合一重新定義,也可以根據需要改變其值

  3、接口中定義的方法默認都是public修飾,也只能是public,而抽象類則是缺省的friendly

instanceof運算符

  java的多態性機制導致了引用變量的聲明類型和其實際類型引用的類型可能不一致,在結合動態方法調度到機制可以得出以下結論:聲明為同種類型的兩個引用變量調用同一個方法時也有可能會有不同的行為.為了更准確的鑒別一個對象的真正類型,java語言引入了instanceof操作符.其實使用的格式如下:

<引用類型變量> instanceof <引用類型>

   該表達式為boolean類型的表達式,當instanceof左側的引用類型變量所引用對象的實際類型是其右側給出的類型或其子類類型時,整個表達式的結果為true,否則為false

  舉例:演示instanceof的用法

package instanceof運算符;

//定義IBase接口
public interface IBase {
    public void print();
}
package instanceof運算符;

//定義類Derive類實現IBase接口 
public class Derive implements IBase{
    int b;
    public Derive (int b) {
        this.b = b;
    }
    public void print() {
        System.out.println("In Derive!");
    }
}
package instanceof運算符;

//定義Derive的子類Derive1
public class Derive1 extends Derive{
    int c;
    public Derive1(int b, int c) {
        super(b);
        this.c = c;
    }
    public void print() {
        System.out.println("In Derive1!");
    }
}
package instanceof運算符;

public class InstanceofDemo {
    //判斷對象類型
    public static void typeof(Object obj) {
        if(obj instanceof Derive) {
            Derive derive = (Derive) obj;
            derive.print();
        }else if(obj instanceof Derive1) {
            Derive1 derive1 = (Derive1) obj;
            derive1.print();
        }
    }
    public static void main(String[] args) {
        IBase b1 = new Derive(4);
        IBase b2 = new Derive1(4,5);
        System.out.print("b1 is:");
        //調用typeof()判斷b1
        typeof(b1);
        System.out.print("b2 is:");
        //調用typeof()判斷b2
        typeof(b2);
    }
}

 

  執行結果:

b1 is:In Derive!
b2 is:In Derive1!

 

  上述代碼中定義了一個IBase接口,Derive類實現IBase接口,Derive1是Derive的子類.在InstanceofDemo類中定義了一個靜態方法typeof(),該方法使用instanceof來判斷對象的類型,並調用其相應的方法,main()方法中定義了兩個Base類型的對象分別是b1和b2所引用的實際對象類型.

  從結果不難看出,instanceof運算符能夠鑒別出實際對象類型,並實現相應方法的調用,此種方法模擬了方法的動態調用機制.但這種做法被認為沒有很好的利用面向對象中的多態性而是采用了結構化編程模式

  注意:在大多數情況下不推薦使用此用算符,應當利用累的多態.

 

對象轉換

  在基本數據類型之間進行相互轉換的過程中,有些轉換可以自行完成,而有些轉換必須通過強制轉換,對於引用類型,也從在相互轉換機制,也分為自動轉換和強制轉換

    自動轉換:子類轉換成為父類,或者實現類轉換接口,轉換自動完成

    強制轉換:父類轉換成為子類,或者接口轉換成實現類,必須使用強制轉換.

Person p = new Teacher(); //創建一個Teacher對象,把引用賦予Person類型變量p
Teacher t = (Teacher) p;  //把變量p強制轉換成Teacher類型變量

  注意:無論自動轉換還是強制轉換,都只能用在有繼承關系的對象之間.並不是任意類型都可以轉換,只有多態的情況下,原本就是子類類型的對象被聲明為父類的類型,才可以通過造型恢復其"真實面目",否則將編譯失敗.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM