Java面向?qū)ο缶幊獭橄箢惡徒涌?/h2>

Java面向?qū)ο缶幊獭橄箢惡徒涌?/h1>

定義類的過程就是抽象和封裝的過程,而抽象類與接口則是對實(shí)體類進(jìn)行更高層次的抽象,進(jìn)定義公共行為和特征。

抽象類:

如果一個(gè)類沒有足夠的信息去描述一個(gè)具體的對象,那我們就稱之為抽象類。

語法格式:

public abstract class 類名{}

案例代碼:

package Demo01;

/**
 * @version 1.0
 * @author: jiazhihao
 * @date: 2021-05-13 10:31
 */
public class Demo01 {
    // 定義動物抽象類
    public abstract  class Animal{
        
    }
}

抽象方法:

有了抽象類,類中就要有與之對應(yīng)的抽象方法。抽象發(fā)發(fā)就是用abstract修飾的方法,這種方法值聲明返回的數(shù)據(jù)類型,方法名稱和所需要的參數(shù),沒有方法體。也就是說在抽響雷中聲明抽象方法時(shí),值需要聲明方法,不需要定義方法體。子類在繼承父類時(shí),必須重寫父類的抽象方法,這也是抽象方法存在的意義。

語法格式:

public abstract 返回值類型 方法名(參數(shù)列表); 

案例代碼:

package Demo01;

/**
 * @version 1.0
 * @author: jiazhihao
 * @date: 2021-05-13 10:31
 */
public class Demo01 {
    // 定義動物抽象類
    public abstract  class Animal{
    public abstract void go(); //  名為go的抽象方法,注意方法沒有大括號
    }
}

抽象類和抽象方法具體該怎么使用? 抽象方法的作用是 什么?

案例代碼

package Demo01;

/**
 * @version 1.0
 * @author: jiazhihao
 * @date: 2021-05-13 10:31
 */
public class Demo01 {
    // 定義動物抽象類
    public abstract  class Animal{
    public abstract void go(); //  名為go的抽象方法,注意方法沒有大括號
    }

    public class Demo02 extends Demo01 {

        public void go(){
            System.out.println("鳥飛的塊");
        }

    }

    public class Demo03 extends Demo01{
        public void go(){
            System.out.println("狗跑的塊");
        }
    }

    


}

測試類:

package Demo01;

/**
 * @version 1.0
 * @author: jiazhihao
 * @date: 2021-05-13 10:42
 */
public class Demo04 {
    public static void main(String[] args) {
        Demo02 d = new Demo02();
        d.go();
        Demo03 demo03 = new Demo03();
        demo03.go();
    }
}

通過上面的代碼我們可以總結(jié):

定義抽象類就是用于繼承的。和一般類的繼承相比,子類繼承抽象類必然會實(shí)現(xiàn)抽象方法。由于抽象方法都是沒有方法體的,也就是說,抽象方法并沒有寫死,我么可以根據(jù)自己的需求去寫

抽象類是一種模板式設(shè)計(jì),通常是對同類事物相對具體的抽象。抽象類通常包含抽象方法、實(shí)體方法、屬性變量。。我們在使用抽象方法和抽象類時(shí),需要注意以下幾點(diǎn)。

(1)包含抽象方法的類一定時(shí)抽象類。

(2)抽象類中的方法不一定都是抽象方法。抽象類也可以沒有抽象方法

(3)構(gòu)造方法不能聲明為抽象方法

(4)abstract 不能與private 、static、final、native并修飾同一個(gè)方法

final修飾符

使用:

顯示生活中,我們的身份證一經(jīng)確定,身份證號就不能在此修改了。那我們Java中某些數(shù)據(jù)是定值,為了保證計(jì)算的正確性,不能在被修改,應(yīng)該怎末辦呢?這時(shí)候就用到了final修飾符,表示最終的。

final使用有以下幾種情況。

(1)修飾類

(2)修飾方法

(3)修飾對象和變量

