Java:禁止扩展类的某些方法?

时间:2012-03-29 19:52:30

标签: java inheritance override overloading extends

我创建了一个Vector2D类,扩展了Point2D.Double

Vector2D有两个字段:幅度和方向。 Point2D.Double的扩展名允许向量存储起始位置。

我喜欢这样做的能力:

Vector2D myVector = new Vector2D(50, 50);  // instantiated without direction or magnitude
Point2D.Double myPoint = new Point2D.Double(myVector.getLocation());

但是,我想不允许这样做:

Point2D.Double myPoint = myVector;

而且:

Point2D.Double myPoint.setLocation(myVector);

因为这两项操作都将myVector视为只是一个Point2D.Double

我知道Java不允许覆盖或重载操作符,因此第一个不需要的情况似乎特别难以消除。我也知道我可以使用空方法体覆盖.setLocation()(以防止其使用),但这不是一个很好的解决方案。

是否有办法禁止<{1}}中存在的 Vector2D方法或运算符?

3 个答案:

答案 0 :(得分:3)

我没有在这里看到这个问题。如果您希望Vector2D成为Point2D.Double的子类,那么您明确声明它 IS 是Point2D.Double。如果客户希望将其用作允许且完全合法的Point2D.Double。

听起来你要完成的是将子类化为代码重用系统,而不是真正的is-a关系。这通常被认为是一种反模式。

接受客户端可以执行此操作(即使您不喜欢它),或者改为切换到合成对象。

答案 1 :(得分:1)

不,没有办法不允许这样做。

但是,您可以使用包含特定功能的Vector字段尝试非继承方法。一个缺点是,这不允许您容纳您提到的以下功能:

Vector2D myVector = new Vector2D(50, 50);  // instantiated without direction or magnitude
Point2D.Double myPoint = new Point2D.Double(myVector.getLocation());

不确定是否有一种干净的方式来处理这个问题。我想知道你的用例是什么,你需要这种行为。

答案 2 :(得分:1)

由于Java的子类型系统的工作方式和Liskov substitution principle类型级别无法实现。 (还有其他语言,例如Eiffel允许这种模式!)

  

Liskov的[行为]子类型的概念定义了...... 如果S是T的子类型,那么程序中类型T的对象可以用类型S的对象替换而不改变[该程序] ....

如果使用继承可以做的最好的是抛出"Not Supported Exception",或者如所指出的那样,什么都不做。 (注意这实际上违反了包含行为正确性的LSP作为要求!)

如果使用多个谨慎的接口 - 但它们不在这里 - 那么就可以选择“不”选择要实现的接口(可以通过合成完成)。但是,使用组合(或其他不相关的类型),不能使用自定义Vector2D作为Point2D.Double,因此Java显示了与子类型绑定是多么容易; - 这些天我倾向于多个专用接口。

如果显式转化可以接受,那么Vector2D.fromPoint2D(...)Vector2D.toPoint2D(...)是一种可以容忍的方法......

快乐的编码。