真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java中的抽象類和接口怎么應(yīng)用

這篇文章主要介紹“Java中的抽象類和接口怎么應(yīng)用”,在日常操作中,相信很多人在Java中的抽象類和接口怎么應(yīng)用問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Java中的抽象類和接口怎么應(yīng)用”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

創(chuàng)新互聯(lián)建站是專業(yè)的華安網(wǎng)站建設(shè)公司,華安接單;提供成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行華安網(wǎng)站開發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!

Java中的抽象類和接口怎么應(yīng)用

什么是抽象類

我們之前學(xué)過什么是類,那么抽象類是不是也是類的一種呢?

聽名字就感覺好抽象呀!說(shuō)對(duì)了,他就是抽象的,不是具體的。在類中沒有包含足夠的信息來(lái)描繪一個(gè)具體的對(duì)象,這樣的類稱為抽象類。

來(lái)看一個(gè)抽象類的例子

// 抽象類和抽象方法需要被 abstract 關(guān)鍵字修飾
abstract class Shape {
    // 抽象類中的方法一般要求都是抽象方法,抽象方法沒有方法體
    abstract void draw();
}

大家覺得這個(gè)抽象類是不是什么也沒干,他唯一的方法draw()還是空的。

像這樣的類是不是就沒有包含足夠的信息來(lái)描繪一個(gè)具體的對(duì)象,自然也就不能實(shí)例化對(duì)象了。不信你看:

Java中的抽象類和接口怎么應(yīng)用

那既然一個(gè)類不能實(shí)例化,那這種抽象類存在的意義是什么?

抽象類在實(shí)現(xiàn)多態(tài)中的意義

抽象類存在的一個(gè)最大意義就是被繼承,當(dāng)被繼承后就可以利用抽象類實(shí)現(xiàn)多態(tài)。

來(lái)看一段代碼

// 抽象類和抽象方法需要被 abstract 關(guān)鍵字修飾
abstract class Shape {
    // 抽象類中的方法一般要求都是抽象方法,抽象方法沒有方法體
    abstract void draw();
}
// 當(dāng)一個(gè)普通類繼承一個(gè)抽象類后,這個(gè)普通類必須重寫抽象類中的方法
class Cycle extends Shape {
    @Override
    void draw() {  // 重寫抽象類中的draw方法
        System.out.println("畫一個(gè)圓圈");
    }
}

public class Test4 {
    public static void main(String[] args) {
        //Shape shape = new Shape();  抽象類雖然不能直接實(shí)例化
        // 但可以把一個(gè)普通類對(duì)象傳給一個(gè)抽象類的引用呀,即父類引用指向子類對(duì)象
        Shape shape = new Cycle(); // 這稱作:向上轉(zhuǎn)型
        
        /*Cycle cycle = new Cycle();
          Shape shape = cycle // 這是向上轉(zhuǎn)型的另一種寫法
         */
        shape.draw();         // 通過父類引用調(diào)用被子類重寫的方法
    }
}

運(yùn)行之后你就會(huì)發(fā)現(xiàn)神奇的一幕:

Java中的抽象類和接口怎么應(yīng)用

大家在看完了代碼可能會(huì)有很多疑問,別急咱們一個(gè)一個(gè)的說(shuō),

什么是向上轉(zhuǎn)型:一句話總結(jié)就是“父類引用指向子類對(duì)象”

向上轉(zhuǎn)型后的變化

  1. 關(guān)于方法:父類引用可以調(diào)用子類和父類公用的方法(如果子類重寫了父類的方法,則調(diào)用子類的方法),但子類特有的方法無(wú)法調(diào)用。

  2. 關(guān)于屬性: 父類引用可以調(diào)用父類的屬性,不可以調(diào)用子類的屬性

向上轉(zhuǎn)型的作用

  1. 減少一些重復(fù)性的代碼

  2. 對(duì)象實(shí)例化的時(shí)候可以根據(jù)不同需求實(shí)例化不同的對(duì)象

這樣的話就我們上面的代碼就可以理解了

Java中的抽象類和接口怎么應(yīng)用

看來(lái),我們可以通過子類對(duì)抽象類的繼承和重寫,抽象類還真有點(diǎn)用呀!

