Java接口总结

什么是接口

接口是对类的一种抽象描述,准确的说是对类的行为(方法)的抽象描述。所有实现了某个接口的类都应该实现这个接口所描述行为。通过接口,我们可以了解实现了接口的类能够对外界提供哪些方法和行为。

如何使用接口

定义接口

接口通过interface关键字来定义,例如,现在需要定义一个接口来描述游泳这个行为,假设游泳有摆动法游泳,滑动法游泳,喷射法游泳三种方式。那么我们可以定义如下ISwim接口如下。

public interface ISwim {

    String SWIM_BY_SWING = "swim by swing";
    String SWIM_BY_SLIDE = "swim by slide";
    String SWIM_BY_JET = "swim by jet";

    void swim();
}

通过ISwim接口,我们可以看到,在接口中只定义了方法(描述),但是并没有提供方法的具体实现。同时,方法没有访问修饰符(public,private,protected)来限定。此外,我们还在接口中定义了变量,如SWIM_BY_SWING,SWIM_BY_SLIDE,SWIM_BY_JET。在接口中定义的方法和变量有如下特点。

  • 接口中的变量会被隐式地指定为public static final类型(且只能是public static final类型,用其他类型修饰编译器会报错)

  • 接口中的方法会被隐式地指定为public abstract类型(在Java8以前,方法只能是public abstract类型,在Java8以后,允许在接口中定默认方法和static方法)

基于上面两个特点,我们可以得出下面的ISwim接口和上面的接口是完全相同的。

public interface ISwim {
    public static final String SWIM_BY_SWING = "swim by swing"; //摆动法游泳
    public static final String SWIM_BY_SLIDE = "swim by slide"; //滑动法游泳
    public static final SWIM_BY_JET = "swim by jet"; //喷射法游泳

    public abstract void swim();
}

实现接口

由于接口只提供了方法的抽象描述,没有提供方法的具体定义,所以单纯的接口没有意义的,因为我们不能像创建对象一样直接new 一个接口对象。必须有实体类来实现接口才有意义,而实现接口的本质就是把接口中抽象的方法描述变成具体的方法实现。实现一个接口时要使用implements关键字。一个接口可以被多个类实现,实现了接口的类具有接口所描述的特征。下面定义了三个类分别实现ISwim接口。

public class Fish implements ISwim{
    @Override
    public void swim() {
        System.out.println(ISwim.SWIM_BY_SWING);
    }
}
public class Frog implements ISwim{
    @Override
    public void swim() {
        System.out.println(ISwim.SWIM_BY_SLIDE);
    }
}
public class Octopus implements ISwim{
    @Override
    public void swim() {
        System.out.println(ISwim.SWIM_BY_JET);
    }
}

实现接口和继承基类有点类似,但是实现接口时,接口中定义的方法必须声明为public的,例如上面三个类中的swim方法。这是因为接口中的方法默认是public的。如果用其他访问修饰符来改变方法的可见性,编译器会报错。

一个接口可以被多个类实现,同时一个类可以实现多个接口,实现多个接口时,所有接口都放到implements关键字后面,接口之间通过逗号来分割,语法如下。

class A implements Interface1,Interface2,Interface3...{
    
}

例如,定义一个接口,描述在陆地行走这个行为。

public interface IWalk {
    void walk();
}

因为青蛙(Frog)是两栖动物,既可以在水中游泳,也可以在陆地上行走,所以青蛙同时具有游泳和行走两种行为,那么我们可以让Frog类同时实现ISwimIWalk接口。

public class Frog implements ISwim, IWalk {
    @Override
    public void swim() {
        System.out.println(ISwim.SWIM_BY_SLIDE);
    }

    @Override
    public void walk() {
        System.out.println("walk by jump");
    }
}

一个类可以实现多个接口,这是一个很有用的特性,它是Java中实现多继承的一种重要方式。因为在Java中,一个类只能有一个基类,只能单继承,而接口的存在,让Java拥有了多重继承的能力。

在上面的例子中,除了实现多个接口,也可以通过继承的方式将多个接口组合成一个接口来扩展接口的能力。例如,可以定义一个接口来描述两栖动物。

