How to quickly determine if a method is overridden in Java
Asked Answered
S

10

24

There is a possible optimization I could apply to one of my methods, if I can determine that another method in the same class is not overridden. It is only a slight optimization, so reflection is out of the question. Should I just make a protected method that returns whether or not the method in question is overridden, such that a subclass can make it return true?

Subtreasury answered 23/2, 2010 at 0:57 Comment(4)
How about just don't optimize it? It sounds like the optimization isn't significant enough to really matter.Silvey
Anon: The method is called hundreds of times per second.Subtreasury
Then go for reflection, and cache the result in a private field.Silvey
Anon: A possibility, just a little unclean.Subtreasury
H
44

I wouldn't do this. It violates encapsulation and changes the contract of what your class is supposed to do without implementers knowing about it.

If you must do it, though, the best way is to invoke

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

If the class that's returned is your own, then it's not overridden; if it's something else, that subclass has overridden it. Yes, this is reflection, but it's still pretty cheap.

I do like your protected-method approach, though. That would look something like this:

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.
  }
}
Henrieta answered 23/2, 2010 at 1:2 Comment(8)
Well, my optimization is a small yield on a case-by-case basis, and it only speeds things a lot because it is called hundreds of times per second. With reflection, that yield would be reduced to such a point that the optimization is pointless. A good answer, so I'm upvoting this anyways.Subtreasury
If you really really need it you could determine if the method(s) are overloaded via in a static initialiser and store the result in a boolean. Alternatively you could add this via aspectjRitualism
Use Class.getMethod instead. Class.getDeclaredMethod will raise NoSuchMethodException if you ask about an inherited method that the the subclass does not override. Of course, you could use the exception as an (poor) indicator that the method wasn't overriden.Jumbled
@vickirk: Static caching wouldn't work. The superclass doesn't know (without reflection) what subclass is invoking it, so it can't cache the result. If a different subclass invokes it later, that cached result will be wrong.Henrieta
Noel: Not only is that reflection, but try...catch blocks are slow too.Subtreasury
PiPeep: But you're resolving the decision once and for all, when the class is loaded. The computation is front-loaded.Jumbled
@John Feminella: I didn't mean add it to the superclass, just the derived classes, this is potentially a lot of code, hence my suggestion to use aspectj. If you put it in the super class the code would never get looked at. Having said that I would not do any of thisRitualism
This doesn't work for me (Java 8?). Iterating targetedStrategyClass.getMethods(), the declaringClass for the overriding method is still TargetedStrategyClass, not the superclass. @Hardy commented the same on this question https://mcmap.net/q/582108/-java-how-to-find-if-a-method-is-overridden-from-base-class-duplicateFlorinda
I
7

Well, my optimization is a small yield on a case-by-case basis, and it only speeds things a lot because it is called hundreds of times per second.

You might want to see just what the Java optimizer can do. Your hand-coded optimization might not be necessary.

If you decide that hand-coded optimization is necessary, the protected method approach you described is not a good idea because it exposes the details of your implementation.

Ignoble answered 23/2, 2010 at 2:16 Comment(1)
+1 Seems good advice to me, don't know why it was down voted.Ritualism
C
2

How many times do you expect the function to be called during the lifetime of the program? Reflection for a specific single method should not be too bad. If it is not worth that much time over the lifetime of the program my recommendation is to keep it simple, and don't include the small optimization.

Jacob

Crocoite answered 23/2, 2010 at 0:59 Comment(2)
It is a very commonly called method.Subtreasury
Let me clarify my answer. I was suggesting that if you have this common pattern, and the instances are all of the same type, you could cache the value of the reflection that is performed once. You determine the configuration the first time, and use that value throughout. This way, the reflection overhead would be one time and the calls would be a much larger number. If this is called repeatedly on each instance, an instance variable declared in the parent class and lazy initialized on the first call (using reflection) might give you a boost.Crocoite
J
1

Annotate subclasses that overrides the particular method. @OverridesMethodX.

Perform the necessary reflective work on class load (i.e., in a static block) so that you publish the information via a final boolean flag. Then, query the flag where and when you need it.

