在Java派生类中,有没有办法“禁用”从基类继承的方法和/或字段?
例如,假设您的Shape
基类具有rotate()
方法。您还可以从Shape
类派生各种类型:Square
,Circle
,UpwardArrow
等。
Shape
有rotate()
方法。但我不希望rotate()
的用户可以使用Circle
,因为它没有意义,或UpwardArrow
的用户,因为我不希望UpwardArrow
成为{{1}}能够旋转。
答案 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(){}