Java面向对象之接口(二)

Java面向对象之接口(二)

前文传送门:Java面向对象之接口(一)

  • 我们之前谈到,Java作为面向对象的语言,并不支持多继承。但是Java中的接口可以实现多继承即会出现:interface A extends InterfaceC,InterfaceD的形式,在一定程度上增加了灵活性。不仅这样,Java中的类也可以实现(implements)多个接口,间接地达到所继承的功能,成为“多实现”
  • 其实,当我们了解了接口,会发现这完全是合理的。为什么这么说呢?在Java中如果你继承两个类,两个类中有同名但不同行为的方法,你在派生类中是不是不知道用哪个,是不是很头疼。但是接口就不一样,我们知道,接口中的抽象方法或者默认方法最终会被实现类定义如果两个方法方法签名相同但是返回类型不同,这时在实现方法时就需要返回两者的公共子类型)所以不存在选择上的困难。接下来,我们慢慢来分析接口继承中可能会出现的问题。

接口定义与实现接口

  • extends关键字的出现一定代表着一种继承,或者说是一种扩展,就是子接口可以获得父接口中的成员。注意:接口可以继承接口,但是不能够继承类哦。
interface Countable {
    int NUM = 50;
}

interface Edible {
    String name = "Edible";
    void howToEat();
}
interface CreatureDoing extends Edible, Countable {
    public abstract void howToSleep();
}
  • 这时让CreatureDoing接口继承Edible和Countable两个接口,用逗号隔开,可以验证,子接口中获得了父接口的成员。
System.out.println(CreatureDoing.name);//Edible
System.out.println(CreatureDoing.NUM);//50
  • 接口无法用于创建实例,所以接口需要被类实现,这时就需要用到implements关键字。格式如下:
//类实现多个接口
class 类 implements 接口1,接口2{}
//类继承某类,且实现多个接口
class 类1 extends 类2 implements 接口1,接口2{}
  • 接口的实现和继承类似,可以获得接口中的成员变量和方法,但是需要注意的是,实现类中需要明确给出所实现的接口的所有抽象方法,否则该实现类需要定义为抽象类。这句话,有点绕,我们知道接口中的抽象方法是需要实现类去实现的,我们又说了接口可以继承接口,类可以实现多个接口。那么,如果接口A中有一个抽象方法method1,接口B继承接口A,有一个抽象方method2,类C继承了这两个接口,就要求C在类中实现这两个抽象方法,这就叫实现所有的抽象方法。

  • 还有一个点就是,实现方法其实就是重写接口中的抽象方法啦,所以必须要声明实现方法为public的,不然不满足重写的要求呢。

接口与多态

  • 可以把接口当作一种引用数据类型,可以直接用接口调用其成员,如上Creature.NUM
  • 不仅如此,接口可以声明引用类型的变量指向其实现类的对象,这类似于让父类变量指向子类对象,是多态性的很好体现。
//接口也实现了多态
Edible[] ediblesArray = new Edible[]{new Chicken(), new Orange()};
for (Edible edible : ediblesArray) {
    edible.howToEat();
}

接口是否继承于Object

  • 在书上看到一句话:所有的接口类型的引用变量都可以直接赋值给Object类型的变量,于是我产生疑惑,既然这样是不是意味着接口类型也是继承于Object类呢?
    于是我进行了尝试,我用接口类型的变量调用了Object类的方法:
System.out.println(cd.hashCode());
  • 让我震惊的是,可以调用成功。但是我始终心存疑惑,于是我展开了漫长的资料搜索,网络上的资料参差不齐,最终在这里贴一下我在stack overflow上看到的觉得比较靠谱的答案:Do interfaces inherit from Object class in java

lYwpes.png

  • 接口和类始终是并行的关系,它们都代表着一种引用数据类型,所有类都继承于Obejct类,但接口并不是。接口类型变量之所以能够调用Object类中的方法,是因为接口中隐含了一套和Object类方法签名完全相同的方法,如果不这样子的话,不能够编译成功。
  • 而接口类型的引用变量可以直接赋值给Object类型的变量,也可以这么理解:接口最终都是需要实现类去实现的,引用变量指向实现类的实例,而实现类都是Object的子类,所以是完全合理的。
package com.my.pac19;

/**
 * @auther Summerday
 */
public class TestEdible {
    public static void main(String[] args) {

        System.out.println(Countable.NUM);
        System.out.println(Edible.name);
        //接口 不能用于创建实例,但是可以声明引用类型变量指向其实现类的对象
        CreatureDoing cd = new Chicken();
        System.out.println(cd.hashCode());
        System.out.println();
        //接口也实现了多态
        Edible[] ediblesArray = new Edible[]{new Chicken(), new Orange()};
        for (Edible edible : ediblesArray) {
            edible.howToEat();
        }
    }
}

interface Countable {
    int NUM = 50;
}

interface Edible {
    String name = "Edible";

    public abstract void howToEat();
    //redundant 多余的

}

//接口继承接口
interface CreatureDoing extends Edible, Countable {
    public abstract void howToSleep();

}

abstract class Animal {

    public abstract void call();
}
class Chicken extends Animal implements Edible, CreatureDoing {
    //实现Edible中的howToEat方法
    @Override
    public void howToEat() {
        System.out.println("鸡要烤着吃");
    }
    //实现Animal中的call方法
    @Override
    public void call() {
        System.out.println("咯咯哒");
    }
    //实现Creature中的howToSleep方法
    @Override
    public void howToSleep() {
        System.out.println("呼呼");
    }
}
class Orange implements Edible {

    @Override
    public void howToEat() {
        System.out.println("橘子要剥皮吃");
    }
}

本文若有叙述不当之处,欢迎评论区留言交流!

参考链接:
https://stackoverflow.com/questions/6056124/do-interfaces-inherit-from-object-class-in-java?r=SearchResults
https://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html#jls-9.2

猜你喜欢

转载自www.cnblogs.com/summerday152/p/12132349.html