2009-07-09 2 views
2

У меня естьметод Java переопределение/проблема интерфейса

interface FooI 
class FooA implements FooI 
class FooB implements FooI 
class FooC implements FooI 

Я написал класс «Handler», который имеет следующие методы

static double handle(FooA f) 
static double handle(FooB f) 
static double handle(FooI f) 

и у меня есть функция, как следующее:

void caller(FooI f) 
{ 
    Handler.handle(f); 
} 

с f только известным как класс, реализующий FooI. Однако f является примером FooA

Вместо вызова метода для FooA вызывается метод FooI.

Когда я использую f.getClass(). GetName() Я получаю правильное имя класса (FooA).

Я смущен, потому что я ожидал, что наиболее подходящий метод будет вызван, а именно, для FooA.

Я хотел использовать метод FooI как резерв для обработки классов, которые могут быть реализованы позже, и я также хочу обрабатывать f, не имея одной большой функции, где я делаю instanceof проверяет все известные в настоящее время классы, реализующие мои интерфейс.

Что было бы хорошим подходом для этого?

+0

Спасибо за дополнительные теги, Samuel :-) – Kage

ответ

16

Разрешение перегрузки выполняется при время компиляции, а не время выполнения в Java. Подпись была выбрана на основе типа времени компиляции вашей переменной. Только переопределения определяются во время выполнения.

Общим решением для таких языков, как Java, является использование double dispatch и visitor pattern.

Лично я не большой поклонник этого. Я предпочитаю пытаться спроектировать свой путь вокруг него. Конечно, это не всегда возможно, но это стоит хотя бы попытаться.

+0

Просто любопытством ... почему вам не нравятся эти узоры? – LB40

+0

Спасибо, кучка Джон! Я полностью забыл об этом решении. – Kage

+0

@LB Я не могу ручаться за Джона, но я лично считаю их довольно уродливыми, потому что теперь есть куча косвенности и шаблона перед концептуальной, очень простой операцией. –

1

Я не знаю точно, что такое ваш дизайн, но может ли функциональность «рукоятки» быть лучше размещена в ваших конкретных реализациях FooI?

+0

Спасибо, чай, вот как я реализовал все это в конце :-). – Kage

0

вы не должны использовать статический метод для того, статические методы подчиняются другим правилам, чем не окончательные методы экземпляра

+0

Статичность здесь не имеет значения. Дело в том, что это * перегрузка * разрешение, которое имеет место, а не * отменяет * разрешение. –

0

Вы можете превратить ваш интерфейс в абстрактный класс с реализацией обработчика. Затем вы его реализуете, а FooA и FooB переопределяет его.

3

Вы ожидаете, что JVM будет использовать наилучший способ подбора во время выполнения, но этого не происходит. Вместо этого метод вызова выбирается во время компиляции, когда единственной известной информацией является то, что f является классом, который реализует FooI.

Наилучший подход к этой проблеме, который позволяет избежать проверок instanceof, может перемещать метод «handle» в эти классы FooA, FooB, FooI.

+0

Спасибо ammoQ! Я полностью забыл об этом :-(, – Kage

1

Java решает, какой метод вызвать в время компиляции используя ссылочный тип, что в вашем примере FooI - если вы об этом думаете это имеет смысл как ссылочного типа все это действительно должно идти на время компиляции.

Ваш Handler класс не handle(FooI f), и, насколько это касается компилятора, не существует допустимого метода handle.