但這和多態(tài)有什么關(guān)系呢,抽象類用起來(lái)這么麻煩,我還不如直接用普通類,也能達(dá)到這樣的效果,還不用再寫一個(gè)子類呢?

那行,你再看看下面的代碼,你就知道抽象類在實(shí)現(xiàn)多態(tài)時(shí)的好處了。

abstract class Shape {
    public abstract void draw(); // 抽象方法不能里有具體的語(yǔ)句
}
// 當(dāng)一個(gè)普通類繼承一個(gè)抽象類的時(shí)候,再這個(gè)子類中必須重寫抽象類中的抽象方法
class Cycle extends Shape {  
    @Override              // 如果不重寫會(huì)報(bào)錯(cuò),但如果繼承的是普通類則不會(huì)報(bào)錯(cuò),用抽象類更安全
    public void draw() {
        System.out.println("畫一個(gè)圓圈");
    }
}
class Flower extends Shape { // 不同的子類對(duì)父類的draw方法進(jìn)行了不同的重寫
    @Override
    public void draw() {
        System.out.println("畫一朵花");
    }
}
class Square extends Shape {
    @Override
    public void draw() {
        System.out.println("畫一個(gè)正方形");
    }
}

public class Test4 {
    public static void main(String[] args) {
        Cycle cycle = new Cycle();   // 子類引用cycle
        Flower flower = new Flower(); // 子類引用flower
        Square square = new Square();
        
        // 數(shù)組的類型是Shape,即數(shù)組中每一個(gè)元素都是一個(gè)父類引用
        // 在這個(gè)過程其實(shí)也發(fā)生了向上轉(zhuǎn)型,對(duì)抽象類中的方法進(jìn)行了重寫
        Shape[] shapes = {cycle, flower, square};  // 父類引用引用不同的子類對(duì)象
        for (int i = 0; i < shapes.length; i++) {
            Shape shape = shapes[i]; // 父類引用shape指向—>當(dāng)前所對(duì)應(yīng)的子類對(duì)象

            shape.draw();  // 通過父類引用調(diào)用子類重寫的draw方法
        }

    }
}

Java中的抽象類和接口怎么應(yīng)用

調(diào)用同一個(gè)方法竟然打印出了不同的結(jié)果,這難道就是所謂的多態(tài)

是不是有點(diǎn)懵,下面我們來(lái)解釋一下

// 對(duì)上面的代碼補(bǔ)充一下
// 可能你對(duì) Shape[] shapes = {cycle, flower, square};不太理解
// 但上面的代碼就相當(dāng)于 

 Shape[] shapes1 = new Shape[3]; // 有三個(gè)不同的子類對(duì)象呀!數(shù)組大小為3

// (將指向->子類對(duì)象)的子類引用賦值給父類對(duì)象,不就相當(dāng)于該夫類引用指向->所對(duì)應(yīng)的子類對(duì)象嗎
//這是向上轉(zhuǎn)型的另一種寫法,應(yīng)為前面已經(jīng)實(shí)例化了子類對(duì)象  Cycle cycle = new Cycle();   
 shapes1[0] = cycle;  // 如果前面沒實(shí)例化子類對(duì)象,就要寫成shape1[0] = new Cycle
 shapes1[1] = flower;
 shapes1[2] = square;

對(duì)于多態(tài)來(lái)說(shuō),他有這三個(gè)要素

  1. 繼承(我們剛才的Cycle類繼承Shape抽象類)

  2. 重寫(我們子類對(duì)draw方法的重寫)

  3. 父類指向子類對(duì)象(就是shape1[0] = cycle -->也可以稱作向上轉(zhuǎn)型)

回頭再看一下我們的代碼,是不是就剛好符合了多態(tài)的三要素。

當(dāng)我們的父類引用指向不同的子類對(duì)象時(shí),當(dāng)我們調(diào)用同一個(gè)draw方法時(shí)卻輸出了不同的結(jié)果。(其實(shí)就是該方法再子類中被重寫成了不同形式)這就叫做多態(tài) 。

嘻嘻,其實(shí)只要只要結(jié)合著例子來(lái)看,多態(tài)也沒那么難理解呀

那為啥一定要用抽象類呢?我一個(gè)普通類繼承普通類來(lái)實(shí)現(xiàn)多態(tài)不可以嗎

當(dāng)然可以,但不太安全有風(fēng)險(xiǎn);

