在Java中,我们在继承类时不能指定private,protected或public。例如,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中采用这种架构决策来删除继承期间的访问修饰符,使用它有什么害处?
答案 0 :(得分:2)
请注意,您无法降低方法或字段的可见性,因为这会导致将子类传递给需要超类的方法时出现问题。但是,你可以增加它。
让我们看一个例子:
public static void displayFromA(A a){
a.display();
}
由于B
延伸A
,我们可能会将B
传递给此B
。如果display(
q(x)
方法的可见性降低,则此方法无效。这将打破Liskov替换原则的前提,正式地说如果display(
是方法调用q(x)
的能力的真值,那么x
将适用于x
作为A的实例,但不一定是{{1}}是A的子类型。
答案 1 :(得分:1)
C ++提供了允许将物理继承用作类的实现细节的一部分的功能。
这部分C ++是在之前设计的 Barbara Liskov介绍了现在所谓的Liskov substitution principle。为了满足Liskov替换原则,只要使用超类的实例,也可以使用子类的实例。在您的情况下,您可以将B传递给期望A。
的方法在引入此原则后,设计了Java。在Java中,继承的物理机制仅用于逻辑上从其超类继承的类。要使用类的实现,而不是其接口,可以使用委托。
来自Stroustrup的“C ++的设计和演变”:
“基类的私有/公共区别早于实现继承与接口继承的争论大约五年[Synder,1986] [Liskov,1987]。如果你只想继承一个实现,你可以使用私有派生C ++。公共派生为派生类的用户提供了对基类提供的接口的访问。私有派生为基础留下了一个实现细节;甚至基类的公共成员也是不可访问的,除非通过为派生类明确提供的接口。“
答案 2 :(得分: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注释的方法会在编译时遇到这种情况。有人知道这个伎俩吗?
(补充)BTW我同意Java的设计师和其他答案,这是你通常不应该为正确的OO-ness,Liskov等所做的事情。但这是一种有点愚蠢的方式来做你想做的事。
答案 3 :(得分:0)
如果你想隐藏每个人的信息,没有理由让B级与A级有“IS-A”关系。
如果您只想重新使用A类代码,您可以让B类包装A的实例并委托给它,如下所示:
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();