在Java中实例化接口

use*_*147 29 java interface abstract

我有这个界面:

public interface Animal {
    public void Eat(String name);
}
Run Code Online (Sandbox Code Playgroud)

这段代码实现了这个接口:

public class Dog implements Animal {
    public void Eat(String food_name) {
        System.out.printf(food_name);
    }

    public static void main(String args[]) {
        Animal baby2 = new Dog(); //HERE!!!!!!!!!!!!!!!!!!!!!!
        baby2.Eat("Meat");
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,为什么代码有效?无法实例化接口.然而在这种情况下,界面被实例化(标记为"HERE !!!!!!!!!!!!!").

这里发生了什么?

zw3*_*324 34

不,它不是 - 您正在实例化a Dog,但由于a Dog是a Animal,您可以将变量声明为a Animal.如果您尝试实例化接口Animal,它将是:

Animal baby2 = new Animal();
Run Code Online (Sandbox Code Playgroud)

试试看,并惊恐地看着编译器尖叫:)

  • 这取决于 - 如果您需要`Dog`中不属于`Animal`合约(想象一个`bark`方法)的特殊功能,那么您需要将其声明为`Dog`(或使用演员,但这不一定好;); 但在其他情况下,当你只是使用`eat`方法或者只是期望一个`Animal`的子类的实例将它声明为`Animal`就足够了,并且不会尝试你`Dog`(你可以后来改为"象";也记录了你的意图(嘿,"动物足够了"). (3认同)
  • @feresr不,你不能.当你"实例化"`Runnable`时,你实际上创建了一个实现`Runnable`接口的匿名类的新实例. (3认同)
  • 那么为什么要实例化为一个接口,然后使用一个类来初始化它呢?至于他们为什么不这样做:Dog baby = new Dog(); (2认同)
  • @ user1535147通常这用于像`public void Foo(Animal bar)`这样的方法,它将使用_any_类实现`Animal`. (2认同)

Boh*_*ian 20

Dog不是接口:Dog是一实现Animal接口.

这里没有什么不好的事情发生.


请注意,您可以实例化接口的匿名实现,如下所示:

Animal animal = new Animal() {
    public void Eat(String food_name) {
        System.out.printf("Someone ate " + food_name);
    }
};
Run Code Online (Sandbox Code Playgroud)

  • 当你不想创建一个独立的类时使用它 - 你只需要传递一些代码.这是java做"闭包"的方式. (4认同)
  • @ user1535147看看这里:[什么是程序到界面的意思](http://stackoverflow.com/questions/383947/what-does-it-mean-to-program -to-的接口) (2认同)

Set*_*sak 12

我们考虑下面的代码:

interface Cookable {
    public void cook();
}

class Food {
    Cookable c = new Cookable() {
     public void cook() {
         System.out.println("anonymous cookable implementer");
        }
      };
 }
Run Code Online (Sandbox Code Playgroud)

上面的代码创建了一个匿名内部类的实例,但是在这里,新的实时类是Cookable接口的实现者.请注意,这是您唯一能看到语法的时间:

new Cookable()
Run Code Online (Sandbox Code Playgroud)

Cookable是一个接口而不是nonabstract类类型.想一想: 你不能实例化一个接口,但这就是它所做的代码.但是,当然,它并没有实例化Cookable object- 它正在创建一个新的实例anonymous implementer of Cookable.

你可以读这一行:

   Cookable c = new Cookable(){}
Run Code Online (Sandbox Code Playgroud)

as"声明一个Cookable类型的引用变量,显然,它将引用一个实现Cookable接口的类中的对象.但是,哦,是的,我们还没有一个实现Cookable的类,所以我们要去现在就在这里做一个.我们不需要该类的名称,但它将是一个实现Cookable的类,这个大括号开始新实现类的定义.

重要的是要记住匿名接口实现者 - 他们只能实现一个接口.根本没有任何机制可以说你的匿名内部类将实现多个接口.实际上,匿名内部类甚至无法扩展类并同时实现接口.innve类必须选择要么是命名类的子类,要么根本不直接实现任何接口,要么实现单个接口.

所以不要被实例化接口的任何尝试所欺骗,除非是匿名内部类.以下是不合法的:

Runnable r = new Runnable(); // can't instantiate interface 
Run Code Online (Sandbox Code Playgroud)

而以下是合法的,因为它实例化了Runnable接口的实现者(匿名实现类):

Runnable r = new Runnable() { 
   public void run(){ }
};
Run Code Online (Sandbox Code Playgroud)

你可以在这里阅读我的文章.


Mak*_*oto 8

你在这里观察的是SOLID依赖倒置方面.

您的代码取决于Animal合同的抽象,通过实例化它的具体实现.你只是说,"我正在对某个对象进行即时消息,但无论该对象实际上什么,它都将受到Animal接口契约的束缚."

举例来说,这些声明:

List<String> wordList = new LinkedList<>();
Map<Integer, String> mapping = new HashMap<>();
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,列表和地图的主要方面是它们遵循a List和的通用合同Map.