2

I would think this question has been asked before, but was not immediately able to find an answer.

Say, somehow, a Pet reference is assigned a Dog object:

Pet pet = new Dog();

If I write

pet.attackInvader();

The child class (Dog)'s method is called by virtue that all functions in Java are virtual.

Is it possible to invoke Pet's attackInvader() instead?

(I know I can edit Dog's method to call super, but, in this case, assume I cannot change Dog's implementation.)

flow2k
  • 3,999
  • 40
  • 55
  • I know it's been asked before, I'll search for it... – D M Jul 06 '17 at 21:27
  • AFAIK, this isn't possible (without gross reflection). – Oliver Charlesworth Jul 06 '17 at 21:32
  • You can't because the designs of java prevent you from doing that. It's a safety/security feature. The only way is if you are able to modify `Dog`'s method to call `super()` – OLIVER.KOO Jul 06 '17 at 21:36
  • Closest I could find is https://stackoverflow.com/questions/13403017/java-calling-function-in-this-class-rather-than-a-subclass-analog-to-super?rq=1 – D M Jul 06 '17 at 21:41
  • 4
    @AndyTurner I disagree that it's a duplicate of that particular question, even if it's almost certainly a duplicate. `super()` doesn't help if you can't modify `Dog`. – D M Jul 06 '17 at 21:45
  • @O.KOO Thanks for confirming this is not possible. But could you elaborate on why it would be a safety/security concern? – flow2k Jul 06 '17 at 22:00
  • D M, thanks for the link - that question is indeed similar. But I suppose in my case, if one really wants to make sure the base class's method is called, one can use `final` to make sure `Pet` is not inherited... – flow2k Jul 06 '17 at 22:01
  • 1
    `java.lang.invoke.MethodHandle` provides a fragile workaround. You basically reflectively invoke the private `MethodHandles.Lookup(Class>, int)` constructor with { `Pet.class`, `Lookup.PRIVATE` }, then call `findSpecial` on the lookup object to get a `MethodHandle` describing the non-overridden method, and finally invoke it via the handle, on your `pet` (`Dog`) instance. I believe to have come across at least one answer demonstrating this approach, but am unable to find it right now. – Uux Aug 17 '17 at 12:16

1 Answers1

1

Without overriding the method in Dog and without changing the instantiated object from Dog to Pet, it is not possible as the polymorphism works in this way :
the method invoked at runtime is always the method of the runtime object.
Now as alternative, you could provide a method in Dog that convert it into a Pet instance :

  public Pet toPet(){
      return new Pet(...);
 }

and then invoke attackInvader() :

myDog.toPet().attackInvader();

Or by creating a new method in Dog that offers this specific behavior :

  public void attackInvaderPet(){
      super.attackInvader();
  }
davidxxx
  • 125,838
  • 23
  • 214
  • 215