为什么界面有用?

时间:2015-02-14 20:48:47

标签: java interface abstract-class

我确切地知道接口和抽象类之间有什么区别,但为什么接口有用呢?看看这个:

Interfaces example

9 个答案:

答案 0 :(得分:6)

现在想象一下抽象PointCircle。您如何实现MovablePoint同时为MovablePoint?只有界面可以为您提供,以及它们的用途。

答案 1 :(得分:1)

参见 HERE

  
      
  • 如果您认为计划使用继承,那么抽象类很好,因为它提供了一个公共基类实现   派生类。
  •   
  • 如果您希望能够声明非公开成员,那么抽象类也很好。在界面中,所有方法都必须是公共的。
  •   
  • 如果您认为将来需要添加方法,那么抽象类是更好的选择。因为如果你添加新方法   标题到接口,然后是所有类   实现该接口必须更改以实现新的   方法。这可能会非常麻烦。
  •   
  • 当您认为API暂时不会改变时,接口是一个不错的选择。
  •   
  • 当你想拥有类似于多重继承的东西时,接口也很好,因为你可以实现多个接口。
  •   

在你的场景中只有你可以指定的接口,如果MovablePoint是Movable和Point。

答案 2 :(得分:0)

想象一下,使用你的图书馆的人想要介绍其他可用的东西,比如MovableTirangle。如果他们让这个工具Movable,它可以完美地与您的图书馆一起使用。

例如,库提供了

void move(Movable m, int horiz, int vert) {
    int i;
    if (horiz >= 0) {
        for (i=0; i < horiz; i++) {
            m.moveRight();
        }
    } else {
        for (i=0; i > horiz; i--) {
            m.moveLeft();
        }
    }
    if (vert >= 0) {
        for (i=0; i < vert; i++) {
            m.moveUp();
        }
    } else {
        for (i=0; i > vert; i--) {
            m.moveDown();
        }
    }
}

,可用于所有当前和未来的Movable种。

到目前为止,这对于基类也是有效的,因此实际上并不重要。

但是,由于Java不支持多重继承,因此类不能从多个基类继承。但如果需要,可以实现多个接口。

此外,如果你有一个功能界面(你没有,因为你有多个非默认函数),你还可以使用Java的新lambda特性。这是另一件不适用于抽象类的东西。

答案 3 :(得分:0)

是的 - 在这种情况下你可以拥有,但也要考虑更大的图景。当我第一次学习OOP时,我问同样的问题,并且界面让我困惑了很长时间。

如果你想将'可移动'方法添加到不是Point的子类的对象,假设'MovableJPEG'或者其他类似的东西。移动操作的最终结果将是相同的,但您必须重写两个类和不同方法的接口,以处理在与Movable对象交互的类中移动这些功能。

使用接口传递任意数量的类型,仅通过使用相同方法的类似接口,因为它们的实现细节保证相同。

答案 4 :(得分:0)

接口和抽象类都允许程序员编写模块化类。

接口优于抽象类的优点是它不带任何预定义的方法或属性。抽象类可能包含您不希望在类中实现的内容。

第二个优点是java类只能扩展一个类,但只能扩展大量接口。

接口提供了更多的自由,抽象类可以影响类的内部设计。抽象类的一个优点是代码共享,这对于接口来说更加困难。

答案 5 :(得分:0)

  1. 您在java中没有多重继承。所以多个类不能在同一个类中继承,但可以实现多个接口
  2. 有助于保持组织有序。就像所有与DOG相关的东西都在一个界面下,CAT下的所有CAT都是如此。
  3. 运行时多态性:使用接口u可以有超类引用变量引用不同的不同子类。这有助于保持代码清洁,提高可伸缩性(使所有桥接/代理/工厂等设计模式成为可能,否则可能不存在)。

答案 6 :(得分:0)

概念差异:

我不会列出使用接口或抽象类之间的所有差异,或者何时使用它们中的每一个,我认为你会在网上找到很多资源,所以只讨论它,例如:{{3 }}

要回答你,,您只能在示例中使用抽象类,而不必使用界面

,存在概念差异,未创建接口以公开公共行为,它是可以执行的类的合同< / strong>即可。 虽然抽象类是层次结构的父级,但可以生成具有核心结构并提供默认行为的子级。

与你的例子类比:

从概念上讲,Movable必须是Interface,因为它定义了implements Movable 可以做什么的类(可以向上移动,向下移动,移动.. 。)而不是如何这样做(Circle dosn像Rectangle一样移动)。虽然您的MovableCircle可能是abstract class,但我们可以定义以下方法:calculateArea()getRadius()calculateCircumference(),...这是类的默认行为将继承自MovableWheel

答案 7 :(得分:0)

让你试图给一些不相关的类提供类似的属性。然后你可以使用界面。例如 -

       <Bounceable>
        /     \
      Ball    Tire 

此处BallTire(汽车)完全无关。但他们都是Bounceable。如果您希望两个不相关的类具有相同的属性,则可以使用interface。

接口还有另一个重要用途 - 提供多重继承的风格,但比多重继承更有效(存在常见的Deadly Diamond of Death问题。)。例如,您期望Ball应该同时为BouncableSerializeableBouncableSerializeable完全无关。然后你可以在这里使用界面。抽象类需要扩展/继承,并且java多个inheritance是不可能的。因此,我们可以通过使用接口为类提供完全不相关的属性。

答案 8 :(得分:0)

当人们将接口解释为合同即实现方法签名的义务时,IMO虽然正确,但我发现他们经常忘记提及使用接口作为实现相同接口的整组对象的类型,而我相信这是拼图的重要部分,了解界面的有用性。

这是一个带有Cat和Dog类的代码示例(C#),它使用了interface和absctract类,希望它们能够突出它们之间的差异。

假设1:两只动物都说声音,但这些是不同的声音(需要不同的方法) 假设2:两只动物都可以吃,如果它们不满(这两种动物都需要一种方法)

static void Main(string[] args)
    {
        IanimalBehavior pluto = new Dog();
        IanimalBehavior simba = new Cat();

        Program.makeAnimals_say_and_eat(pluto);
        Program.makeAnimals_say_and_eat(simba);

        Program.makeAnimals_say_and_eat(pluto);
        Program.makeAnimals_say_and_eat(simba);
        Console.ReadLine();
    }

    static void makeAnimals_say_and_eat(IanimalBehavior animalObject)
    {
        Console.WriteLine(animalObject.makeSound());
        Console.WriteLine(animalObject.eat());
    }

    interface IanimalBehavior {
       string makeSound();
       string eat();
    } 

    class Dog : Animal, IanimalBehavior {            

        public string makeSound() {
            return this.GetType().Name + " says: wuf";
        }
    }

    class Cat : Animal, IanimalBehavior {

        public string makeSound()
        {
            return this.GetType().Name + " says: miauw";
        }
    }

    abstract class Animal {

        bool _isFull = false;
        public string eat()
        {
            if (_isFull == false)
            {
                _isFull = true;
                return this.GetType().Name + " is now eating";
            }
            else
            {
                return this.GetType().Name + " is now too full to eat!";
            }
        }
    }

请注意,动物被声明为接口类型:

IanimalBehavior pluto = new Dog();

这将确保方法makeAnimals_say_and_eat()可以采用针对两种类型的对象(Cat&amp; Dog)的参数类型,因此所有动物只需要一种方法,这就是我们想要的。

static void makeAnimals_say_and_eat(IanimalBehavior animalObject)
    {
        Console.WriteLine(animalObject.makeSound());
        Console.WriteLine(animalObject.eat());
    }

该方法从作为参数传递的任何对象调用.makeSound()和.eat()。编译器很高兴,因为它知道任何IanimalBehavior类型都必须包含这两种方法,因为它在合同中这样说:

interface IanimalBehavior {
       string makeSound();
       string eat();
    } 

on .makeSound()返回值取决于类类型,而.eat()对于两个类都相同,因为eat()在所有动物继承的absctract类Animal中声明。

这些指示的输出:

Program.makeAnimals_say_and_eat(pluto);
Program.makeAnimals_say_and_eat(simba);

Program.makeAnimals_say_and_eat(pluto);
Program.makeAnimals_say_and_eat(simba);

是:

Dog says: wuf
Dog is now eating
Cat says: miauw
Cat is now eating
Dog says: wuf
Dog is now too full to eat!
Cat says: miauw
Cat is now too full to eat!

接口类型还为您提供了在单个数组中存储具有相似性质的不同对象(相同的接口实现)的选项,然后您可以迭代这些对象。

IanimalBehavior[] animal_list = { new Dog(), new Cat()};

foreach (IanimalBehavior animal in animal_list)
       {
           Console.WriteLine(animal.eat());
           Console.WriteLine(animal.makeSound());
       }