Jumbled answered 23/2, 2010 at 1:21 Comment(2)
static blocks break inheritance.Subtreasury
I know it smells. But the optimization you want is already subverting polymorphism.Jumbled
R
1

maybe there is a cleaner way to do this via the Strategy Pattern, though I do not know how the rest of your application and data are modeled but it seem like it might fit.

It did to me anyhow when I was faced with a similar problem. You could have a heuristic that decides which strategy to use depending on the data that is to be processed.

Again, I do not have enough information on your specific usage to see if this is overkill or not. However I would refrain from changing the class signature for such specific optimization. Usually when I feel the urge to go against the current I take it as a sing that I had not forseen a corner case when I designed the thing and that I should refactor it to a cleaner more comprehensive solution.

however beware, such refactoring when done solely on optimization grounds almost inevitably lead to disaster. If this is the case I would take the reflecive approach suggested above. It does not alter the inheritance contract, and when done properly needs be done once only per subclass that requires it for the runtime life of the application.

Ruffo answered 23/2, 2010 at 2:32 Comment(0)
R
1

I know this is a slightly old question, but for the sake of other googlers:

I came up with a different solution using interfaces.

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

or the other way around:

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(){}
}
Romonaromonda answered 28/3, 2013 at 12:12 Comment(0)
H
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;
}
Hinkle answered 28/10, 2013 at 15:24 Comment(1)
You posted exactly same answer here and here. If you can give exactly same answer then you should mark question as duplicated, not duplicate answer too.Diagnostics
I
0

Reflection can be used to determine if a method is overridden. The code is a little bit tricky. For instance, you need to be aware that you have a runtime class that is a subclass of the class that overrides the method.

You are going to see the same runtime classes over and over again. So you can save the results of the check in a WeakHashMap keyed on the Class.

See my code in java.awt.Component dealing with coalesceEvents for an example.

Impaction answered 23/2, 2010 at 1:18 Comment(1)
@PiPeep: The actual instance is irrelevant. As I say, map key based upon the runtime class.Impaction
G
0

it might be another workaround which is similar to override another protected method returns true/false

I would suggest creating an empty interface, markup interface, then make the subclass implements this interface and inside the superclass check that this instance is instanceof this interface before calling the overridden expensive method.

Garda answered 16/6, 2020 at 11:52 Comment(0)
F
0

This is a lambda's solution with synthetic introspection as in:

   private Component mComponent = new Component(this::overriddenMethod);
   protected void overriddenMethod() {}

Method:

void read(Runnable lambda) {
   try {
      Field f = lambda.getClass().getDeclaredFields()[0]; //No more indices
      f.setAccessible(true); //For some reason appears as "private final" so this is required.
      String canonName = f.get(lambda).getClass().getCanonicalName();
      //                  ^ I am not sure if this is a bit hyperbolic, please improve if possible, and report back!!
      System.out.println("class is = " + canonName);
   } catch (IllegalAccessException e) {
      throw new RuntimeException(e);
   }
}

Let's assume you have something like:

class EnclosingClass {
   private Component mComponent = new Component(this::overriddenMethod);
   protected void overriddenMethod() {}

   public static EnclosingClass giveMeOverridden(Runnable runnable) {
      return new EnclosingClass() {
         @Override
         protected void overriddenMethod() {
            runnable.run();
         }
     }
   }
}

class SubClass extends EnclosingClass {
   @Override
   protected void overriddenMethod() {
      //I've been overridden!!!
   }
}

public class Test {
   public static void main(String[] args) {
      EnclosingClass nonOveridden = new EnclosingClass();
      EnclosingClass overridden = new EnclosingClass() {
         @Override
         protected void overriddenMethod() {
            //I've been overridden!!!
         }
      }
      EnclosingClass factoryOverridden = EnclosingCLass.giveMeOverridden(
         () -> {
            //I've been overridden!!!
         }
      );
      SubClass subClass = new SubClass();
   }
}

class Component {
   Component(Runnable lambda) {
      read(lambda);
   }
}

Results:

class is = path.EnclosingClass //NON overridden!
class is = null // Overridden!!
class is = null // Overridden!!
class is = path.SubClass //not EnclosingClass?? Overridden!!!
Filmer answered 17/7, 2023 at 0:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.