我们今天在工作中有一个有趣的角落案例,关于Java中的方法调用。想象一下:
class Bar {}
class ExtendedBar extends Bar {}
class Foo {
void doFoo(Bar bar) {}
}
class ExtendedFoo extends Foo {
void doFoo(ExtendedBar exBar) {}
}
现在您有ExtendedBar
的实例,并且想要在doFoo()
的实例上调用ExtendedFoo
。在我们的测试中,运行时从Foo
选择了doFoo(Bar)
个doFoo(ExtendedBar)
实现,而不是ExtendedFoo
。
当然有一个简单的方法可以解决这个问题 - 我们只需要将doFoo
重命名为其他内容 - 但是,如果不重命名方法,保留方法的名称,它会让我们感到震惊因为它在这里用于强大的传统环境中。
答案 0 :(得分:2)
我认为没有办法直接做到这一点,因为你不是重写方法,而是着色它。您可以通过在其上添加@Override
来轻松断言。请注意,如果您使用返回类型执行此操作,它将正常工作:
class Foo {
Bar doFoo() { return null; }
}
class ExtendedFoo extends Foo {
@Override
ExtendedBar doFoo() { return null; }
}
但只要您更改参数,就会有不同的签名。
在这种情况下你可以做的是使用通用性我想。
class Foo<BAR extends Bar> {
void doFoo(BAR bar) {}
}
class ExtendedFoo extends Foo<ExtendedBar> {
@Override
void doFoo(ExtendedBar exBar) {}
}
现在因为你实际上正确覆盖方法,JRE将正确解析方法调用并调用专用方法。
答案 1 :(得分:0)
除了别人说的话:为什么你在这里尝试......简直就是错误。
定义继承层次结构需要更多考虑,而不仅仅是在类上添加“extends Something”。您希望确保理解Liskov Substitution Principle。
在您的情况下:子类应该从不 限制某些基类中定义的任何参数类型的方法。您可以限制返回类型(例如,当基类返回Number时返回Long);但对于“输入”参数,只能加宽(允许数字,当基类使用Long时)。
正确的OO建模的想法意味着:在任何使用Foo
对象的源代码中......您应该能够用Foo
替换ExtendedFoo
个对象宾语。你的提议违反了这条规则。