在Java中实例化接口

我有这个界面:

public interface Animal { public 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(); //HERE!!!!!!!!!!!!!!!!!!!!!! baby2.Eat("Meat"); } } 

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

这里发生了什么?

不,它不是 – 你正在实例化一只Dog ,但由于一只DogAnimal ,你可以将变量声明为Animal 。 如果您尝试实例化Animal接口,它将是:

 Animal baby2 = new Animal(); 

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

Dog不是一个接口: Dog是一个实现 Animal接口的类。

这里没有什么不可思议的事情发生。


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

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

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

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

举例来说,这些声明:

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

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

我们考虑下面的代码:

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

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

 new Cookable() 

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

你可以读这一行:

  Cookable c = new Cookable(){} 

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

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

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

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

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

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

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

 Animal baby2 = new Dog(); //HERE!!!!!!!!!!!!!!!!!!!!!! 

当然你没有实例化动物。 您只是将Dog实例引用到它。 在java中我们可以采用超类引用。

接口Animal不是被实例化的,而是由Dog实现的。并且一个Dog被实例化

当你说:

 Animal baby2 = new Dog(); 

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

如果你做了类似的事情,

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

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

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

要有更广泛的图景:

 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 

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

  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 

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

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

该程序运行成功并打印test试试吧。

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

Animanl a =新的Dog Animal a – 变量被引用为新的Dog – 现在已经分配了Memory