Java中的抽象類和接口怎么應(yīng)用

但如果是抽象類的話,就不一樣了

Java中的抽象類和接口怎么應(yīng)用

從這我們也可以看出,當(dāng)用抽象類的時(shí)候,編譯器自動(dòng)就對(duì)我們是否重寫進(jìn)行了校驗(yàn),而充分利用編譯器的校驗(yàn), 在實(shí)際開發(fā)中是非常有意義的 。所以說(shuō)抽象類還是有用的

好了,相信到這里你對(duì)抽象類也有了一個(gè)大概的認(rèn)識(shí),下面來(lái)簡(jiǎn)單做一下總結(jié)

  1. 使用abstract修飾的類或方法,就抽象類或者抽象方法

  2. 抽象類是不能具體的描述一個(gè)對(duì)象,不能用抽象類直接實(shí)例化對(duì)象

  3. 抽象類里面的成員變量和成員方法,都是和普通類一樣的,只不過就是不能進(jìn)行實(shí)例化了

  4. 當(dāng)一個(gè)普通類繼承這個(gè)抽象類后,那么這個(gè)普通類必須重寫抽象類當(dāng)中的所有的抽象方法(我們之前說(shuō)過抽象類是不具體的,沒有包含足夠的信息來(lái)描述一個(gè)對(duì)象,所以我們需要把他補(bǔ)充完整)


  5. 但當(dāng)一個(gè)抽象類A繼承了抽象類B,這是抽象類A就可以不重寫抽象類B當(dāng)中的抽象方法

  6. final不能修飾抽象類和抽象方法(因?yàn)槌橄箢惔嬖诘淖畲笠饬x就是被繼承,而被final修飾的不能被繼承,final和抽象,他們兩個(gè)是天敵)

  7. 抽象方法不能被private修飾(抽象方法一般都是要被重寫的,你被private修飾了,還怎么重寫)

  8. 抽象類當(dāng)中不一定有抽象方法,但如果一個(gè)類中有抽象方法,那么這個(gè)類一定是抽象類。

接口是什么

抽象類是從多個(gè)類中抽象出來(lái)的模板,如果將這種抽象進(jìn)行的更徹底,則可以提煉出一種更加特殊的“抽象類”——接口(Interface)。

接口是Java中最重要的概念之一,它可以被理解為一種特殊的類,不同的是接口的成員沒有執(zhí)行體,是由全局常量和公共的抽象方法所組成。

如何定義一個(gè)接口呢?下面我們來(lái)看一個(gè)栗子

//接口的定義格式與定義類的格式基本相同,將class關(guān)鍵字換成 interface 關(guān)鍵字,就定義了一個(gè)接口

public interface 接口名稱{
// 定義變量
int a = 10;      // 接口當(dāng)中的成員變量默認(rèn)都是public static final

// 抽象方法
public abstract void method1(); // public abstract 是固定搭配,可以不寫
void method2();  //  接口當(dāng)中的成員方法默認(rèn)都是public abstract, 更推薦用第二種來(lái)定義方法 
}

可以看到接口和類其實(shí)還是有很多相似點(diǎn):

接口中也包含抽象方法,所以也不能直接實(shí)例化接口,那么我們?cè)趺从媒涌谀兀?/p>

哈哈,很簡(jiǎn)單,我們?cè)儆靡粋€(gè)普通類實(shí)現(xiàn)這個(gè)接口不就行了嗎,不同的是抽象類是被子類來(lái)繼承而實(shí)現(xiàn)的,而接口與類之間則是用關(guān)鍵字implements來(lái)實(shí)現(xiàn)。

就像普通類實(shí)現(xiàn)實(shí)現(xiàn)抽象類一樣,一個(gè)類實(shí)現(xiàn)某個(gè)接口則必須實(shí)現(xiàn)該接口中的抽象方法,否則該類必須被定義為抽象類。

通過接口實(shí)現(xiàn)多態(tài)

鐵汁們!剛才我們是用抽象類來(lái)實(shí)現(xiàn)多態(tài),那么現(xiàn)在我們可以嘗試用接口來(lái)實(shí)現(xiàn)多態(tài),

