温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何理解Java编程接口

发布时间:2021-10-08 09:08:49 来源:亿速云 阅读:121 作者:iii 栏目:开发技术

本篇内容介绍了“如何理解Java编程接口”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

目录
  • 一、抽象类和抽象方法

  • 二、接口

  • 三、Java中的多重继承

  • 四、通过继承来扩展接口

    • 1、组合接口时的名字冲突

  • 五、适配接口

    • 六、接口中的域

      • 七、嵌套接口

        • 1.类中的接口

        • 2.接口中的接口

      • 八、接口与工厂

        一、抽象类和抽象方法

        抽象:从具体事物抽出、概括出它们共同的方面、本质属性与关系等,而将个别的、非本质的方面、属性与关系舍弃,这种思维过程,称为抽象。

        这句话概括了抽象的概念,而在Java中,你可以只给出方法的定义不去实现方法的具体事物,由子类去根据具体需求来具体实现。

        抽象类除了包含抽象方法外,还可以包含具体的变量和具体的方法。类即使不包含抽象方法,也可以被声明为抽象类,防止被实例化。

        抽象类不能被实例化,也就是不能使用new关键字来得到一个抽象类的实例,抽象方法必须在子类中被实现。

        抽象类总结规定:

        1. 抽象类不能被实例化,如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。

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

        3. 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。

        4. 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。

        5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。

        二、接口

        interface关键字使得抽象的概念更加向前迈进了一步,abstract关键字允许人们在类中创建一个或多个没有任何定义的方法---提供了接口部分。但是没有提供任何相应的具体实现,这些实现是由此类的继承者实现的。

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

        接口使用 interface 关键字来声明,可以看做是一种特殊的抽象类,可以指定一个类必须做什么,而不是规定它如何去做。

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

        • 接口中只能定义抽象方法,这些方法默认为 public abstract 的,因而在声明方法时可以省略这些修饰符。试图在接口中定义实例变量、非抽象的实例方法及静态方法,都是非法的

        • 接口中没有构造方法,不能被实例化

        • 一个接口不实现另一个接口,但可以继承多个其他接口。接口的多继承特点弥补了类的单继承

        接口与抽象类的区别:

        接口作为系统和外界交互的窗口,接口体现的是一种规范。对于接口的实现者而言,接口规定了实现者必须向外提供哪些服务(以方法的形式来提供);对于接口的调用者而言,接口规定了调用者可以调用哪些服务,以及如何调用这些服务(就是如何来调用方法)。当在一个程序中使用接口时,接口是多个模块间的耦合标准;当在多个应用程序之间使用接口时,接口是多个程序之间的通信标准。

        从某种角度上来看,接口类似于整个系统的“总纲”,它制定了系统各模块之间应该遵循的标准,因此一个系统中的接口不应该经常改变。一旦接口改变,对整个系统而言甚至其他系统的影响将是辐射式的,导致系统中的大部分类都需要改写。所以,在一般的应用里,最顶级的是接口,然后是抽象类实现接口,最后才到具体类实现。

        抽象类则不一样,抽象类作为系统中多个子类的共同父类,它所体现的是模板式设计。抽象类作为多个子类的的抽象父类,可以被当成系统实现过程中的中间产品,这个产品已经实现了系统的部分功能(那些在抽象类中已经提供实现的方法),但这个产品依然不能当成最终产品,必须有更进一步的完善。

        除此之外,接口和抽象类在用法上也存在如下区别:

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

        • 接口里不能定义静态方法,抽象类里可以定义静态方法。

        • 接口里不包含构造器,抽象类可以包含构造器。抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。

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

        • 接口里只能定义静态常量,抽象类既可以定义普通变量,也可以定义静态常量。

        • 接口可以可以继承多个接口,类只能继承一个类。

        • 抽象类主要是用来抽象类别,接口主要是用来抽象方法功能。当关注事物的本质时,使用抽象类,当关注一种操作时,使用接口。

        三、Java中的多重继承

        接口不仅仅是一种更加纯粹的抽象类,它的目标比这更高。因为接口中根本没有任何具体实现,所以没有任何与接口相关的存储,因此也就无法阻止多个接口的组合。在C++中,组合多个类的接口的行为叫做多重继承,但这可能会带来很多副作用,因为每个类都有一个具体实现。在Java中,可以执行一样的行为,但是只有一个类可以有具体实现,所以通过组合多个接口,C++的问题不会在Java中发生。

        表达这样一个意思:“ x 从属于 a,也从属于 b,也从属于 c ”

        使用接口的核心原因:

        1).为了能够向上转型为多个基类型(以及由此带来的灵活性);

        2).防止客户端程序员创建该类的对象,并确保这仅仅是建立一个接口(这与使用抽象基类原因相同)

        这带来的一个问题是,应该使用接口还是抽象类?

        如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类。事实上,若知道某事物应该成为一个基类,那么第一选择应该是接口。

        四、通过继承来扩展接口

        1、组合接口时的名字冲突

        在实现多重继承时,会碰到一个小陷阱,在前面的例子中,CanFightActionCharacter都有一个相同的void fight()方法。问题不是它们方法相同,问题是,如果它们的签名(参数)或返回类型不同,会怎么样呢?

        //: 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{  //实现的方法和积累方法命名相同,但方法的返回值不一样。
        //    int f(){
        //        return 0;
        //    }
        //}
        //
        //interface I4 extends I1 , I3{  //重写的方法名相同,但是返回值不同。
        //
        //    @Override
        //    void f();
        //}

        因为他们的方法名都相同,但是返回值不同,并不能实现方法重载。所以不能实现多重继承和组合接口。

        五、适配接口

        接口最吸引人的原因之一就是允许同一个接口具有多种不同的实现。

        接口最常见的用法就是使用策略设计模式。此时你编写一个执行某些操作的方法,而该方法将接受一个你指定的接口。你主要就是声明:“ 你可以用任何你想要的对象来调用我的方法,只要你的对象遵循我的接口。”

        比如Java SE5Scanner类,它的构造器接收的是一个Readable接口。

        public Scanner(Readable source) {
            this(Objects.requireNonNull(source, "source"), WHITESPACE_PATTERN);
        }
        
        
        // Readable 是一个字符源。read方法的调用方能够通过 CharBuffer 使用 Readable 中的字符。
        public interface Readable {
            // 将输入内容添加到CharBuffer参数中。
            public int read(java.nio.CharBuffer cb) throws IOException;
        }

        example1 : 实现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 : 未实现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();
            }
        
        }

        六、接口中的域

        实例变量都是static final

        七、嵌套接口

        在类中嵌套接口的语法是相当显而易见的,就像非嵌套接口一样,可以拥有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, 不能向下转型为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只能被其自身所使用。你无法说它实现了一个private接口D,因此,实现一个private接口只是一种方式,它可以强制该接口中的方法定义不要添加任何类型信息(也就是说,不允许向上转型),即A.DImp2不能转型为 private接口D;

        2. 接口也可以被实现为private的,就像在A.D中看到的那样; private接口不能在定义它的类之外被实现

        3. 将返回值交给有权使用它的对象。在本例中,是另一个A通过receiveD()方法来实现的;

        4. 嵌套在另一个接口中的接口自动是public的,而不能声明为private的;

        2.接口中的接口

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

        八、接口与工厂

        接口时实现多重继承的途径,而生成遵循某个接口的对象的典型方式就是工厂方法设计模式

        通过工厂方法,接口和实现完全分离,可以非常方便的更改实现。

        interface Service // Service接口,可以有多种实现
        {
           void method1();
           void method2();
        }
        
        interface ServiceFactory // 工厂接口,可以由多种实现
        {
           Service getService();
        }
        
        class Implementation1 implements Service {  //Service接口的实现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接口的实现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(); //向上造型,工厂将生成某类实现接口的对象
              s.method1();
              s.method2();
           }
           public static void main(String[] args) {
              serviceConsumer(new Implementation1Factory());
              //serviceConsumer(new Implementation2Factory());很方便就可以更改实现
           }
        }
        
        /*output:
        Implementation1 method1
        Implementation1 method2
        Implementation2 method1
        Implementation2 method2
        */

        匿名内部类改进

        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编程接口”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

        向AI问一下细节

        免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

        AI