如何快速确定是否在Java中重写了方法

时间:2010-02-23 00:57:27

标签: java oop optimization methods override

如果我可以确定同一类中的另一个方法没有被覆盖,那么可以对我的一个方法应用可能的优化。这只是一个小小的优化,所以反思是不可能的。我是否应该创建一个受保护的方法来返回有问题的方法是否被覆盖,以便子类可以使它返回true?

9 个答案:

答案 0 :(得分:33)

我不会这样做。它违反了封装并改变了你的类应该做的事情的合同,而没有实施者知道它。

但是,如果必须这样做,最好的方法是调用

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

答案 1 :(得分:7)

  

嗯,我的优化是一个很小的收益率,并且它只是加速了很多东西,因为它被称为每秒数百次。

您可能希望了解Java优化器可以执行的操作。您的手动编码优化可能没有必要。

如果您认为有必要进行手工编码优化,那么您所描述的受保护方法方法并不是一个好主意,因为它会公开您的实施细节。

答案 2 :(得分:2)

您希望在程序的生命周期内调用函数多少次?对特定单一方法的反思不应该太糟糕。如果在整个程序的生命周期中不值得花费那么多时间,我的建议是保持简单,并且不包括小优化。

雅各

答案 3 :(得分:1)

注释覆盖特定方法的子类。 @OverridesMethodX。

对类加载(即在static块中)执行必要的反射工作,以便通过最终布尔标志发布信息。然后,在需要的地方和时间查询标志。

答案 4 :(得分:1)

也许有一种更简洁的方法可以通过Strategy Pattern执行此操作,但我不知道您的应用程序和数据的其余部分是如何建模的,但它似乎可能适合。

无论如何,当我遇到类似的问题时,它对我有用。您可以使用启发式方法来决定使用哪种策略,具体取决于要处理的数据。

同样,我没有足够的关于您的具体用法的信息,看看这是否有点过分。但是,我会避免更改此类特定优化的类签名。通常当我感觉到与现在相反的冲动时,我把它作为一种唱歌,当我设计这个东西时我没有预见到一个角落的情况,我应该将它重构为更清洁更全面的解决方案。

但请注意,仅在优化的基础上进行此类重构几乎不可避免地导致灾难。如果是这种情况,我会采取上面建议的反思方法。它不会改变继承契约,并且当正确完成时,只需要为每个子类执行一次,这需要它在应用程序的运行时间内。

答案 5 :(得分:1)

我知道这是一个稍微陈旧的问题,但是为了其他googlers:

我想出了一个使用接口的不同解决方案。

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

答案 6 :(得分:1)

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

答案 7 :(得分:0)

可以使用反射来确定是否覆盖了方法。代码有点棘手。例如,您需要知道您有一个运行时类,它是覆盖该方法的类的子类。

您将一遍又一遍地看到相同的运行时类。因此,您可以在WeakHashMap上键入Class保存结帐。

请参阅java.awt.Component处理coalesceEvents的代码。

答案 8 :(得分:0)

这可能是另一个替代方法,它类似于重写另一个受保护的方法返回true / false

我建议创建一个空接口,即标记接口,然后让子类实现此接口,并在调用重写的昂贵方法之前,在超类内部检查此实例是否为instanceof此接口。