Java接口-致命缺陷

Java接口-致命缺陷,java,interface,casting,Java,Interface,Casting,假设我们有一个接口A,由类B实现: public interface A { public int getValueForName(String name); } public class B implements A { public int getValueForName(String name) { //implementation } public String getNameForValue(int value) {

假设我们有一个接口
A
,由类
B
实现:

public interface A {
    public int getValueForName(String name);
}

public class B implements A {

    public int getValueForName(String name) {
        //implementation
    }

    public String getNameForValue(int value) {
        //implementation
    }

}
如果程序员每次引用
B
的实例时都一致地使用类型
A
,则
B
中定义但
A
中未指定的任何方法(如
getNameForValue()
)都将被隐藏,并且任何持有类型
A
引用的代码都无法访问

这种方法似乎有一个致命的缺陷。引用
B
(类型为
a
)实例的一段代码如何访问
getNameForValue()

真正的缺陷是接口的契约没有得到尊重。如果我正在使用接口,我不应该关心除了接口中定义的那些方法之外的任何其他方法

如果接口没有定义我想要使用的方法,那么要么需要更新接口以适应新方法,要么需要使用不同的接口

以…为例。如果我有一个绑定到
集合
契约的实例,那么我可以访问。但是,我知道我要返回的元素类型是
List
,我想使用更强大的

问题是,
集合
没有为我定义任何访问
列表迭代器的方法。因此,我只有一个选择(因为我不能不必要地去更新
集合
界面):使用
列表
界面

如果您在自己的代码中遇到这种情况,则您的接口不支持所需的方法。在接口级别添加支持,而不是在实例级别添加支持。

真正的缺陷是接口的契约没有得到尊重。如果我正在使用接口,我不应该关心除了接口中定义的那些方法之外的任何其他方法

如果接口没有定义我想要使用的方法,那么要么需要更新接口以适应新方法,要么需要使用不同的接口

以…为例。如果我有一个绑定到
集合
契约的实例,那么我可以访问。但是,我知道我要返回的元素类型是
List
,我想使用更强大的

问题是,
集合
没有为我定义任何访问
列表迭代器的方法。因此,我只有一个选择(因为我不能不必要地去更新
集合
界面):使用
列表
界面

如果您在自己的代码中遇到这种情况,则您的接口不支持所需的方法。在接口级别而不是实例级别添加该支持

引用B实例(类型为a)的代码段如何访问getNameForValue()

通过将实例强制转换为类型B

接口的目的之一是定义两种或两种以上类型通用的方法。这并不意味着您要为每个可能类型的每个可能组合定义接口方法,而只定义那些对希望通过接口公开的所有类型通用的方法

因此,根据定义,拥有接口类型的实例假定原始类型中可能存在您无法通过接口访问的方法。这就是它的工作原理

您可能拥有接口的另一个原因是指定功能。所以,如果一个类是Iterable,这意味着它可以被迭代。如果我试图获得一个Iterable实例,我关心类中实现Iterable方法的方法,但我不关心任何其他方法,因为它们与Iterable功能无关

简而言之,这是一个特性,而不是一个缺陷

引用B实例(类型为a)的代码段如何访问getNameForValue()

通过将实例强制转换为类型B

接口的目的之一是定义两种或两种以上类型通用的方法。这并不意味着您要为每个可能类型的每个可能组合定义接口方法,而只定义那些对希望通过接口公开的所有类型通用的方法

因此,根据定义,拥有接口类型的实例假定原始类型中可能存在您无法通过接口访问的方法。这就是它的工作原理

您可能拥有接口的另一个原因是指定功能。所以,如果一个类是Iterable,这意味着它可以被迭代。如果我试图获得一个Iterable实例,我关心类中实现Iterable方法的方法,但我不关心任何其他方法,因为它们与Iterable功能无关


简而言之,这是一个功能,而不是一个缺陷。

从一个更真实的例子来看。如果我被蒙上眼睛,你告诉我有一只家养宠物在我面前,我能用它做什么?也许就这些了。现在,如果你告诉我它是一只仓鼠,我也可以把它放在轮子里让它到处跑(另一方面,我的猫不会同意这个想法)

当您将变量声明为接口(或更高级别的类)时,例如
a
,它与上面示例中的家庭宠物相同。因此,并非所有的方法都可以访问

要知道它是仓鼠还是a
B
你必须取下眼罩。对于Java,这意味着调用
instanceof
,然后将变量强制转换为a
B
。您需要
指令