溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何理解Java編程接口

發(fā)布時間:2021-10-08 09:08:49 來源:億速云 閱讀:121 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容介紹了“如何理解Java編程接口”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

目錄
  • 一、抽象類和抽象方法

  • 二、接口

  • 三、Java中的多重繼承

  • 四、通過繼承來擴(kuò)展接口

    • 1、組合接口時的名字沖突

  • 五、適配接口

    • 六、接口中的域

      • 七、嵌套接口

        • 1.類中的接口

        • 2.接口中的接口

      • 八、接口與工廠

        一、抽象類和抽象方法

        抽象:從具體事物抽出、概括出它們共同的方面、本質(zhì)屬性與關(guān)系等,而將個別的、非本質(zhì)的方面、屬性與關(guān)系舍棄,這種思維過程,稱為抽象。

        這句話概括了抽象的概念,而在Java中,你可以只給出方法的定義不去實(shí)現(xiàn)方法的具體事物,由子類去根據(jù)具體需求來具體實(shí)現(xiàn)。

        抽象類除了包含抽象方法外,還可以包含具體的變量和具體的方法。類即使不包含抽象方法,也可以被聲明為抽象類,防止被實(shí)例化。

        抽象類不能被實(shí)例化,也就是不能使用new關(guān)鍵字來得到一個抽象類的實(shí)例,抽象方法必須在子類中被實(shí)現(xiàn)。

        抽象類總結(jié)規(guī)定:

        1. 抽象類不能被實(shí)例化,如果被實(shí)例化,就會報錯,編譯無法通過。只有抽象類的非抽象子類可以創(chuàng)建對象。

        2. 抽象類中不一定包含抽象方法,但是有抽象方法的類必定是抽象類。

        3. 抽象類中的抽象方法只是聲明,不包含方法體,就是不給出方法的具體實(shí)現(xiàn)也就是方法的具體功能。

        4. 構(gòu)造方法,類方法(用 static 修飾的方法)不能聲明為抽象方法。

        5. 抽象類的子類必須給出抽象類中的抽象方法的具體實(shí)現(xiàn),除非該子類也是抽象類。

        二、接口

        interface關(guān)鍵字使得抽象的概念更加向前邁進(jìn)了一步,abstract關(guān)鍵字允許人們在類中創(chuàng)建一個或多個沒有任何定義的方法---提供了接口部分。但是沒有提供任何相應(yīng)的具體實(shí)現(xiàn),這些實(shí)現(xiàn)是由此類的繼承者實(shí)現(xiàn)的。

        在抽象類中,可以包含一個或多個抽象方法;但在接口(interface)中,所有的方法必須都是抽象的,不能有方法體,它比抽象類更加“抽象”。

        接口使用 interface 關(guān)鍵字來聲明,可以看做是一種特殊的抽象類,可以指定一個類必須做什么,而不是規(guī)定它如何去做。

        與抽象類相比,接口有其自身的一些特性:

        • 接口中只能定義抽象方法,這些方法默認(rèn)為 public abstract 的,因而在聲明方法時可以省略這些修飾符。試圖在接口中定義實(shí)例變量、非抽象的實(shí)例方法及靜態(tài)方法,都是非法的

        • 接口中沒有構(gòu)造方法,不能被實(shí)例化

        • 一個接口不實(shí)現(xiàn)另一個接口,但可以繼承多個其他接口。接口的多繼承特點(diǎn)彌補(bǔ)了類的單繼承

        接口與抽象類的區(qū)別:

        接口作為系統(tǒng)和外界交互的窗口,接口體現(xiàn)的是一種規(guī)范。對于接口的實(shí)現(xiàn)者而言,接口規(guī)定了實(shí)現(xiàn)者必須向外提供哪些服務(wù)(以方法的形式來提供);對于接口的調(diào)用者而言,接口規(guī)定了調(diào)用者可以調(diào)用哪些服務(wù),以及如何調(diào)用這些服務(wù)(就是如何來調(diào)用方法)。當(dāng)在一個程序中使用接口時,接口是多個模塊間的耦合標(biāo)準(zhǔn);當(dāng)在多個應(yīng)用程序之間使用接口時,接口是多個程序之間的通信標(biāo)準(zhǔn)。

        從某種角度上來看,接口類似于整個系統(tǒng)的“總綱”,它制定了系統(tǒng)各模塊之間應(yīng)該遵循的標(biāo)準(zhǔn),因此一個系統(tǒng)中的接口不應(yīng)該經(jīng)常改變。一旦接口改變,對整個系統(tǒng)而言甚至其他系統(tǒng)的影響將是輻射式的,導(dǎo)致系統(tǒng)中的大部分類都需要改寫。所以,在一般的應(yīng)用里,最頂級的是接口,然后是抽象類實(shí)現(xiàn)接口,最后才到具體類實(shí)現(xiàn)。

        抽象類則不一樣,抽象類作為系統(tǒng)中多個子類的共同父類,它所體現(xiàn)的是模板式設(shè)計。抽象類作為多個子類的的抽象父類,可以被當(dāng)成系統(tǒng)實(shí)現(xiàn)過程中的中間產(chǎn)品,這個產(chǎn)品已經(jīng)實(shí)現(xiàn)了系統(tǒng)的部分功能(那些在抽象類中已經(jīng)提供實(shí)現(xiàn)的方法),但這個產(chǎn)品依然不能當(dāng)成最終產(chǎn)品,必須有更進(jìn)一步的完善。

        除此之外,接口和抽象類在用法上也存在如下區(qū)別:

        • 接口里只能包含抽象方法,抽象類則可以包含普通方法。

        • 接口里不能定義靜態(tài)方法,抽象類里可以定義靜態(tài)方法。

        • 接口里不包含構(gòu)造器,抽象類可以包含構(gòu)造器。抽象類里的構(gòu)造器并不是用于創(chuàng)建對象,而是讓其子類調(diào)用這些構(gòu)造器來完成屬于抽象類的初始化操作。

        • 接口里不能包含初始化塊,但抽象類可以包含初始化塊。

        • 接口里只能定義靜態(tài)常量,抽象類既可以定義普通變量,也可以定義靜態(tài)常量。

        • 接口可以可以繼承多個接口,類只能繼承一個類。

        • 抽象類主要是用來抽象類別,接口主要是用來抽象方法功能。當(dāng)關(guān)注事物的本質(zhì)時,使用抽象類,當(dāng)關(guān)注一種操作時,使用接口。

        三、Java中的多重繼承

        接口不僅僅是一種更加純粹的抽象類,它的目標(biāo)比這更高。因?yàn)榻涌谥懈緵]有任何具體實(shí)現(xiàn),所以沒有任何與接口相關(guān)的存儲,因此也就無法阻止多個接口的組合。在C++中,組合多個類的接口的行為叫做多重繼承,但這可能會帶來很多副作用,因?yàn)槊總€類都有一個具體實(shí)現(xiàn)。在Java中,可以執(zhí)行一樣的行為,但是只有一個類可以有具體實(shí)現(xiàn),所以通過組合多個接口,C++的問題不會在Java中發(fā)生。

        表達(dá)這樣一個意思:“ x 從屬于 a,也從屬于 b,也從屬于 c ”

        使用接口的核心原因:

        1).為了能夠向上轉(zhuǎn)型為多個基類型(以及由此帶來的靈活性);

        2).防止客戶端程序員創(chuàng)建該類的對象,并確保這僅僅是建立一個接口(這與使用抽象基類原因相同)

        這帶來的一個問題是,應(yīng)該使用接口還是抽象類?

        如果要創(chuàng)建不帶任何方法定義和成員變量的基類,那么就應(yīng)該選擇接口而不是抽象類。事實(shí)上,若知道某事物應(yīng)該成為一個基類,那么第一選擇應(yīng)該是接口。

        四、通過繼承來擴(kuò)展接口

        1、組合接口時的名字沖突

        在實(shí)現(xiàn)多重繼承時,會碰到一個小陷阱,在前面的例子中,CanFightActionCharacter都有一個相同的void fight()方法。問題不是它們方法相同,問題是,如果它們的簽名(參數(shù))或返回類型不同,會怎么樣呢?

        //: interfaces/InterfaceCollision.java
        package object;
        
        interface I1 { void f(); }
        interface I2 { int f(int i); }
        interface I3 { int f(); }
        class C { public int f() { return 1; } }
        
        class C2 implements I1, I2 {
          public void f() {}
          public int f(int i) { return 1; } // overloaded
        }
        
        class C3 extends C implements I2 {
          public int f(int i) { return 1; } // overloaded
        }
        
        class C4 extends C implements I3 {
          // Identical, no problem:
          public int f() { return 1; }
        }
        
        // Methods differ only by return type:
        //!class C5 extends C implements I1 {}            --23
        //! interface I4 extends I1, I3 {} ///:~          --24      I1, I3中f()返回值類型不一致
        
        //class C5 extends C  implements I1{  //實(shí)現(xiàn)的方法和積累方法命名相同,但方法的返回值不一樣。
        //    int f(){
        //        return 0;
        //    }
        //}
        //
        //interface I4 extends I1 , I3{  //重寫的方法名相同,但是返回值不同。
        //
        //    @Override
        //    void f();
        //}

        因?yàn)樗麄兊姆椒枷嗤?,但是返回值不同,并不能?shí)現(xiàn)方法重載。所以不能實(shí)現(xiàn)多重繼承和組合接口。

        五、適配接口

        接口最吸引人的原因之一就是允許同一個接口具有多種不同的實(shí)現(xiàn)。

        接口最常見的用法就是使用策略設(shè)計模式。此時你編寫一個執(zhí)行某些操作的方法,而該方法將接受一個你指定的接口。你主要就是聲明:“ 你可以用任何你想要的對象來調(diào)用我的方法,只要你的對象遵循我的接口?!?/p>

        比如Java SE5Scanner類,它的構(gòu)造器接收的是一個Readable接口。

        public Scanner(Readable source) {
            this(Objects.requireNonNull(source, "source"), WHITESPACE_PATTERN);
        }
        
        
        // Readable 是一個字符源。read方法的調(diào)用方能夠通過 CharBuffer 使用 Readable 中的字符。
        public interface Readable {
            // 將輸入內(nèi)容添加到CharBuffer參數(shù)中。
            public int read(java.nio.CharBuffer cb) throws IOException;
        }

        example1 : 實(shí)現(xiàn)Readable接口。

        import java.io.IOException;
        import java.nio.CharBuffer;
        import java.util.Random;
        import java.util.Scanner;
        
        public class RandomWords implements Readable {
        
         private int count;
        
         public RandomWords(int count) {
          this.count = count;
         }
        
         private static Random random = new Random(47);
         private static final char[] capitals = "ABCDEFTHIGKLMNOPQRSTUVWXYZ".toCharArray();
         private static final char[] lowers = "abcdefghijklmnopqrstuvwxyz".toCharArray();
         private static final char[] vowerls = "aeiou".toCharArray();
        
         @Override
         public int read(CharBuffer cb) throws IOException {
          if (count-- == 0) {
           return -1;
          }
          cb.append(capitals[random.nextInt(capitals.length)]);
        
          for (int i = 0; i < 4; i++) {
           cb.append(vowerls[random.nextInt(vowerls.length)]);
           cb.append(lowers[random.nextInt(lowers.length)]);
          }
          cb.append(" ");
          return 10;
         }
        
         public static void main(String[] args) {
          @SuppressWarnings("resource")
          Scanner scanner = new Scanner(new RandomWords(10));
          while (scanner.hasNext()) {
           System.out.println(scanner.next());
          }
         }
        }
        /*output:
        Yazeruyac
        Fowenucor
        Toeazimom
        Raeuuacio
        Nuoadesiw
        Hageaikux
        Ruqicibui
        Numasetih
        Kuuuuozog
        Waqizeyoy
        */

        example2 : 未實(shí)現(xiàn)Readable的類,就可以使用適配器+代理的方式

        class RandomDoubles{
            private static Random rand =new Random(47);
            public double next(){
                return rand.nextDouble();
            }
        }
        
        // ---------------------------------------------------
        
        import java.io.IOException;
        import java.nio.CharBuffer;
        import java.util.Random;
        import java.util.Scanner;
        
        public class Test {
            public static void main(String[] args) {
                Scanner s=new Scanner(new AdaptedRandomDoubles(7));
                while(s.hasNext()){
                    System.out.println(s.next());
                }
            }
        }
        class AdaptedRandomDoubles extends RandomDoubles implements Readable {
            private int count;
            public AdaptedRandomDoubles(int count){
                this.count=count;
            }
            public int read(CharBuffer cb) throws IOException {
                if(count--==0){
                    return -1;
                }
                String result=Double.toString(this.next());
                cb.append(result);
                return result.length();
            }
        
        }

        六、接口中的域

        實(shí)例變量都是static final

        七、嵌套接口

        在類中嵌套接口的語法是相當(dāng)顯而易見的,就像非嵌套接口一樣,可以擁有public和“包訪問”兩種可視性。

        1.類中的接口

         {
                void f();
            }
        
        class A {
            interface B {
                void f();
            }
        
            public class BImp implements B {
                public void f() {
                }
            }
        
            private class BImp2 implements B {
                public void f() {
                }
            }
        
            public interface C {
                void f();
            }
        
            class CImp implements C {
                public void f() {
                }
            }
        
            private class CImp2 implements C {
                public void f() {
                }
            }
        
            private interface D
        
            private class DImp implements D {
                public void f() {
                }
            }
        
            public class DImpl2 implements D {
                public void f() {
                }
            }
        
            public D getD() {
                return new DImpl2();
            }
        
            private D dRef;
        
            public void receive(D d) {
                dRef = d;
                dRef.f();
            }
        }
        
        interface E {
            interface G {
                void f();
            }
        
            //Redundant "public"
            public interface H {
                void f();
            }
        
            void g();
            //cannot be private within an interface
        }
        
        public class NestingInterface {
            public class BImpl implements A.B {
                public void f() {
                }
            }
        
            class CImpl implements A.C {
                public void f() {
                }
            }
            
            // cannot implement a private interface
            // class DImpl implements A.D {
            //     public void f() {
            //    }
            // }
        
            class EImpl implements E {
                public void g() {
                }
            }
        
            class EImpl2 implements E.G {
                public void f() {
                }
        
                class EG implements E.G {
                    public void f() {
                    }
                }
            }
        
            public static void main(String[] args) {
                A a = new A();
                A a2 = new A();
                //Can't access A.D:   不能訪問私有接口A.D
                //! A.D ad = a.getD();
                //Doesn't return anything but A.D:  除了私有接口A.D,不能返回任何東西 
                //! A.DImp2 di2 = a.getD();   //返回回來的私有接口A.D, 不能向下轉(zhuǎn)型為A.DImp2
                //Cannot access a member of the interface:  不能訪問私有接口A.D中的成員
                //! a.getD().f();  
                //Only another A can do anything with getD():  只有另一個A才能使用getD()做任何事
                a2.receive(a.getD());
            }
        }
        1. A.DImp2只能被其自身所使用。你無法說它實(shí)現(xiàn)了一個private接口D,因此,實(shí)現(xiàn)一個private接口只是一種方式,它可以強(qiáng)制該接口中的方法定義不要添加任何類型信息(也就是說,不允許向上轉(zhuǎn)型),即A.DImp2不能轉(zhuǎn)型為 private接口D;

        2. 接口也可以被實(shí)現(xiàn)為private的,就像在A.D中看到的那樣; private接口不能在定義它的類之外被實(shí)現(xiàn)

        3. 將返回值交給有權(quán)使用它的對象。在本例中,是另一個A通過receiveD()方法來實(shí)現(xiàn)的;

        4. 嵌套在另一個接口中的接口自動是public的,而不能聲明為private的;

        2.接口中的接口

        interface E{
            // 只能是默認(rèn)或者public
            interface G {
                //默認(rèn)為public
                void f();
            }
            
            // Cannot be private within an interface:
            //! private interface I {}
            
        }
        class t2 implements E.G{
            public void f() {
            }
        }

        八、接口與工廠

        接口時實(shí)現(xiàn)多重繼承的途徑,而生成遵循某個接口的對象的典型方式就是工廠方法設(shè)計模式

        通過工廠方法,接口和實(shí)現(xiàn)完全分離,可以非常方便的更改實(shí)現(xiàn)。

        interface Service // Service接口,可以有多種實(shí)現(xiàn)
        {
           void method1();
           void method2();
        }
        
        interface ServiceFactory // 工廠接口,可以由多種實(shí)現(xiàn)
        {
           Service getService();
        }
        
        class Implementation1 implements Service {  //Service接口的實(shí)現(xiàn)1
           public Implementation1() {  }
           public void method1() {
              System.out.println("Implementation1 method1");
           }
           public void method2() {
              System.out.println("Implementation1 method2");
           }
        }
        
        class Implementation1Factory implements ServiceFactory{ //生成對象1的工廠1
           public Service getService() {
              return new Implementation1();
           }
        }
        
        class Implementation2 implements Service {  // Service接口的實(shí)現(xiàn)2
           public Implementation2() {  }
           public void method1() {
              System.out.println("Implementation2 method1");
           }
           public void method2() {
              System.out.println("Implementation2 method2");
           }
        }
        
        class Implementation2Factory implements ServiceFactory{//生成對象2的工廠2
           public Service getService() {
              return new Implementation1();
           }
        }
        
        public class Factories { //使用service的模塊
           public static void serviceConsumer(ServiceFactory fact) {
              Service s = fact.getService(); //向上造型,工廠將生成某類實(shí)現(xiàn)接口的對象
              s.method1();
              s.method2();
           }
           public static void main(String[] args) {
              serviceConsumer(new Implementation1Factory());
              //serviceConsumer(new Implementation2Factory());很方便就可以更改實(shí)現(xiàn)
           }
        }
        
        /*output:
        Implementation1 method1
        Implementation1 method2
        Implementation2 method1
        Implementation2 method2
        */

        匿名內(nèi)部類改進(jìn)

        interface Service {
            void method1();
        
            void method2();
        }
        
        interface ServiceFactory {
            Service getService();
        }
        
        class Implementation1 implements Service {
            private Implementation1() {
            }
        
            public void method1() {
                System.out.println("Implementation1 method1");
            }
        
            public void method2() {
                System.out.println("Implementation1 method2");
            }
        
            public static ServiceFactory factory = new ServiceFactory() { 
                public Service getService() {
                    return new Implementation1();
                }
            }; 
        }
        
        class Implementation2 implements Service {
            private Implementation2() {
            }
        
            public void method1() {
                System.out.println("Implementation1 method1");
            }
        
            public void method2() {
                System.out.println("Implementation1 method2");
            }
        
            public static ServiceFactory factory = new ServiceFactory() {
                public Service getService() {
                    return new Implementation2();
                }
            }; 
        }
        
        public class Factories {
            public static void serviceConsumer(ServiceFactory fact) { 
                Service s = fact.getService(); 
                s.method1();
                s.method2();
            }
        
            public static void main(String[] args) {
                serviceConsumer(Implementation1.factory);
                serviceConsumer(Implementation2.factory);
            }
        }

        “如何理解Java編程接口”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

        向AI問一下細(xì)節(jié)

        免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

        AI