接口可以看成是一種特殊的類,只能用 interface 關(guān)鍵字修飾
interface IShape {
    int a = 10;   接口當(dāng)中的成員變量默認(rèn)都是public static final
    int b = 23;
    void draw();  接口當(dāng)中的成員方法一般只能是抽象方法,默認(rèn)是public abstract(JDK1.8以前)
  
    default void show() {
        System.out.println("接口中的其他方法");//接口中的其他方法也可以實(shí)現(xiàn),但要用default修飾
    }
    public static void test() {
        System.out.println("這是接口當(dāng)中的一個(gè)靜態(tài)的方法");
    }
}

// 一個(gè)普通的類要想實(shí)現(xiàn)接口,可以用implement, 
//因?yàn)榻涌谝彩浅橄蠓椒ǖ?,所以?shí)現(xiàn)接口的這個(gè)類也要重寫抽象方法
class Cycle implements IShape {

    @Override
    public void draw() {
        System.out.println("畫一個(gè)圓圈");
    }
}
class Square implements IShape {
    @Override
    public void draw() {
        System.out.println("畫一個(gè)正方形");
    }
}
class Flower implements IShape {

    @Override
    public void draw() {
        System.out.println("畫一朵花");
    }
}
public class Test4 {
    public static void main(String[] args) {
        // IShape iShape = new IShape(); 接口也不能直接實(shí)例化
        Cycle cycle = new Cycle();
        Square square = new Square();
        Flower flower = new Flower();
        // 這里的IShape接口就相當(dāng)與抽象類中父類,接口類型也是一種引用類型

        IShape[] iShapes = {cycle, square, flower}; // 這個(gè)過程其實(shí)就發(fā)生了向上轉(zhuǎn)型

        for (IShape iShape : iShapes) { // 增強(qiáng)型的for—each循環(huán),也可以寫成普通的for循環(huán)形式
            iShape.draw();              // 通過重寫實(shí)現(xiàn)了多態(tài)
        }
    }
}
引用變量cycle和square都賦值給了Shape類型的引用變量shape,
但當(dāng)執(zhí)行shape.draw()時(shí),java虛擬機(jī)到底要調(diào)用誰(shuí)重寫的的draw方法,
就看此時(shí)接口引用的是那個(gè)對(duì)象的,是shape的、還是cycle的

看一下運(yùn)行結(jié)果

Java中的抽象類和接口怎么應(yīng)用

看完代碼你可能有點(diǎn)暈,但沒關(guān)系。一般接口咱也不這么用,直接使用抽象類不就好了(我只是演示一下用接口也能實(shí)現(xiàn)多態(tài))

