Java中的接口 – 它们用于什么?
可能重复:
接口的目的仍在继续
我不久前就开始学习Java了。
我遇到过Interfaces
,我知道如何使用但仍然无法完全掌握它的想法。
据我了解, interfaces
通常由类实现,然后必须实现接口中声明的方法。
问题是 – 究竟是什么意思? 从接口实现方法作为普通类方法不是更容易吗? 使用接口的优势究竟是什么?
我试过在谷歌上寻找答案。 有很多,但我仍然无法理解它的意义。 我也读过这个问题及其答案,但整个合同的事情让它变得更加复杂……
希望有人可以简化它! 🙂
提前致谢!
接口允许您在运行时提供不同的实现,注入依赖关系,单独关注,使用不同的实现进行测试。
只需将接口视为类保证实现的合同即可。 实现接口的具体类是无关紧要的。 不知道这是否有帮助。
想一些代码可能有所帮助。 这并没有解释接口的所有内容,继续阅读,但我希望这能让你开始。 这里要点是你可以改变实施……
package stack.overflow.example; public interface IExampleService { void callExpensiveService(); } public class TestService implements IExampleService { @Override public void callExpensiveService() { // This is a mock service, we run this as many // times as we like for free to test our software } } public class ExpensiveService implements IExampleService { @Override public void callExpensiveService() { // This performs some really expensive service, // Ideally this will only happen in the field // We'd rather test as much of our software for // free if possible. } } public class Main { /** * @param args */ public static void main(String[] args) { // In a test program I might write IExampleService testService = new TestService(); testService.callExpensiveService(); // Alternatively, in a real program I might write IExampleService testService = new ExpensiveService(); testService.callExpensiveService(); // The difference above, is that we can vary the concrete // class which is instantiated. In reality we can use a // service locator, or use dependency injection to determine // at runtime which class to implement. // So in the above example my testing can be done for free, but // real world users would still be charged. Point is that the interface // provides a contract that we know will always be fulfilled, regardless // of the implementation. } }
接口可用于许多事情。 大多数公共使用的是多态和dependency injection ,您可以在运行时更改依赖项。 例如,假设您有一个名为Database的接口,它有一个名为getField(...)
。
public interface Database { public void getField(String field); }
现在假设您在应用程序中使用了两个数据库,具体取决于您的客户端:MySQL和PostgreSQL。 你将有两个具体的课程:
public class MySQL implements Database { // mysql connection specific code @Override public void getField(String field) { // retrieve value from MySQL } }
和…
public class PostgreSQL implements Database { // postgre connection specific code @Override public String getField(String field) { // retrieve value from Postgre } }
现在,根据您的客户端偏好,您可以在main中实例化MySQL或PostgreSQL类
public static void main(String args[]) { if (args[2].equals("mysql")) Database db = new MySQL(); else Database db = new PostgreSQL(); } //now get the field String foo = db.getField();
或者您可以使用JS或Ruby使用Factory / Abstract Factory或脚本引擎。
它们用于实现多态,而不需要使用inheritance。
接口的想法是它们指定一个类可以实现的契约。 你读过的另一篇文章大致涵盖了这个想法。
直接从接口直接实现方法的原因是,其他方法可以使用接口类型来要求存在这些方法。
我们以AutoCloseable为例。 唯一的方法是close方法,但是使用类型而不是列出所有方法,方法表达“我需要一个可以关闭的参数”的思想要容易得多:
public void passMeSomethingThatICanClose(AutoCloseable bar) { //stuff goes here bar.close(); //the compiler knows this call is possible }
如果我们没有简洁的类型名称,那么该方法必须明确列出要求,这不是很容易,特别是当接口“contract”有很多方法时。
这也是另一种方式。 通过使用特定关键字“实现AutoCloseable”来表示意图,编译器可以告诉您是否未正确实现合同。
public class BrokenCloseable implements AutoCloseable { public void colse() { //ERROR — see the typo? //blah }
}
这是一个错误,因为该方法名称错误。 在Java中,编译器可以(并且将会)告诉您这一点。 但是如果你只负责自己实现这些方法,那么就不会出错。 相反,你的class级会默默地“不”自动解决。
其他一些语言(Python就是一个很好的例子)并不是这样做的 – 而是按照你在问题中建议的方式做事。 这被称为“鸭子打字”(如果它看起来像鸭子,像鸭子一样呱呱叫,像鸭子一样对待它),它也是一种可行的做事方式,与Java不同。
接口指定function。 在某种程度上,它们提供了多重inheritance。 假设我有一个用列表做某事的函数。 但不仅仅是一个列表,只是任何集合。 我可以循环内容的任何东西。 所以我使用了Iterable接口。
public int randomMethod(Iterable li) { ... }
现在,这适用于Lists和HashSets以及所有不同的东西,它们以完全不同的方式实现和工作,属于不同的类结构,但都提供了这个基本function 。 这与一个大型游戏循环不同,即.update()
所有扩展公共类的实体,尽管可以使用接口。
以List
界面为例。 您只能在一个点决定是否要在特定场合使用ArrayList
或LinkedList
(或其他相关的东西)。
然而他们都实现了List
接口。 因此,无论它们如何工作或者它们是否甚至是分层相关的,都可以保证它们公开了一组可以使用的方法,并且您不必在代码中的每个点知道集合对象背后的实现。以结束。
因为“死亡的致命钻石”。 让我们考虑一下这种情况:
您可以在允许多inheritance的编程语言中编写类(名称: Parent
)。 该类包含一个实例变量( int a;
)和一个方法( void hello()
)。 然后你创建两个类( Kid1
和Kid2
)。 每个类都扩展了Parent class
。 然后你重写hello();
Kid1
和Kid2
类中的方法,并为a
变量分配一些值,同样在Kid1
和Kid2
类中。 在最后一步中,您将创建第4个类(如Main
),扩展Kid1
和Kid2
类(多重inheritance)。 现在……问题是, hello();
方法将Main
类inheritance和变量的值。
由于Java中没有多重inheritance,因此我们有interfaces
…包含抽象方法的抽象类。 我们可以实现多个接口,但在条件下我们必须覆盖实现interface
包含的所有方法。
我建议你看一下策略模式和组合模式。
你的问题可以在一篇文章中广泛回答,而不是过于拙劣或过于通用而没有用处。 所以我将尝试给出一个有希望的有用的例子,说明接口何时非常有用。
假设您有许多代表各种类型对象的类。可能是十几个,或任何足够大的数字。 并且你在另一个类中有一些函数,它希望能够对任意对象进行排序。 为此,它需要能够比较任何两个对象并确定一个对象是否大于或小于另一个对象。 由于每个对象可以是您的许多类型中的任何一个,因此这个比较函数编写起来非常繁琐,因为它必须确定每个对象的类型,然后通过为每个类调用适当的逻辑来进行比较。
输入接口。 此时,您可以让所有类都实现一个接口,例如Comparable,它指定实现它的任何类都将实现Compare方法。
现在你的命令对象的函数将变得微不足道,因为它只能依赖于它需要比较的任何类对象具有相同的Comapre方法这一事实。
这只是一个例子 – 而且是一个相当普遍的例子。