2016-04-27 60 views
1

今天我们在工作中遇到了一个有趣的案例,涉及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 s doFoo(Bar)实现,而不是doFoo(ExtendedBar)ExtendedFoo

当然这个问题有一个简单的方法 - 我们只需要将doFoo重命名为其他的东西 - 但是,如果不重命名该方法,某种程度上可能会让我们感到震惊,因为它保留了方法的名称这里用在强大的传统语境中。

+1

提示:'doFoo(ExtendedBar)'* does ** not ***'Override''doFoo(Bar)'。 *名称*不是真正的问题,方法有不同的签名。 –

+1

如果“_你有一个ExtendedBar的实例,并且你想对ExtendedFoo_的一个实例调用doFoo()”,那么它应该选择'doFoo(ExtendedBar)'。看到这个:http://ideone.com/sJCZ3W – Hackerdarshi

+0

@Hackerdarshi嗯,你是对的,那么我想我有一个不同的问题(在这里运行Android ART,而不是本机JVM)。感谢您清除那个(并且ideone被加入书签:)) –

回答

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会妥善解决的方法调用并调用专业之一。

0

除了别人说过的话:你为什么在这里试试......简直是错的。

定义一个继承层次需要更多的思考,而不仅仅是把“extends Something”放在你的类上。你想确保你了解Liskov Substitution Principle

在您的情况:一个子类应该从未限制任何在一些基类中定义的参数类型的方法。你可以限制返回类型(例如返回Long时基类返回Number);但对于“输入”参数,只能扩展(允许数字,当基类使用Long时)。

正确的OO建模思想意味着:在使用Foo对象的任何一段源代码中,您应该能够用ExtendedFoo对象代替Foo对象。你的建议违反了这条规则。

+0

绝对理解 - 我个人不会自己提出这样的想法,如果我不会在DI的背景下被迫做这样丑陋的事情我正在使用的库(Dagger2)。 –