下面我們來(lái)總結(jié)一下Java中接口的幾個(gè)主要特點(diǎn)

  1. 接口中可以包含變量和方法,變量被隱式指定為 public static final,方法被隱式指定為 public abstract(JDK 1.8 d一個(gè)類可以同時(shí)實(shí)現(xiàn)多個(gè)接口,一個(gè)類實(shí)現(xiàn)某個(gè)接口則必須實(shí)現(xiàn)該接口中的抽象方法,否則該類必須被定義為抽象類

  2. 接口支持多繼承,即一個(gè)接口可以繼承(extends)多個(gè)接口,間接解決了 Java 中類不能多繼承的問題。

那么接口一般用在什么地方呢?

  • 一般情況下,實(shí)現(xiàn)類和它的抽象類之前具有 "is-a" 的關(guān)系,但是如果我們想達(dá)到同樣的目的,但是又不存在這種關(guān)系時(shí),使用接口。

  • 由于 Java 中單繼承的特性,導(dǎo)致一個(gè)類只能繼承一個(gè)類,但是可以實(shí)現(xiàn)一個(gè)或多個(gè)接口,此時(shí)可以使用接口。

下面就讓我們來(lái)看看接口的正確用法:幫助java實(shí)現(xiàn)“ 多繼承 ”

由于 Java 中單繼承的特性,導(dǎo)致一個(gè)類只能繼承一個(gè)類,但是可以實(shí)現(xiàn)一個(gè)或多個(gè)接口,此時(shí)可以使用接口。
class Animal {
    String name;        // 不能使用private,后面的子類也要用

    public Animal(String name) { // 父類的自定義的構(gòu)造方法
        this.name = name;
    }
}
interface IFlying {   // 自定義多種接口
    void fly();
}
interface IRunning {
    void run();
}
interface ISwimming {
    void swimming();
}
// 小鴨子,不僅會(huì)跑,還會(huì)游泳、飛行
一個(gè)類繼承父類,并實(shí)現(xiàn)多個(gè)接口,間接的解決java中不能多繼承的問題
class Duck extends Animal implements IRunning, ISwimming, IFlying {

    public Duck(String name) {  // 子類構(gòu)造方法
        super(name);            // 必須在子類構(gòu)造方法的第一行
        // 在給實(shí)現(xiàn)子類的構(gòu)造方法前,先要用super()調(diào)用實(shí)現(xiàn)父類的構(gòu)造方法,比較先有父后有子呀!
        // 因?yàn)楦割愖约憾x了構(gòu)造方法,編譯器不會(huì)自動(dòng)給給子類構(gòu)造方法中添加super();來(lái)實(shí)現(xiàn)父類的構(gòu)造方法,需要我們自己實(shí)現(xiàn)
    }
    // 對(duì)接口中的抽象方法進(jìn)行重寫
    @Override
    public void fly() {
        System.out.println(this.name + "正在用翅膀飛");
    }

    @Override
    public void run() {
        System.out.println(this.name + "正在用兩條腿跑");
    }

    @Override
    public void swimming() {
        System.out.println(this.name + "正在漂在水上");
    }

}

public class 接口的使用 {  // 不用學(xué)我用中文名作為類名,我只是為演示方便
    public static void main(String[] args) {
        Duck duck = new Duck("第一個(gè)小鴨子");  // 實(shí)例化鴨子對(duì)象
        duck.fly();  // 通過引用 變量名.方法名 輸出重寫后的方法
        duck.run();
        duck.swimming();
    }
}
有人可能會(huì)說(shuō)干嘛用接口,我直接在父類Animal中實(shí)現(xiàn)fly、run、swimming這些屬性,
然后不同的動(dòng)物子類再繼承父類這些方法不行嗎?

但問題是,鴨子會(huì)fly、swimming,那貓會(huì)飛和游泳嗎?你再寫個(gè)其他動(dòng)物的子類是不是就不行了
而用接口呢?我們只是把這種飛、游泳的行為給抽象出來(lái)了,

只要一個(gè)子類有這種行為,他就可以實(shí)現(xiàn)相對(duì)應(yīng)的接口,接口是更加靈活的

Java中的抽象類和接口怎么應(yīng)用

上面的代碼展示了 Java 面向?qū)ο缶幊讨凶畛R姷挠梅?/strong>: 一個(gè)類繼承一個(gè)父類, 同時(shí)實(shí)現(xiàn)多個(gè)接口。

繼承表達(dá)的含義是 is - a 語(yǔ)義, 而接口表達(dá)的含義是 具有 xxx 特性 ,能實(shí)現(xiàn)接口的類和該接口并不一定有is_a的關(guān)系,只要該類有這個(gè)接口的特性就行

貓是一種動(dòng)物, 具有會(huì)跑的特性.

青蛙也是一種動(dòng)物, 既能跑, 也能游泳

鴨子也是一種動(dòng)物, 既能跑, 也能游, 還能飛

這樣設(shè)計(jì)有什么好處呢? 時(shí)刻牢記多態(tài)的好處, 讓程序猿忘記類型. 有了接口之后, 類的使用者就不必關(guān)注具體類型,只要這個(gè)類有有這個(gè)特性就好。

舉個(gè)栗子

class Robot implements IRunning {
    private String name;
    public Robot(String name) {
        this.name = name;
    }
    // 對(duì)run方法進(jìn)行重寫
    @Override
    public void run() {
        System.out.println("機(jī)器人" + this.name + "正在跑");
    }
}
public class Test4 {
    public static void main(String[] args) {
        Robot robot1 = new Robot("圖圖");
        robot1.run();
    }
}
// 執(zhí)行結(jié)果
機(jī)器人圖圖正在跑

只要能跑就行,管他是機(jī)器人還是動(dòng)物呢

到此,關(guān)于“Java中的抽象類和接口怎么應(yīng)用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!


網(wǎng)頁(yè)名稱:Java中的抽象類和接口怎么應(yīng)用
當(dāng)前URL:http://weahome.cn/article/ieghih.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部