在派生类上禁用继承的方法

时间:2011-03-30 12:42:59

标签: java derived-class

在Java派生类中,有没有办法“禁用”从基类继承的方法和/或字段?

例如,假设您的Shape基类具有rotate()方法。您还可以从Shape类派生各种类型:SquareCircleUpwardArrow等。

Shaperotate()方法。但我不希望rotate()的用户可以使用Circle,因为它没有意义,或UpwardArrow的用户,因为我不希望UpwardArrow成为{{1}}能够旋转。

10 个答案:

答案 0 :(得分:38)

我认为不可能。 但是,您可以通过从其规范中删除rotate()方法来进一步细化 Shape 类,而是定义另一个名为子类。 RotatableShape 并让 Shape 中的 Circle derive 以及 RotatableShape 中的所有其他可旋转类

e.g:

public class Shape{
 //all the generic methods except rotate()
}

public class RotatableShape extends Shape{

 public void rotate(){
    //Some Code here...
 }
}

public class Circle extends Shape{
 //Your implementation specific to Circle
}

public class Rectangle extends RotatableShape{
 //Your implementation specific to Rectangle
}

答案 1 :(得分:17)

您可以在要禁用此操作的类中覆盖特定方法“rotate()”,如下所示

public void rotate() {
    throw new UnsupportedOperationException();
}

答案 2 :(得分:5)

如果需要禁用子类中的方法,则会出现类错误的类。任何子类都应该能够顺利使用其超类的方法。这被称为" Liskov Substitution Principal" (https://en.wikipedia.org/wiki/Liskov_substitution_principle)。您可以在此主题中阅读有关此内容的更多信息:https://softwareengineering.stackexchange.com/questions/219543/should-a-class-know-about-its-subclasses

做Chandu建议的事情。不要将rotate()放在Shape中。相反,创建一个名为RotatableShape的Shape的子类,并在其中放置rotate()。然后Circle可以从Shape继承,Rectangle可以从RotatableShape继承。

答案 3 :(得分:4)

没有。

  • 您可以仅在Circle类(或仅由该类实现的接口)中删除该方法
  • 您可以提供一个空实现,或者在不支持它的类中抛出UnsupportedOperationException

答案 4 :(得分:3)

在'child'类中声明相同的函数将覆盖在基类中声明的默认函数。所以在你的子类中,创建一个名为rotate()的函数,它什么都不做,将覆盖默认行为

答案 5 :(得分:3)

你可以为圆圈使用空(无效)方法吗? 对于箭头,我会重新考虑对象层次结构

答案 6 :(得分:2)

解决这个问题的一种方法是定义一个名为(例如)boolean isRotatable()的第二个方法,并使用它来确定旋转控件是否可供用户使用。

另一个选择是引入Rotatable界面并使用shape instanceof Rotatable进行确定。 (但是,我认为isRotatable()方法更灵活。)

在任何一种情况下,您都可以在永远不应该旋转的类上实现rotate()方法:

public void rotate() {
    throw new UnsupportedOperationException("rotate");
}

Java语言没有提供在子类中“删除”或“禁用”方法的方法。这将违反替代性原则,并会破坏多态性。子类无法从父类API中删除可见成员。

答案 7 :(得分:1)

我认为你不能以你建议的方式禁用方法。

在您的示例中,假设您有一个采用Shape

的方法
public void handleShape(Shape s){
  s.rotate();
}

然后你将Circle传递给这个方法

handleShape(new Circle());

应该怎么办?从本质上讲,您要求对Java的类型系统进行根本性的改变。

如果Circle是一个Shape并且不应该旋转那么它可能意味着Shape的设计很差并且不应该有旋转方法。您可以将旋转添加到层次结构中的其他类,例如RotatableShape,或者可以使用可循环的接口。

答案 8 :(得分:1)

所以这里有两种可能性。一个是你有一个可以旋转的对象,但是在这个过程中没有变化。另一个是你有一个由它的方向定义的对象。每个都应该以自己的方式单独处理。

因此对于 circle ,我们有一个旋转函数的存根,因为系统没有变化。不喜欢它,太糟糕了。我正在推断我的小组测验来写这个。
对于向上箭头,我们抛出一个例外,因为我们不想在单行道上以错误的方式行驶而且这应该是恒定的。

在我的例子中,我通过从定义四元数的类继承操作来定义三维空间中的一个点。三维点仅使用四元数的3个虚坐标,如果四元数对于实部分具有非零值,则会破坏通过三维坐标从四元数继承的渲染算法的重要操作。

请原谅我过于哲学,然而,这个问题在CS中提出了一个关于如何处理这个问题的有效观点。正如斯蒂芬所指出的那样,能够隐藏,禁用或删除子类中的继承函数“......会违反替代性原则并破坏多态性。”

我的情况属于向上箭头,除了我指向想象力。我试图截断派生类,这意味着任何'孙子'类(可能继承自旋运算符)将不再是四元数。通过在类型转换处修剪基类来截断派生类,避免诉诸异常会更加优雅。替代方案是将三维坐标定义为具有四元数成员变量的单独类;缺点是实施有太多胶水。

然后我可以将新的旋转操作放入三个平面(ij,jk,ik)的三维坐标的派生类中,然后可以通过循环和相同的成员函数调用旋转具有3d顶点的对象对于每个顶点。在开始旋转定义球体表面的点之前,您可以自己跟踪对称性,这就是为什么需要使用存根函数并可能实现自己的“常量”标记。

答案 9 :(得分:0)

我需要为自定义alertdialog做同样的事情。我需要传递一个只在演出时才可用的参数,所以我实现了我的show(参数)方法,但show()因为超类而工作。我有可能偶然地调用myDlg.show()而没有争论,这会导致崩溃。为了确保永远不会在CustomAlertDialog类之外调用超类方法,我向它添加了方法private static void show(){}。就是这样。

因此,要禁用supermethod,请在子类中将其设为private和static。在你的情况下,它将是:

 private void rotate(){}
相关问题