Подтвердить что ты не робот

Как быстро определить, переопределен ли метод в Java

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

4b9b3361

Ответ 1

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

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

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.
  }
}

Ответ 2

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

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

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

Ответ 3

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

Jacob

Ответ 4

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

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

Ответ 5

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

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

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

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

Ответ 6

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

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

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(){}
}

Ответ 7

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

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

См. мой код в java.awt.Component, относящийся к coalesceEvents для примера.

Ответ 8

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;
}