为什么Java没有基于访问规范的继承

时间:2013-07-24 19:19:09

标签: java inheritance

在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中采用这种架构决策来删除继​​承期间的访问修饰符,使用它有什么害处?

4 个答案:

答案 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();