java中的接口懂多少

接口很多人都会写,也明白它用在什么地方,会产生哪些效果。特别是很多人一提到接口,就脱口而出规范、设计模式,那么对于接口又了解多少呢?本章试着从java中接口的定义和使用出发,谈谈java中接口具有哪些特性。

一、接口

首先,了解接口interface就必须和类class区分开,为什么这么说呢?因为接口和类是两个概念,但接口又和类具有一定的关系。有人不禁会问,怎么说呢?类class是从java.lang.Object类派生而来,但接口interface并不是从某一个特定接口派生而来,两个interface可能没有任何交集,但两个class一定存在交集。接口不是Object的子类,但接口却隐士申明了Object中的所有可继承方法,类似于Object子类继承了它的所有可继承方法,这里申明的方法都是abstract形式,也即只有申明,没有方法体block。
其次,接口的申明形式如下:

[annotation] [modifier] interface identitor [extends interfacelist] {
  [public | static |  ]  [FieldConstant];  
  [public | abstract |  ]  [AbstractMethod];
  [public | static |  ]  [MemberType];
}

其中,”[ ]”表示可有可无,而[ a | b ]表示从a或b中选择一个。annotation表示接口的注解;modifier表示接口的修饰符,正如前面所说top interface只能是public, nested interface可是static,在class中还可以是protected或private;identitor表示该接口的名称,一般取名时前缀为”I” + interfaceName 或者 interfaceName + “able”;interfacelist表示继承父接口列表,如Comparable, Serializable,Iterator等;FieldConstant表示接口中的字段;AbstractMethod表示接口中的abstract方法;MemeberType表示接口中的成员,如class,interface。

二、interface种类

java将接口分为两种:normal interface,annotation type。normal这个单词不用解释,既然有两种,那么他们肯定存在差异,也具有一定的共性。下面分别谈谈这两种interface。

三、normal interface

通用接口又可以分为外层接口top interface、内嵌接口nested interface,也即是作为一个单独的接口,还是被嵌入于类中、接口中的接口。它们的接口体body定义相同,唯一的区别在于修饰符的差异。nested interface的修饰符可以是static、public、protected或private(这两者只能是作为class中的内嵌接口才能修饰,而作为top interface中的内嵌接口进行修饰,会编译报错)。
1、FieldConstant常量字段
在接口中定义的字段都被修饰符public static final默认进行了修饰,虽然可以显示的添加public、static或final,但是建议不要添加,因为这是多余的行为,可以添加只是说明字段的修饰符。此处,还需注意一个问题,那就是常量的初始化问题,因为class中的常量可以在定义的时候进行初始化,也可以在构造函数中进程初始化,那么问题是接口中的常量何时进行初始化?因为不能显示的调用接口的初始化,所以常见在定义的时候就必须初始化,否则编译器会抛出初始化Error。其次,接口中的FieldConstant能否被子类继承?可以,如果class实现了interface,那么该接口的实例引用可以引用该接口中的常量字段,如果subinterface继承了该接口,那么subinterface继承了该接口的所有常量字段。

public class Test implements ITest {
    public static void main(String... args) {
        ITest test = new Test();
        //通过实例引用接口ITest的常量字段
        System.out.println(test.strTest); //hello world
        //通过接口引用常量字段
        System.out.println(ITest.strTest); //hello world
        //通过子接口引用常量字段
        System.out.println(ISubTest1.strTest); // hello world
    }
}
public interface ITest {
    //字段常量在定义的时候必须进行初始化
    String strTest = "hello world";
} 
public interface ISubTest1 extends ITest {}

提问:接口中的常量字段能否hide父接口中相同名称的字段?肯定可以!
2、AbstractMethod抽象方法
接口中定义的方法没有方法体,并且修饰符为public abstract默认进行修饰,也就是可以给接口中的方法添加这两种修饰符,但是建议不添加,完全是画蛇添足,理由和常量字段一样。既然是方法,那么就必然涉及到方法的重写、重载以及实现问题。

public interface ITest {
    public abstract testMethod();
    //可以不用添加public abstract修饰符,编译器默认添加
    test();
}
  • 重写override
    在class中重写,子类通过重写父类的方法来改变通过该方法名进行引用时,所具有的行为。那么,interface的方法重写是什么样的呢?除了方法体,方法重写的签名和返回值都和class中方法的重写要求相同。
public interface ITest {
    //定义一个待重写的方法
    Object test() throws IOException, ClassCastException;

    String test2();
}

public interface ISubTest extends ITest {
    //第一种,返回值类型是重写方法的子类型
    String test() throws IOException, ClassCastException;
    //第二种,异常子句重写
    Object test() throws IOException;
    String test() throws CLassCastException;
    String test() throws EOFException; 
    //第三种,正常重写
    Object test();
    String test(Object obj) throws IOException;
}

