Переопределение метода Java / проблема интерфейса - PullRequest
2 голосов
/ 09 июля 2009

у меня

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

Я написал класс "Обработчик", который имеет следующие методы

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 проверки всех известных на данный момент классы, реализующие мой интерфейс.

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

Ответы [ 6 ]

16 голосов
/ 09 июля 2009

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

Распространенным решением для таких языков, как Java, является использование двойной отправки и шаблона посетителей .

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

3 голосов
/ 09 июля 2009

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

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

1 голос
/ 09 июля 2009

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

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

1 голос
/ 09 июля 2009

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

0 голосов
/ 09 июля 2009

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

0 голосов
/ 09 июля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...