public interface IAmphibians extends ISwim{
    void walk();
}

这样IAmphibians接口同时描述了swimwalk两种能力,接下来让Frog类实现IAmphibians接口。

public class Frog implements IAmphibians {
    @Override
    public void swim() {
        System.out.println(ISwim.SWIM_BY_SLIDE);
    }

    @Override
    public void walk() {
        System.out.println("walk by jump");
    }
}

使用接口

如果一个类实现了一个接口,那么这个类可以向上转型为接口类型,就像可以转型为基类一样。虽然我们没有办法直接new一个接口类型的对象,但是我们却可以把实现了接口的类向上转型为接口的类型。基于这个特性,在代码中可以使用接口类型来代替具体的类,这样做可以提供更高的抽象性,将定义和实现分离,保证代码的扩展性。例如,我们现在需要一个方法来显示一个动物是如何游泳的,定义方法如下。

public class TestSwim {

    public static void testSwim(ISwim swim) {
        swim.swim();
    }

    public static void main(String[] args) {
        testSwim(new Fish());
        testSwim(new Frog());
        testSwim(new Octopus());
    }
}

通过将接口类型ISwim作为testSwim方法的参数,我们避免了testSwim方法和具体的类型绑定。这样可以把方法和具体的类实现解耦,后面任何实现了ISwim接口的类都可以使用这个方法。便于代码的复用和扩展。

在接口中定义静态方法

在Java8之前,接口中只能存在方法的描述,不能定义任何方法的实体,并且方法默认是public abstract类型。所以在Java8之前,如果有一些通用的方法,很有可能会放在工具类里边。但是Java8以后,允许在接口中定义静态方法。这样,可以将一些静态的工具方法直接定义在接口中,而不再需要一个单独的工具类。例如,可以把TestSwim类中的静态方法testSwim移动到接口ISwim中。

public interface ISwim {

    String SWIM_BY_SWING = "swim by swing";
    String SWIM_BY_SLIDE = "swim by slide";
    String SWIM_BY_JET = "swim by jet";

    void swim();

    static void testSwim(ISwim swim) {
        swim.swim();
    }
}

这样,就可以直接在其他类中通过ISwim.testSwim的方式来调用testSwim方法。需要注意的是,在Java8之前,在接口中定义静态方法编译器是会直接报错的。

在接口中定义默认方法

在Java8后,除了可以在接口中定义静态方法外,还可以在接口中定义默认方法。默认方法通过default关键字来标识,默认方法不仅提供了方法描述,还提供了方法的具体实现。例如。

public interface Collection {

    int size();
    default boolean isEmpty() {
        return size()==0;
    }
}

Collection接口中,为isEmpty方法提供了一个默认实现。这样在实现Collection接口的时候,我们可以只关注size方法的实现,而不需要关心isEmpty方法。

public class CollectionImpl implements Collection{

    @Override
    public int size() {
        return 1;
    }
}

当然,在CollectionImpl中也可以重写isEmpty方法。同时,通过Collection接口可以看到在默认方法中,还可以调用接口中的其他方法

那为什么要在接口中增加这个能力呢?在接口中定义默认方法主要有两个用途:

  1. 当接口中有多个方法时,默认方法可以让实现接口的类只关注他们要实现的方法,而对其他方法则不必关心。
  2. 当接口后续拓展时,通过把新增的方法定义为默认方法,可以避免修改之前已经实现了该接口的类,保证向前兼容。

第一点很好理解,关于第二点,以Collection接口为例,假设最开始Collection接口定义如下。

public interface Collection {

    int size();
}

然后,有一个类CollectionImpl实现了Collection接口。

public class CollectionImpl implements Collection{

    @Override
    public int size() {
        return 1;
    }
}

现在,如果想在Collection接口中增加一个isEmpty方法,那么我们就需要修改CollectionImpl类,让CollectionImpl类实现isEmpty方法,如果代码中有很多类都实现了Collection接口,我们就需要修改很多地方,这违反了面向对象设计的开闭原则。但是,如果isEmpty方法是默认方法,那么Collection接口的修改对先前已经实现了Collection接口的类就是无感的。

以上,就是接口的一些基本特性和使用方法。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容