2013-07-24 86 views
1

在Java中,我们不能在继承类时指定private,protected或public。例如下面的代码在Java中是不可能的。为什么?为什么Java没有基于访问指定符的继承

class A { 
    public void display() { 
     //Some implementation of display logic. 
    } 
} 

class B extends **protected** A 
{ 
    public void show() { 
     display(); 
     //some more logic. 
    } 
} 

B obj = new B(); 
obj.show(); 

我不想要obj.display()并需要隐藏它的实现从外部世界。在C++中,我们可以使用基于访问修饰符的继承,但在java中不能。我的问题是,如果我们想隐藏实现,我们如何实现这一目标?

为什么在Java中采用此架构决策在继承期间删除访问修饰符时,使用它有什么危害?

+3

什么是你想实现与访问修饰符为基类? – jlordo

+0

是的,更新了问题。 –

+0

我认为他是问为什么......在我看来,Ankit,Java被设计成纯粹的OO语言..而C++也被设计为支持OO范式。所以这里Java的人认为这些在C++中的东西可以使事情更复杂,所以他们离开它。 所以,如果你仍然有像这样的probs意味着,很明显,你没有完全转向Java。你正试图在Java中实现C++。这不好。 所以我建议你重新考虑你目前的概率的OO设计。 – Dreamer

回答

1

C++提供了允许物理继承作为类的实现细节的一部分的功能。

这部分C++被设计为之前 Barbara Liskov介绍了现在被称为Liskov substitution principle的内容。为了满足Liskov替换原则,无论使用超类的实例,也可以使用子类的实例。在你的情况下,你可以将B传给一个预期为A的方法。引入这个原理后,Java被设计为。在Java中,继承的物理机制仅用于从其超类中逻辑上继承的类。要使用类的实现,但不使用它的接口,可以使用委派。

从Stroustrup的“C++的设计和演化”:

“为基类的私有/公共区别通过五年左右[星达,1986] [里氏早在实现继承与接口继承辩论,1987)如果你只想继承一个实现,你可以在C++中使用私有派生,派生类的用户可以访问基类提供的接口,私有派生为基础留下一个实现细节;甚至基类的公共成员不可访问,除非通过为派生类明确提供的接口。“

+0

是的,我同意但为什么这个架构决策是针对Java的 –

+0

其中一个原因(如上所述)是它会打破Liskov替换原则。 –

+0

@AnkitZalani - 挖掘一下这一点,参见上面的编辑。 –

2

请注意,您不能减少方法或字段的可见性,因为它会将子类传递给需要超类的方法。但是,您可以增加它。

让我们来看一个例子:

public static void displayFromA(A a){ 
    a.display(); 
} 

由于B延伸A我们可以通过B了这一点。如果Bdisplay(方法的可见性降低,则此方法无效。这将打破Liskov替代原则的前提,正式地说,如果q(x)是一个方法调用display(的能力的真值,则q(x)将作为A的一个实例持有x,但不一定如果x是A的子类型

+0

请看看,我已经更新了这个问题。 –

+0

@AnkitZalani你不能这样做会打破超类型兼容性,以防某些方法需要'A'来运行'display('on,但你通过了它B.你只能增加可见性。 – hexafraction

0

防止访问底层显示器()的一种方法是覆盖它。例如在你的B类中:

@Override 
public void display() { 
    throw new UnsupportedOperationException("Do not use B.display(), please use B.show() instead"); 
} 

而且,在B中,例如,在show()中,改为调用super.display()。

但是,这将在运行时捕获,而不是在编译期间捕获。添加一些javadoc并希望他们阅读它们。 :-)

我不知道添加类似于@NeverCallMe注释的方法,它会在编译时被捕获。任何人都知道这个诀窍?

(补充)顺便说一句,我同意Java的设计师和其他答案,这是你通常不应该做的适当的面向对象,Liskov和所有这些。但是,这是一种有点疯狂的方式来做你想做的事。

0

如果您想隐藏每个人的信息,没有理由让B班与A班有“IS-A”关系。

如果你只是想重新使用从A类的代码,你可以有B类保鲜膜的实例,并委托给它,像这样:

class B{ 
    //this is our delegate to A 
    private A myA = new A(); 

    public void show() { 
     myA.display(); 
     //some more logic. 
    } 
} 

B obj = new B(); 
obj.show();