Java - generic classes hierarchy and generic methods overloading

3845 views java
-3

I tried searching for this, but to be honest I'm not sure if I used the correct terms.

I have a (non abstract) generic base class A<L,M>, an abstract generic sub class B<K, L, M> extends A<L,M> and a (non abstract) class C extends B<Integer, Integer, Void> :

public class A<L,M> { }

public abstract class B<K, L, M> extends A<L,M> { }

public class C extends B<Integer, Integer, Void> { }

I have a utils class that has a few methods, two are relevant here:

public static <K, L, M> void doSomething(B<K, L, M> b) {...}
public static <L, M>    void doSomething(A<L, M>    a) {...}

To be clear, both methods have the same name.
If I call doSomething(c); (where C c) it goes as expected to the 1st method.
My issue is with the following code (at another class that uses the utils):

private void doSomethingMoreComplex(A a) { // a is actually C
    Utils.doSomething(a);
}

So here a is actually C but it goes to the second method, I am not sure if I made a mistake in the code or this is actually the expected behavior.

answered question

"I have a (non abstract) generic base..." show code, rather than describing it in words.

"or this is actually the expected behavior." Yes, it's the expected behavior. The compiler chooses which method is run, and it doesn't know that it is a B (because you've said it's an A).

2 Answers

0

or this is actually the expected behavior.

Yes, it's the expected behavior.

The compiler chooses which method is run, and it doesn't know that it is a B (because you've said it's an A). So it doesn't know if the first overload is safe to invoke, but it knows the second overload is.

posted this
11

This is the expected behavior. The runtime type of a is inconsequential, as this method resolution is done in compile time. Since doSomething(B) cannot be applied to an argument of type A, the method is resolved to doSomething(A).

You could handle this yourself by explicitly downcasting a:

private void doSomethingMoreComplex(A a) { // a is actually C
    if (a instance of B) {
        Utils.doSomething((B) a);
    } else {
        Utils.doSomething(a);
    }
}

... but, well, in a word - yuck.

The more idiomatic way to address this would be to have doSomething as a method of A and override (not overload) it in B.

posted this

Have an answer?

JD

Please login first before posting an answer.