为什么对接口的引用数组可以包含实现该接口的类?

时间:2014-02-13 22:22:11

标签: java class oop interface

我已经阅读了许多线程来解释接口和抽象类之间的差异;这些帖子特别有用:What is the difference between an interface and abstract class?Interface vs Abstract Class (general OO);但是,我找不到任何专门解决我问题的答案。

上下文: 今天在课堂上我们编写了一个接口和两个实现接口的类:

public interface Animal{ // This is in its own file
    void move();
    void makeSound();
}

class Dog implements Animal{  // The rest of these are in another file
    public void move(){
        System.out.println("Runs.");
    }
    public void makeSound(){
        System.out.println("Barks.");
    }
}

class Fish implements Animal{
    public void move(){
        System.out.println("Swims.");
    }
    public void makeSound(){
        System.out.println("Bloops.");
    }
}

public class Zookeeper{
    public static void main(String[] args){
        Animal[] zoo = new Animal[10]; // This an array of references to an interface
        for(int i = 0; i < zoo.length; i++){
            zoo[i] = (Math.round(Math.random()) == 0)?new Dog():new Fish();
        }
        for(Animal animal: zoo){
            System.out.println(animal.getClass().getName());
            animal.makeSound();
            animal.move();
        }
    }
}

我知道这是有可能的,因为它有效;我的问题是它为什么有效?我得到的子类与它们的超类有一个ISA关系,但接口根本不是类,所以继承仍适用于它们吗? 实现多个接口的类是否与这些接口具有ISA关系?

这个问题可以进一步抽象为:为什么接口的引用变量可以实现该接口的类?

1 个答案:

答案 0 :(得分:4)

您的Animal[]持有Animals,对。

但是您当然知道Dog也是Animal,因此编译器可以将其视为Animal,并将其作为Animal[]添加到数组中。

当然,当你浏览数组时,编译器不能进一步假设哪个引用属于哪个类,所以只有接口方法在你的循环中可用

多态的好处。

编辑:也许您的问题更关心类与界面的差异,您想知道如何存储对界面实例的引用?

即使之前的措辞也很粗糙。没有接口实例,而是接口实现的实例。那么你的Dog实际拥有的是对你实现该接口的任何类的实例的引用(即FishNyanCatString或你有什么。)

另请注意,在之前的解释中,我并不真正关心类与界面的差异。编译器也没有。所有它关心的是正确输入,也就是说,您实际上无法向Animal[]添加Animal,但只有衍生物/子项-types {{1}}。

强类型