1

I have a following code:

class A{}
class B{}
class StuffDoer {
  public void doStuff(A a) { System.out.println("A"); }
  public void doStuff(B b) { System.out.println("B"); }
  public void doStuff(Object o) { System.out.println("Object"); }
}

class Test {
  private final StuffDoer stuffDoer;

  public <T> void foo(T t) {
    stuffDoer.doStuff(t)
  }
}

And following execution

Test test = new Test();
A a = new A();
B b = new B();
test.foo(a);
test.foo(b);

prints "Object" twice, instead of expected "A" and "B" afterwards.

It doesn't work if i explicit pass a Class object either

class Test {
  private final StuffDoer stuffDoer;

  public <T> void foo(T t) { //doesnt work
    stuffDoer.doStuff(t.getClass().cast(t))
  }

  public <T> void foo(T t, Class<T> tClass) { //doesnt work either
    stuffDoer.doStuff(tClass.cast(t))
  }

}

It only works if i explicity cast them to proper object in the foo method like this

class Test {
  private final StuffDoer stuffDoer;

  public <T> void foo(T t) {
    if ( t instanceof A ) 
      stuffDoer.doStuff((A) t) // Prints "A"
    else if ( t instance of B ) 
      stuffDoer.doStuff((B) t) // Prints "B"
    else
      stuffDoer.doStuff(t) // Prints "Object"
  }
}

Why is that? How can i achive right method overloading from a generic type? Is it even possible in Java?

user1079475
  • 379
  • 1
  • 5
  • 17
  • At runtime T gets erased to Object when you don't specify a bound. getClass() returns the runtime type. – Anthony Cathers Jan 25 '22 at 10:09
  • But when i print tClass object it shows me a true type – user1079475 Jan 25 '22 at 10:15
  • Think about how you would have to call your method that has the tClass argument. `test.foo(b, B.class);` You're passing a class literal. – Anthony Cathers Jan 25 '22 at 10:33
  • And even then it is not working – user1079475 Jan 25 '22 at 14:12
  • Does this answer your question? [Overloading in Java and multiple dispatch](https://stackoverflow.com/questions/9759141/overloading-in-java-and-multiple-dispatch) [Overloaded method selection based on the parameter's real type](https://stackoverflow.com/a/1572403/1689608) – dshelya Jan 26 '22 at 13:09

1 Answers1

1

In Java only the method receiver is picked dynamically at runtime whereas the signature of a method is determined at compile time using the provided argument type(s), so that doStuff(Object o) method is being chosen as the only possible (commenting it out would result in a compile-time error).

There aren't many options around to "emulate" multiple dispatch in the way you want:

  • A chain of instanceof as you already mentioned

  • A Visitor/Strategy pattern

  • Dynamic method lookup via Reflection or MethodHandle

  • Pattern matching (since Java 17):

    public <T> void foo(T t) {
        switch (t) {
            case A a  -> stuffDoer.doStuff(a);
            case B b  -> stuffDoer.doStuff(b);
            case null -> System.out.println("OOPS :(");
            default   -> stuffDoer.doStuff(t);
        }
    }
    
dshelya
  • 448
  • 3
  • 13