Как быстро определить, переопределен ли метод в Java - PullRequest
17 голосов
/ 23 февраля 2010

Существует возможная оптимизация, которую я мог бы применить к одному из моих методов, если я могу определить, что другой метод в том же классе не переопределен. Это всего лишь небольшая оптимизация, поэтому об обсуждении не может быть и речи. Должен ли я просто создать защищенный метод, который возвращает значение переопределения рассматриваемого метода или нет, чтобы подкласс мог вернуть его в состояние true?

Ответы [ 8 ]

33 голосов
/ 23 февраля 2010

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

Однако, если вы должны это сделать, лучший способ - вызвать

class.getMethod("myMethod").getDeclaringClass();

Если возвращаемый класс является вашим собственным, то он не переопределяется; если это что-то еще, этот подкласс переопределил это. Да, это отражение, но это все еще довольно дешево.

Мне действительно нравится ваш подход защищенного метода. Это будет выглядеть примерно так:

public class ExpensiveStrategy {
  public void expensiveMethod() {
    // ...
    if (employOptimization()) {
      // take a shortcut
    }
  }

  protected boolean employOptimization() {
    return false;
  }
}

public class TargetedStrategy extends ExpensiveStrategy {
  @Override
  protected boolean employOptimization() {
    return true; // Now we can shortcut ExpensiveStrategy.
  }
}
7 голосов
/ 23 февраля 2010

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

Возможно, вы захотите узнать, на что способен оптимизатор Java. Ваша оптимизация с ручным кодом может не понадобиться.

Если вы решите, что необходима оптимизация с ручным кодированием, описанный вами подход защищенного метода не является хорошей идеей, поскольку он раскрывает детали вашей реализации.

2 голосов
/ 23 февраля 2010

Сколько раз вы ожидаете, что функция будет вызываться в течение жизни программы? Отражение для конкретного метода не должно быть слишком плохим. Если в течение жизненного цикла программы не стоит так много времени, я рекомендую сделать ее простой и не включать небольшую оптимизацию.

Jacob

1 голос
/ 28 октября 2013
private static boolean isMethodImplemented(Object obj, String name)
{
    try
    {
        Class<? extends Object> clazz = obj.getClass();

        return clazz.getMethod(name).getDeclaringClass().equals(clazz);
    }
    catch (SecurityException e)
    {
        log.error("{}", e);
    }
    catch (NoSuchMethodException e)
    {
        log.error("{}", e);
    }

    return false;
}
1 голос
/ 28 марта 2013

Я знаю, что это немного старый вопрос, но ради других гуглов:

Я придумал другое решение с использованием интерфейсов.

class FastSub extends Super {}
class SlowSub extends Super implements Super.LetMeHandleThis {
    void doSomethingSlow() {
        //not optimized
    }
}
class Super {
    static interface LetMeHandleThis {
        void doSomethingSlow();
    }
    void doSomething() {
        if (this instanceof LetMeHandleThis)
            ((LetMeHandleThis) this).doSomethingSlow();
        else
            doSomethingFast();
    }
    private final void doSomethingFast() {
        //optimized
    }
}

или наоборот:

class FastSub extends Super implements Super.OptimizeMe {}
class SlowSub extends Super {
    void doSomethingSlow() {
        //not optimized
    }
}
class Super {
    static interface OptimizeMe {}
    void doSomething() {
        if (this instanceof OptimizeMe)
            doSomethingFast();
        else
            doSomethingSlow();
    }
    private final void doSomethingFast() {
        //optimized
    }
    void doSomethingSlow(){}
}
1 голос
/ 23 февраля 2010

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

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

Опять же, у меня недостаточно информации о вашем конкретном использовании, чтобы увидеть, является ли это излишним или нет. Однако я бы воздержался от изменения сигнатуры класса для такой специфической оптимизации. Обычно, когда я чувствую побуждение идти против течения, я воспринимаю это как пение, что я не предвидел углового случая, когда я проектировал вещь, и что я должен реорганизовать ее в более чистое и всеобъемлющее решение.

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

1 голос
/ 23 февраля 2010

Аннотировать подклассы, которые переопределяют конкретный метод. @ OverridesMethodX.

Выполните необходимую рефлексивную работу при загрузке класса (т. Е. В блоке static), чтобы опубликовать информацию с помощью окончательного логического флага. Затем запросите флаг, где и когда он вам нужен.

0 голосов
/ 23 февраля 2010

Отражение может использоваться, чтобы определить, переопределен ли метод. Код немного сложнее. Например, вы должны знать, что у вас есть класс времени выполнения, который является подклассом класса, который переопределяет метод.

Вы будете снова и снова видеть одни и те же классы времени выполнения. Таким образом, вы можете сохранить результаты проверки в WeakHashMap, набранном на Class.

См. Мой код в java.awt.Component для примера coalesceEvents.

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