在派生类上禁用inheritance的方法
有没有办法在Java派生类中“禁用”从基类inheritance的方法和/或字段?
例如,假设您有一个具有rotate()
方法的Shape
基类。 您还可以从Shape
类派生各种类型: Square
, Circle
, UpwardArrow
等。
Shape
有一个rotate()
方法。 但是我不想让Circle
的用户可以使用rotate()
,因为它没有意义,或者是UpwardArrow
用户,因为我不希望UpwardArrow
能够旋转。
我不认为这是可能的。 但是,您可以通过从其规范中删除rotate()方法来进一步细化Shape类,而是定义另一个名为RotatableShape的Shape 子类 ,并让Circle从Shape和RotatableShape中的所有其他可旋转类 派生 。
例如:
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 }
您可以在要禁用此操作的类中覆盖特定方法“rotate()”,如下所示
public void rotate() { throw new UnsupportedOperationException(); }
如果你需要在子类中禁用方法,那么你有一个糟糕的类层次结构。 任何子类都应该能够顺利使用其超类的方法。 这被称为“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可以从Shapeinheritance,Rectangle可以从RotatableShapeinheritance。
没有。
- 你可以只在
Circle
类(或只由该类实现的接口)中拉下方法 - 您可以提供一个空实现或在不支持它的类中抛出
UnsupportedOperationException
实现。
在’child’类中声明相同的函数将覆盖在基类中声明的默认函数。 因此,在您的子类中,创建一个名为rotate()
的函数,它不会执行任何操作,这将覆盖默认行为
你能用圆圈的empy(什么也不做)方法? 对于箭头,我会重新考虑对象层次结构
解决这个问题的一种方法是定义一个名为(例如) boolean isRotatable()
的第二个方法,并使用它来确定旋转控件是否可供用户使用。
另一个选择是引入一个Rotatable
接口并使用shape instanceof Rotatable
进行确定。 (但是,我认为isRotatable()
方法更灵活。)
在任何一种情况下,您都可以在一个永远不应该旋转的类上实现rotate()
方法:
public void rotate() { throw new UnsupportedOperationException("rotate"); }
Java语言没有提供“删除”或“禁用”子类中的方法的方法。 这将违反可替代性原则,并会破坏多态性。 子类无法从父类API中删除可见成员。
我不认为您可以按照建议的方式禁用方法。
在您的示例中,假设您有一个采用Shape的方法
public void handleShape(Shape s){ s.rotate(); }
然后将Circle传递给此方法
handleShape(new Circle());
应该怎么办? 基本上你要求对Java的类型系统进行根本性的改变。
如果Circle是一个Shape并且不应该旋转那么它可能意味着Shape的设计很差并且不应该有旋转方法。 您可以将旋转添加到层次结构中的其他类,例如RotatableShape,也可以使用可循环接口。
所以这里有两种可能性。 一个是你有一个可以旋转的对象,但是在这个过程中没有变化。 另一个是你有一个由它的方向定义的对象。 每一个都应该以自己的方式单独处理。
因此对于圆 ,我们有一个旋转函数的存根,因为系统没有变化。 不喜欢它,太糟糕了。 我正在推断我的小组测验来写这个。
对于向上箭头 ,我们抛出一个例外,因为我们不想在单行道上以错误的方式行驶而且这应该是不变的。
在我的例子中,我通过从定义四元数的类inheritance操作来定义三维空间中的一个点。 三维点仅使用四元数的3个虚坐标,并且如果四元数对于实部的具有非零值,则将破坏通过三维坐标从四元数inheritance的渲染算法的重要操作。
请原谅我过于哲学,但是,这个问题在CS中提出了一个关于如何处理这个问题的有效观点。 正如斯蒂芬所指出的那样,能够隐藏,禁用或删除子类中的inheritance函数“……会违反替代性原则,并会破坏多态性。”
我的情况属于向上箭头,除了我指向想象力。 我试图截断派生类,这意味着任何’孙子’类(可能inheritance自旋运算符)将不再是四元数。 通过在类型转换处修剪基类来截断派生类,避免诉诸exception会更加优雅。 替代方案是将3维坐标定义为具有四元数成员变量的单独类; 缺点是实施有太多胶水。
然后我可以将新的旋转操作放入三个平面(ij,jk,ik)的三维坐标的派生类中,然后可以通过循环旋转具有3d顶点的对象,并为每个顶点调用相同的成员函数。 在开始旋转定义球体表面的点之前,您可以自己跟踪对称性,这就是为什么需要使用存根函数并可能实现自己的“常量”标志。
我需要自定义alertdialog相同的东西。 我需要传递一个只在演出时才可用的参数,所以我实现了我的show(参数)方法,但show()因为超类而工作。 有可能我无意中调用myDlg.show()
而没有参数,这会导致崩溃。 为了确保永远不会在我的CustomAlertDialog类之外调用超类方法,我向它添加了private static void show(){}
方法。 而已。
因此,要禁用超级方法,请在子类中将其设置为private和static。 在你的情况下,它将是:
private void rotate(){}