jeudi 2 février 2017

Work around JAVA method overloading issue

I am trying to work around the issue with JAVA overloading, here is a testing code:

public class Main {
    static interface Base {
        void func(Base o);
    }
    static interface ExtBase extends Base {
        void func(ExtBase o);
    }
    static class BaseClass implements Base {
        public void func(Base o) {
            System.out.println("Method:BaseClass#func(Base)");
            System.out.println("Real Class:" + this.getClass().getCanonicalName() + " | Real Object:" + o.getClass().getCanonicalName() + "\n");
        }
    }
    static class ExtBaseClass extends BaseClass implements ExtBase {
        public void func(ExtBase o) {
            System.out.println("Method:ExtBaseClass#func(ExtBase)");
            System.out.println("Real Class:" + this.getClass().getCanonicalName() + " | Real Object:" + o.getClass().getCanonicalName() + "\n");
        }
    }
    static class OverrideExtBaseClass extends BaseClass implements ExtBase {
        public void func(Base o) {
            System.out.println("Method:ExtBaseClass#func(Base)");
            System.out.println("Real Class:" + this.getClass().getCanonicalName() + " | Real Object:" + o.getClass().getCanonicalName() + "\n");
        }
        public void func(ExtBase o) {
            System.out.println("Method:ExtBaseClass#func(ExtBase)");
            System.out.println("Real Class:" + this.getClass().getCanonicalName() + " | Real Object:" + o.getClass().getCanonicalName() + "\n");
        }
    }
    public static void main(String[] args) {
        ExtBase a = new ExtBaseClass();
        a.func(a);
        Base b = new ExtBaseClass();
        b.func(b);
        Base c = new OverrideExtBaseClass();
        c.func(c);
        List<Base> list = new ArrayList<>();
        list.add(a);
        list.add(b);
        list.add(c);
        for (Base d : list) {
            d.func(d);
        }
        for (Base d : list) {
            try {
                d.getClass().getMethod("func", d.getClass().getInterfaces()[0]).invoke(d, d);
            } catch (IllegalAccessException | IllegalArgumentException | NoSuchMethodException | SecurityException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}

If we look at the outputs:

ExtBase a = new ExtBaseClass();
a.func(a);
// Method:ExtBaseClass#func(ExtBase)
// Real Class:Main.ExtBaseClass | Real Object:Main.ExtBaseClass

This is all good, just a control test.

Base b = new ExtBaseClass();
b.func(b);
// Method:BaseClass#func(Base)
// Real Class:Main.ExtBaseClass | Real Object:Main.ExtBaseClass

Here I have an overloading issue. Even though the real classes are identified as ExtBaseClass, it is still calling the method BaseClass#func(Base)...

Base c = new OverrideExtBaseClass();
c.func(c);
// Method:ExtBaseClass#func(Base)
// Real Class:Main.OverrideExtBaseClass | Real Object:Main.OverrideExtBaseClass

OK, at least the overriding works, the ExtBaseClass method is called, but still it is the func(Base) version, not the func(ExtBase) version...

This is causing me trouble because I have a list of the Base class objects and try to loop through them and call the appropriate version of func for each of them.

List<Base> list = new ArrayList<>();
list.add(a);
list.add(b);
list.add(c);
for (Base d : list) {
    d.func(d);
}
// Method:BaseClass#func(Base)
// Real Class:Main.ExtBaseClass | Real Object:Main.ExtBaseClass
// Method:BaseClass#func(Base)
// Real Class:Main.ExtBaseClass | Real Object:Main.ExtBaseClass
// Method:ExtBaseClass#func(Base)
// Real Class:Main.OverrideExtBaseClass | Real Object:Main.OverrideExtBaseClass

See how none of these are calling the func(ExtBase) version...I can't change this to List<ExtBase> because I may have other interfaces extending Base in the list.

I need a way to work around this JAVA limitation. I wouldn't mind using reflection like

d.getClass().getMethod("func", d.getClass().getInterfaces()[0]).invoke(d, d);

which gives me my expected outputs:

// Method:ExtBaseClass#func(ExtBase)
// Real Class:Main.ExtBaseClass | Real Object:Main.ExtBaseClass
// Method:ExtBaseClass#func(ExtBase)
// Real Class:Main.ExtBaseClass | Real Object:Main.ExtBaseClass
// Method:ExtBaseClass#func(ExtBase)
// Real Class:Main.OverrideExtBaseClass | Real Object:Main.OverrideExtBaseClass

Is there a cleaner or more correct way to work around the issue if not using reflection?





Aucun commentaire:

Enregistrer un commentaire