public class Test implements ISubTest {
    //实现子接口的方法,如果子接口没有重写父接口的方法,则必须实现父接口的方法。也即,实现子接口申明的、继承的方法。

    //第一种,返回值类型是重写方法的子类型
    String test() throws IOException, ClassCastException {
        return null;
    }
    //第二种,异常子句重写
    Object test() throws IOException {
        return null;
    }
    String test() throws CLassCastException {
        return null;
    }
    String test() throws EOFException {
        return null;
    }
    //第三种,正常重写
    Object test() {
        return null;
    }
    String test(Object obj) throws IOException {
        return null;
    }

    //实现子接口继承的方法
    String test2(){
        return null;
    }
}
  • 重载overload
    重载相对于重写来说没那么复杂,它所要求的是方法的签名不同,所谓方法签名是指方法的返回值和方法的参数组合,如String test(Object obj)的签名signatrue为(Object)String。但是,这里并不能根据返回值的不同来判定重载,而在JVM的底层中是根据signature来进行实现,只是编译器进行了过滤处理。
public interface ITest {
    //原始方法
    String test();

    //第一种,参数个数不同
    String test(String str);

    //第二种,参数的类型不同
    String test(int a);

    //第三种,参数的类型和个数不同
    String test(String str1, String str2);
}
  • 方法的实现
    接口中方法的实现都必须反映到实现类中,同时允许class通过继承类实现接口interface。此外,class实现implements接口,那么该class必须实现接口中的所有abstract方法(后面会说JDK8的新特性)。
    public class Test {
        //父类中定义了test1, 记得实现时修饰符的全限必须是public
        public void test1() {
        }
    }
    class A extends Test implements ITest1, ITest2 {
        //实现ITest2接口方法,记得实现时修饰符的全限必须是public
        public String test2() {
            return null;
        }
    }

    interface ITest1 {
        //方法被A的父类Test实现
        void test1();
    }

    interface ITest2 {
        //方法被A实现
        String test2();
    }

提问:接口中字段和方法是否可以具有相同名称?肯定可以!
3、MemberType成员类型
class中可以申明内部类innerClass、内部接口innerInterface和内部枚举innerEnum,接口也同样可以,此时对于innerClass、innerInterface成员类型的默认修饰符为public static,那么在定义时可以显示的指定这两个修饰符,但不建议。但innerEnum是内部枚举类型,此时它的默认修饰符为public static final,也就是说在接口中定义的枚举都是常量枚举。

public interface ITest {
    //修饰符默认为public static 
    class NestedClass {
        private int a;
        NestedClass (int a) {
            this.a = a;
        }
    }

    //默认修饰符为 public static
    interface INestedInterface {

    }

    //默认修饰符为public static final
    enum NestedEnum {
        RED, YELLOW,GREEN;
    }
}

提问:接口中的字段是否可以和成员类型具有相同的名字?可以;接口中的方法能否具有和成员类型相同的名字呢?可以。
4、内嵌接口NestedInterface
接口可以作为top interface的内嵌成员,也可以作为class中的内嵌成员。无论作为class还是interface的内嵌成员,其中接口体的定义内如如前所述,但是作为class的成员时,接口申明的修饰符还可以是protected 、private或者static。

四、接口中的defaut方法

考虑这样一种场景,某个已发布的jar中的某个接口需要集成一个新的功能函数,那么此时需要往接口中添加一个abstract方法,而所有implements这个接口的class都必须实现这个abstract方法,如果采用一个接口适配器来实现程序,也就需要在适配器类中进行实现即可,其他情况是否就很麻烦?JDK8中在接口中引入了default方法,它是一个接口实例方法,可以用来继承。那么default方法和接口的abstract方法有什么相同点和特性?具体体现在重写、重载和实现。

public interface ITest {
   //abstract抽象方法
   void test();

   //default默认方法
   default void testDefault() {
    System.out.println("hello world");
   }

   //@complile-error默认方法不能作为abstract方法的具体实现
   /*default void test() {
   }*/
}
  • 重写
    方法重写的方式就四种,default方法和普通的abstract方法没有区别,都必须满足下列四种情况之一:1、具有和父接口方法相同的返回值、名称和抛出异常;2、具有和父接口方法相同名称、抛出异常,但返回值类型是子类型;3、具有和父接口方法相同的名称、返回值,但抛出异常兼容(子异常类型);4、具有和父接口方法相同的名称,但返回值和抛出异常兼容。
    但default方法不能重写abstract方法,它只能重写父类的default方法,同时default方法不能具有和abstract方法相同的名称;
public interface ITest {
    //抽象方法
    Object test();
    //默认方法
    default Object testDefault() {
     System.out.println("hello world");
    }
}
public interface ISubTest extends ITest {
    //@compile-error编译错误
    //默认方法不能作为abstract方法的重写方法
    /*default Object test() {
         System.out.println("test");
    }*/

    //默认方法可以重写默认方法
    default String testDefault() {
        System.out.prinln("hello world");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值