Java choice between overloading methods from generic class

81 Views Asked by At

The following code could not be compiled: in generic class LM Java unable to resolve which of "static server()" methods to call. On the other hand, I'm not able to add any "instanceof" or "isAssignableFrom" code too, because "DB" is generic.

I think, it is main ERROR in Java - they should have added something like a switch (DB instanceof Class) internally in byte-code. The one thing why they didn't - it is if list of possible real parameters is unknown in compile-time.

What could be a work-around? Things like Unsafe or (even Javassist) are possible, though Javassist is less preferable.

public class UnitTest {
    interface A {}
    static class B implements A {}
    static class C implements A {}
    final static A s = new B(); // instance

    public class LM<DB extends A> {
        DB get() {
            return server((DB) null); // this doesn't work
        }
    }

    static <DB extends B> DB server(DB NULL) {
        return (s instanceof B ? (DB) s : null);
    }

    static <DB extends C> DB server(DB NULL) {
        return (s instanceof C ? (DB) s : null);
    }

    @Test
    public void useNoContext() throws IOException {
        B b = server((B) null); // this works
        C c = server((C) null); // this works

        LM<B> lb = new LM<>();
        B b1 = lb.get();

        LM<C> lc = new LM<>();
        C c1 =  lc.get(); // problem!
    }
}

The problem is THERE ARE A LOT of instances of "LM", so it is not possible to have dynamic reference to "DB" instance, it is absolute necessary to have it in compile-time.

I have as well tried to use Lambdas with generic parameter "DB", but with no apparent success.

1

There are 1 best solutions below

6
AlexDem On

The main problem in Java is construction "if (object instanceof DB)", where "DB" is generic, does not work.

public class UnitTest {
    interface A {}
    static class B implements A {}
    static class C implements A {}
    final static A s = new B(); // instance

    public class LM<DB extends A> {
        DB get() {
            return server((DB) null);
        }
    }

    private <DB extends A> DB server(DB NULL) {
        return (DB) s; // Typecast error must be here

        // This doesn't work for type "C"
        //try {
        //    return (DB) ((B) s);
        //} catch (ClassCastException e) {
        //    return null;
        //}
    }

    @Test
    public void useNoContext() throws IOException {
        LM<B> lb = new LM<>();
        B b = lb.get(); // this works

        LM<C> lc = new LM<>();
        C c = lc.get(); // Java BIG HOLE! Typecast error just here (unpredictable behavior)

    }
}

Comment: It is just an example. The point is that we should NEVER receive object of wrong type in "LM<C>" : if we need type "C", we must receive either instance of type "C" or null, or exception, or something like this. Else we will catch typecast exception or unpredictable behavior in runtime. In my mind it is big hole in Java.