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?

5
  • At runtime T gets erased to Object when you don't specify a bound. getClass() returns the runtime type. Commented Jan 25, 2022 at 10:09
  • But when i print tClass object it shows me a true type Commented Jan 25, 2022 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. Commented Jan 25, 2022 at 10:33
  • And even then it is not working Commented Jan 25, 2022 at 14:12
  • Does this answer your question? Overloading in Java and multiple dispatch Overloaded method selection based on the parameter's real type Commented Jan 26, 2022 at 13:09

1 Answer 1

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); } } 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.