Java-从接口类型而不是类声明
在我正确掌握界面最佳实践的过程中,我注意到如下声明:Java-从接口类型而不是类声明,java,interface,Java,Interface,在我正确掌握界面最佳实践的过程中,我注意到如下声明: List<String> myList = new ArrayList<String>(); 我的问题是,我无法访问batherself()方法,因为它只存在于Cat中。这让我相信,如果我只使用在接口中声明的方法(而不是子类中的额外方法),那么我应该只从接口声明,否则我应该直接从类中声明(在本例中是Cat)。我的假设正确吗?是的,你是正确的。您应该声明为提供所使用方法的最通用类型 这就是多态性的概念。是的,你是对的。
List<String> myList = new ArrayList<String>();
我的问题是,我无法访问batherself()方法,因为它只存在于Cat中。这让我相信,如果我只使用在接口中声明的方法(而不是子类中的额外方法),那么我应该只从接口声明,否则我应该直接从类中声明(在本例中是Cat)。我的假设正确吗?是的,你是正确的。您应该声明为提供所使用方法的最通用类型
这就是多态性的概念。是的,你是对的。通过让Cat实现“PetInterface”,您可以在上面的示例中使用它,并轻松添加更多种类的宠物。如果你真的需要特定于猫,你需要访问猫类。你的答案是正确的,但是如果你需要,你可以从界面转换到所需的宠物。例如:
PetInterface p = new Cat();
((Cat)p).batheSelf();
当然,如果你想把宠物扔给狗,你不能调用batherself()方法。它甚至不会编译。因此,为了避免出现问题,您可以采用如下方法:
public void bathe(PetInterface p){
if (p instanceof Cat) {
Cat c = (Cat) p;
c.batheSelf();
}
}
使用
instanceof
时,请确保在运行时不会让狗自己洗澡。这将抛出一个错误。您可以从Cat中的talk
调用方法batherself
。在通过其接口引用对象或类引用对象之间进行选择时,应首选前者,但前提是存在适当的类型
以实现为例。对于所有情况,您都不应该盲目地使用CharSequence
而不是String
,因为这会拒绝像trim()
,toUpperCase()等简单操作
但是,如果一个方法只使用字符串
来关心它的char
值序列,那么应该使用CharSequence
,因为在这种情况下,这是合适的类型。实际上,String
类中的情况就是这样
另一个例子是它的设计和方法。这允许从模式
创建一个匹配器
,不仅用于字符串
,还用于所有其他字符序列
库中的一个很好的例子是,应该使用接口,但不幸的是没有,也可以在中找到:its和方法仅接受。自1.5版以来,这个类基本上被它的更快的同类所取代
StringBuilder
不是StringBuffer
,因此我们不能将前者与Matcher
中的append…
方法一起使用。但是,它们都实现了
(也在1.5中介绍)。理想情况下,Matcher
的append…
方法应该接受任何appendeable
,然后我们就可以使用StringBuilder
,以及所有其他可用的appendeable
因此,我们可以看到,当一个适当的类型存在时,通过接口引用对象是一个强大的抽象,但前提是这些类型存在。如果该类型不存在,那么如果有意义的话,可以考虑定义自己的类型。例如,在此Cat
示例中,您可以定义接口自浴池。然后,您可以接受任何可自洗澡的对象(例如长尾鹦鹉),而不是参考猫
如果创建一个新类型没有意义,那么您可以通过它的类来引用它
另见
- 有效Java第二版,第52项:通过对象接口引用对象
如果存在适当的接口类型,则应使用接口类型声明参数、返回值和字段。如果你养成了使用接口类型的习惯,你的程序将会更加灵活。如果不存在合适的接口,那么由类引用对象是完全合适的
相关链接
通常,您应该更喜欢接口而不是具体的类。沿着这些思路,如果您可以避免使用新操作符(在新的ArrayList示例中,它总是需要具体的类型),那就更好了
这一切都与管理代码中的依赖项有关。最好只依赖于高度抽象的东西(如接口),因为它们往往非常稳定(请参阅)。因为它们没有代码,所以只有在API改变时才需要改变它们……换句话说,当您希望该接口向世界呈现不同的行为时,即设计改变时
另一方面,课程总是在变化。依赖于类的代码不关心它如何做它所做的事情,只要API的输入和输出不改变,调用方就不应该关心
您应该根据开闭原则(请参阅)努力确定类的行为,这样即使在添加功能时,现有接口也不需要更改,您只需指定一个新的子接口即可
避免新操作符的旧方法是使用抽象工厂模式,但这会带来一系列问题。更好的方法是使用像Guice这样的工具进行依赖项注入,并且更喜欢构造函数注入。在开始使用依赖项注入之前,请确保您了解依赖项反转原则(请参阅)。我见过很多人注入了不适当的依赖项,后来又抱怨这个工具没有帮助他们……它不会让你成为一个优秀的程序员,你仍然必须正确地使用它
你正在写一个帮助学生学习物理的程序。在本课程中,学生可以在各种物理场景中放置球,并观察球的行为:从悬崖上的大炮中射出球,将球放在水下,放在深空中,等等。问题:你想包括一些关于
PetInterface p = new Cat();
((Cat)p).batheSelf();
public void bathe(PetInterface p){
if (p instanceof Cat) {
Cat c = (Cat) p;
c.batheSelf();
}
}
Cat c = new Cat();
PetInterface p = (PetInterface)c;
p.talk();
c.batheSelf();