41

我有这个界面:

public interface Animal {
    void Eat(String name);
}

这里的代码实现了接口:

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(); // <- this line
        baby2.Eat("Meat");
    }
}

我的问题是,为什么代码有效?无法实例化接口。然而在这种情况下,接口被实例化(用注释标记)。

这里发生了什么?

4

15 回答 15

51

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

Animal baby2 = new Animal();

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

于 2013-05-25T14:59:30.620 回答
29

Dogis not an interface:Dog实现该接口的Animal

这里没有发生任何不愉快的事情。


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

Animal animal = new Animal() {
    public void Eat(String food_name) {
        System.out.printf("Someone ate " + food_name);
    }
};
于 2013-05-25T15:03:18.270 回答
19

让我们考虑下面的代码:

interface Cookable {
    public void cook();
}

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

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

new Cookable()

其中 Cookable 是一个接口而不是非抽象类类型。想一想: 你不能实例化一个 interface,但这就是代码看起来正在做的事情。但是,当然,它不是实例化 a Cookable object- 它是创建一个 new 的实例anonymous implementer of Cookable

你可以阅读这一行:

   Cookable c = new Cookable(){}

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

对于匿名接口实现者来说,记住这一点很重要——他们只能实现一个接口。根本没有任何机制可以说您的匿名内部类将实现多个接口。事实上,一个匿名内部类甚至不能同时扩展一个类和实现一个接口。innve 类必须选择作为命名类的子类并且根本不直接实现任何接口或实现单个接口。

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

Runnable r = new Runnable(); // can't instantiate interface 

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

Runnable r = new Runnable() { 
   public void run(){ }
};

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

于 2016-02-29T20:24:39.537 回答
9

您在这里观察到的是SOLID的依赖反转方面。

Animal您的代码通过实例化合约的具体实现来依赖于合约的抽象。您只是在说明,“我正在实例化某个对象,但无论该对象实际上什么,它都将绑定到Animal接口的合同。”

以这些声明为例:

List<String> wordList = new LinkedList<>();
Map<Integer, String> mapping = new HashMap<>();

在这两种情况下,列表和地图的主要方面是它们遵循 aList和的通用协定Map

于 2013-05-25T15:08:16.000 回答
2
Animal baby2 = new Dog(); //HERE!!!!!!!!!!!!!!!!!!!!!!

当然,您没有实例化 Animal。您只是将 Dog 实例引用给它。在java中,我们可以获取超类引用。

于 2013-05-25T15:50:44.287 回答
2

这是多态性的一个例子,看起来你正在创建“动物”对象,但事实并非如此。您正在创建在运行时计算的“狗”对象。“动物”充当合同。接口不能直接实例化,但可以通过向上转换其子类来用作类型。您还可以使用匿名类将对象实例化为“动物”类型。

   Animal baby2 = new Dog(); //upcasting polymorphically
   Animal baby3=new Animal(){
      public void Eat(String food){System.out.println("fdkfdfk"); }
   }
    //You can instantiate directly as anonymous class by implementing all the method of interface
于 2015-10-19T05:20:30.817 回答
1

当你说:

Animal baby2 = new Dog();

引用类型是指向具体实现(Dog)的Animal(接口)。对象类型 Dog 是具体的并且可以被实例化。在这种情况下,只要 Dog hasanimal 指向 Dog。接口中所有方法的具体实现,可以做一个引用类型

如果你做了类似的事情,

Animal baby2 = new Animal(); // here you are actually instantiating

这将是无效的,因为现在您正试图从抽象实现创建一个具体对象。

于 2014-03-08T23:22:37.193 回答
1

该接口Animal不是实例化的,而是由 .and 实现的Dog。并且 aDog是实例化的

于 2013-05-25T15:04:07.987 回答
1

接口 Animal 充当 Dog 类的数据类型。您实际上是在实例化 Dog 类而不是接口或其数据类型。

于 2014-09-25T14:31:51.390 回答
1

有一个更广泛的画面:

Animal [] Zoo = new Animal[10] ; // is also correct

但为什么 ?

整个想法是,在上面的表格中,您可以放置​​ 10 种不同类型的动物。唯一的条件是所有进入动物园的动物都必须实现接口 Animal 。

public interface Animal {
 void Eat();
}
class Wolf implements Animal {  void Eat (){ 
System.out.println("Wolf eats meat ") ;}}

Class Zebra implements Animal{ void Eat (){
System.out.println("Zebra eats the grass ") ;}}

class test {
public static void main (String args []) {

Animal [] Zoo = new Animal[2] ;

Zoo[0] =  new Wolf() ;
Zoo[1] = new Zebra() ;

 //so you can feed your animals in Zoo like this

 for (int i=0 ; i<Zoo.lenght;i++) {Zoo[i].Eat();}
}
}
于 2015-12-30T11:53:09.487 回答
1

您不能实例化接口。可以认为该功能类似于抽象类的功能。您可以引用接口,但不能创建接口对象。如果你做这样的事情......

动物 a = 新动物();编译器将显示错误-“无法实例化动物类型”。

于 2019-11-21T11:01:47.187 回答
0

实际上你可以实例化接口。这是您可以尝试的代码

public static void main(String args[]) {
    System.out.println(new Animal() {
        public String toString() {
            return "test";
        }
    });
}

该程序成功运行并打印test Try it。

于 2014-08-06T01:49:04.903 回答
0

你所做的是类型转换。你已经创建了一个 dog 类的实例,并将它的类型转换为接口 animal。它是运行时 polymorphosim 的一个示例。但是是的,可以实现一个接口,我在搜索这个时已经到达这里。IE

public class demo16{
interface cardio{
    void run();
}

static void foo(){
    cardio c = new cardio(){ //HENCE instance of "interface cardio" is being created inside a method foo
        public void run(){
            System.out.println("How you doing  ! ");
        }; //HENCE observe the ";" beside }
    };     //HENCE observe the ";" beside }
    c.run();
}

public static void main(String [] args){
    foo();
}

}

于 2021-02-22T15:26:02.723 回答
0

这里只是引用接口,但实例化仅由类完成。例如

Animanl a = new Dog Animal a - 变量被引用 new Dog - 现在内存已分配

于 2017-08-08T10:31:13.720 回答
0

Java 8 让你使用,功能接口,

@FunctionalInterface // this is not mandatory 
interface A{
    void m1(); // only one abstract method allowed for functional interface
}

class Main{
   public static void main(String a[]){

      // old usage
      A a1 = new A(){
        @Override
        public void m1(){
           System.out.println("Call Me normally");
        }
      };

      a1.m1();

      // new in java 8, functional interface
      A a2 = ()-> System.out.println("Call Me as functional interface");
      a2.m1();
 
   }
}
于 2020-07-13T02:58:20.417 回答