2016-04-27 3 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 и вы хотите вызвать doFoo() в экземпляре ExtendedFoo_ ", тогда он должен выбрать' doFoo (ExtendedBar) '. Смотрите это: http://ideone.com/sJCZ3W – Hackerdarshi

+0

@Hackerdarshi Huh, вы правы, тогда, я думаю, у меня была другая проблема (работает под Android ART здесь, а не с родным JVM).Спасибо за очищение этого (и идеон закладок :)) –

ответ

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

Кроме того, что говорили другие: почему вы здесь пытаетесь ... просто неправильно.

Определение иерархии наследования требует больше мысли, чем просто наложение «расширяет что-то» на ваши классы. Вы хотите, чтобы вы поняли, что вы знаете Liskov Substitution Principle.

В вашем случае: класс суб должны никогдаограничить любой из типов параметров методов, определенных в некотором базовом классе. Вы можете ограничить типами возвращаемых значений (например, возвращать Long, когда базовый класс возвращает Number); но для параметров «ввода» вы можете только расширить (разрешить Number, когда базовый класс использует Long).

Идея правильного моделирования OO означает: в любой части исходного кода, используя Foo объект ... Вы должны быть в состоянии заменить этот Foo объект с ExtendedFoo объекта. И ваше предложение нарушает это правило.

+0

Абсолютно понятый - и я лично сам не придумал бы такую ​​идею, если бы меня не заставили делать что-то уродливое, как это в контексте DI библиотека, которую я использую (Dagger2). –

Смежные вопросы