修飾類:

  1. 被final修飾過的類不能被繼承

  2. .因?yàn)椴荒鼙焕^承,所以此類中的所有方法默認(rèn)都是final修飾

  3. 該類如果不需要子類,不需要被擴(kuò)展,類中的方法不允許被重寫,就是用final

    修飾方法:

    被final修飾的方法可以被繼承,不能被覆蓋重寫

    修飾對象和變量:

    final修飾一個(gè)對象,那么這個(gè)對象的引用不能變,但是值是可以變的。如果是基礎(chǔ)類型,那么值不可變。

    案例代碼:

    package Demo02;
    
    ;
    
    /**
     * @version 1.0
     * @author: jiazhihao
     * @date: 2021-05-13 10:31
     */
    public class Demo01 {
        public String name;
    
        public Demo01(String name) {
            super();
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Demo01{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    
    
    

    測試類:

    package Demo02;
    
    /**
     * @version 1.0
     * @author: jiazhihao
     * @date: 2021-05-13 10:31
     */
    public class Demo02 {
        public static void main(String[] args) {
            // final 修飾的是李斯特這個(gè)對象
            final Demo01 list  = new Demo01("李四");
            // 李四對象中name 屬性并沒有被final修飾
            list.setName("張三");
            //最終輸出內(nèi)容:Demo01{name='張三'}
            System.out.println(list.toString());
        }
    }
    
    

接口

在生活中,接口時(shí)一套規(guī)范,滿足這個(gè)規(guī)范的設(shè)備,就可以組裝在一起。

接口就像插座一樣,一種插孔可以插很多種電器,這個(gè)插孔就是我們像外賣呢提供的接口,所有的電器都要實(shí)現(xiàn)這個(gè)接口

為什么需要接口?

和抽象類對同類事物進(jìn)行抽象不同,接口不是類,而是一組對類的需求描述(可以看成只有抽象方法的抽象類)。這要求接口采用鍥約式、開放式對需求進(jìn)行設(shè)計(jì),這樣才能滿足不同事物的相同要求。

接口的使用

在軟件中,接口同樣是一種規(guī)范和標(biāo)準(zhǔn),他們可以約束類的行為,是一些方法特征的集合,但沒有方法的實(shí)現(xiàn),需要類對接口進(jìn)行實(shí)現(xiàn)。

Java中接口的定義語法:

[修飾符] interface 接口名 extends 父接口1,父接口2 ..{
    // 常量定義
    // 方法定義
}

類實(shí)現(xiàn)接口的語法如下

class 類名 extends父類名 implement  接口1 ,接口2 ,,,{
    //類成員
}

interface 之中可以定義變量和方法,變量必須是public static final的,方法必須是publicabstract

說明:

(1)接口的命名規(guī)則與類相同。如果修飾符是public,則該接口在整個(gè)項(xiàng)目中可見;如果省略修飾符,則該接口只在當(dāng)前包可見。

(2) 接口中可以定義常量,不能定義變量。接口中的屬性都會自動用public static final 修飾

(3)接口中的所有方法都是抽象方法。接口中方法都會自動用 public abstract修飾,即接口中只有全局抽象方法

(4)和抽象類一樣,接口也不能實(shí)例化,接口中不餓能有構(gòu)造方法

(5)接口之間可以通過extends來實(shí)現(xiàn)繼承關(guān)系,一個(gè)接口可以繼承多個(gè)接口,但接口不能繼承類。

(6)實(shí)現(xiàn)接口的類必須實(shí)現(xiàn)接口的全部方法,否則必須定義為抽象類

(7)一個(gè)類只能有一個(gè)直接父類,但可以通過implements是西安多個(gè)接口。當(dāng)類在繼承父類的同時(shí)有實(shí)現(xiàn)了多個(gè)接口時(shí),extends關(guān)鍵字必須位于implements 關(guān)鍵字之前

案例代碼:

(1)約定Usb接口標(biāo)準(zhǔn)

(2)制作符合Usb接口約定的各種具體設(shè)備

(3)將Usb設(shè)備插到Usb接口上進(jìn)行工作

package Demo03;/**
*@author: jiazhihao
*@date:  2021-05-14 09:08
*@version 1.0
*/public abstract class Demo01 {

    public interface Usb{
        public void run();
    }

    static class UsbPrinter implements Usb{
        @Override
        public void run(){
            System.out.println("Usb連接中,打印機(jī)連接中,開始工作");
        }
    }
    static class UsbMouse implements  Usb{
    @Override
    public void run(){
        System.out.println("Usb 連接中 ,鼠標(biāo)連接中,開始工作");
    }  }
    static class Test{
        public static  void main(String[] args){
            Usb a = new UsbPrinter();
            Usb B = new UsbMouse();

            a.run();
            B.run();
        }
    }
}

接口是一種能力使用

接口是一種能力,一個(gè)類實(shí)現(xiàn)了某個(gè)接口,就表示這個(gè)類具備了某種能力。

案例代碼:

package Demo03;

import org.w3c.dom.ls.LSOutput;

/**
 * @version 1.0
 * @author: jiazhihao
 * @date: 2021-05-14 09:24
 */
public class Demo02 {
    static  public abstract class Venicle {
        public abstract void run();

        public abstract void stop();
    }

    static  interface Lock {
        void lock();

        void open();
    }
      static class Car extends Venicle implements Lock{

        @Override
        public void run() {
            System.out.println("開完鎖,發(fā)動引擎,駕駛員駕駛者汽車開始行駛");

        }

        @Override
        public void stop() {
            System.out.println("駕駛員將發(fā)動機(jī)熄火,準(zhǔn)備鎖上汽車");

        }

        @Override
        public void lock() {
            System.out.println("插進(jìn)鑰匙,向左旋轉(zhuǎn)三圈,拔出鑰匙");

        }

        @Override
        public void open() {
            System.out.println("插進(jìn)鑰匙,向右旋轉(zhuǎn)三圈,所打開了,拔出鑰匙");

        }
    }
}

測試類:

package Demo03;

/**
 * @version 1.0
 * @author: jiazhihao
 * @date: 2021-05-14 09:41
 */
public class TestDemo02 {
    public static  void main(String[] args){
        Demo02.Car  car = new Demo02.Car();

        car.lock();
        car.open();
        car.run();
        car.stop();
    }
}

既然接口代表一種能力,那么我i們在開車和停車的基礎(chǔ)上,擴(kuò)展行車記錄儀記錄功能,需要增加一種能力

代碼:

package Demo03;

/**
 * @version 1.0
 * @author: jiazhihao
 * @date: 2021-05-14 09:24
 */
public class Demo03 {
    static  public abstract class Venicle {
        public abstract void run();

        public abstract void stop();
    }

      interface Lock {
        void lock();

        void open();
    }

    interface TripREC{
        void record();
    }


      static class Car extends Venicle implements Lock{

        @Override
        public void run() {
            System.out.println("開完鎖,發(fā)動引擎,駕駛員駕駛者汽車開始行駛");

        }

        @Override
        public void stop() {
            System.out.println("駕駛員將發(fā)動機(jī)熄火,準(zhǔn)備鎖上汽車");

        }

        @Override
        public void lock() {
            System.out.println("插進(jìn)鑰匙,向左旋轉(zhuǎn)三圈,拔出鑰匙");

        }

        @Override
        public void open() {
            System.out.println("插進(jìn)鑰匙,向右旋轉(zhuǎn)三圈,所打開了,拔出鑰匙");

        }


        public void record(){
            System.out.println("行車記錄儀開始錄像");
        }
    }
}

測試類:

package Demo03;

/**
 * @version 1.0
 * @author: jiazhihao
 * @date: 2021-05-14 09:41
 */
public class TestDemo03 {
    public static  void main(String[] args){
        Demo03.Car  car = new Demo03.Car();

        car.lock();
        car.open();
        car.run();
        car.stop();
        car.record();
    }
}

從結(jié)果中可以看出:

接口在代碼的擴(kuò)展和維護(hù)方面十分方柏霓。接口類似于一個(gè)組件,需要時(shí)可以自由組裝。從使用角度來講,接口和抽象類的區(qū)別在于:抽象類利于代碼復(fù)用,接口利于代碼維護(hù)

接口是一種約定

接口其實(shí)就是一種約定,實(shí)現(xiàn)接口的類就必須遵守這個(gè)接口的約定

Java8中接口的變化

在 JDK 8及以后,允許我們在接口中定義static方法和default方法,這兩種方法可以有方法體

  1. default方法屬于實(shí)例,static方法屬于接口或類。要注意的是 default方法可以被繼承,static方法不能被繼承

  2. 如果一個(gè)類實(shí)現(xiàn)了多個(gè)接口,并且這些接口之間沒有相互繼承關(guān)系,同時(shí)存在相同的default方法時(shí)會報(bào)錯(cuò),不過可以在實(shí)現(xiàn)類中重寫default方法并通過“<接口>.super.<方法名>();"
    靜態(tài)方法:

    在接口中增加靜態(tài)方法。理論上講。沒有任何理由認(rèn)為這是不合法的。只是這有違將接口作為抽象規(guī)范的初衷

    案例代碼:

package Demo04;

/**
 * @version 1.0
 * @author: jiazhihao
 * @date: 2021-05-14 10:02
 */
public class Demo01 {
    public static void main(String[] args) {
                //靜態(tài)方法不會被繼承
        TestInter.staticMethh();
        TestInter2.staticMethh2();
        
    }
}

interface TestInter{
    static void staticMethh(){
        System.out.println("TestInter中的靜態(tài)方法");
    }
}
interface TestInter2{
    static void staticMethh2(){
        System.out.println("TestInter2中的靜態(tài)方法");
    }
}

默認(rèn)方法:

default關(guān)鍵字修飾接口的方法,使其稱為默認(rèn)方法。目的時(shí)減少子類實(shí)現(xiàn)接口的工作量。

案例代碼:

先看沒有使用默認(rèn)方法的方式:

package Demo04;

/**
 * @version 1.0
 * @author: jiazhihao
 * @date: 2021-05-14 10:18
 */
public class Demo02 {
    public interface Log {
        void login(String name);
    }

    class Emp implements Log{
        @Override
        public void login(String name){
            System.out.println("用戶"+name+":登陸系統(tǒng)");
        }

    }
    class Student implements  Log{
        @Override
        public void login(String name){
            System.out.println("用戶"+name+";登陸系統(tǒng)");
        }
    }
}

再看使用默認(rèn)方法之后的代碼:

package Demo04;

/**
 * @version 1.0
 * @author: jiazhihao
 * @date: 2021-05-14 10:21
 */
public class Demo03 {
    public interface Log{
        default  void login(String name){
            System.out.println("用戶"+name+":登陸系統(tǒng)");
        }
    }

    static class Emp implements Log{}
    static class Student implements Log{}
    static class DefaultMethodTest{
        public static void main(String[] args) {
            Emp emp = new Emp();
            emp.login("張三");
            Student student = new Student();
            student.login("李四");
        }
    }
}

結(jié)論:

如果多個(gè)子類實(shí)現(xiàn)某個(gè)接口方法,方法體都是一樣的,這就導(dǎo)致后期維護(hù)上的困難,如果在接口中定義了默認(rèn)的實(shí)現(xiàn),那么即減少了子類實(shí)現(xiàn)的接口的工作量,也為后期的維護(hù)提供了方便(只需要更改接口中的默認(rèn)實(shí)現(xiàn)即可)

總結(jié)

面向接口編程可以實(shí)現(xiàn)接口和現(xiàn)實(shí)的分離,這樣做最大的好處就是能夠在客戶端位置的情況下修改是西安代碼,那么怎樣抽象出接口呢?一種時(shí)用在層與層的調(diào)用。層與層之間最機(jī)會耦合度過高或修改過于頻繁。設(shè)計(jì)優(yōu)秀的接口能夠解決這個(gè)問題,

另一種時(shí)是使用在那些不穩(wěn)定的部分上。如果某些需求的變化性很大,那么定義接口也是一種解決方法,設(shè)計(jì)良好的接口就像日常使用的萬能插座,不論插頭如何變化,都可以使用

當(dāng)糾結(jié)定義接口還是抽象類時(shí),優(yōu)先推薦定義為接口,遵循接口隔離原則,按某個(gè)維度劃分成多個(gè)接口,然后在用抽象類去是實(shí)現(xiàn)某些接口,這樣做可方柏霓后續(xù)的擴(kuò)展和重構(gòu)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容