Can you "dynamically bind" overloaded methods?

User1291 :
public class ConstructorOverloading {
    static class A{
        final String msg;
        public A(Object o){
            this.msg = "via object";
        }

        public A(Integer i){
            this.msg = "via integer";
        }
    }

    public A aWith(Object o){return new A(o);}
    public A aWith(Integer i){return new A(i); }


    static class B{
        final String msg;
        public B(Object o){
            this.msg = "via object";
        }

        public B(Integer i){
            this.msg = "via integer";
        }
    }

    public <T> B bWith(T it){return new B(it);}

    public void test(){
        A aO = aWith(new Object());
        A aI = aWith(Integer.valueOf(14));

        B bO = bWith(new Object());
        B bI = bWith(Integer.valueOf(14));

        System.out.println(format("a0 -> %s", aO.msg));
        System.out.println(format("aI -> %s", aI.msg));
        System.out.println(format("b0 -> %s", bO.msg));
        System.out.println(format("bI -> %s", bI.msg));
    }
}

gives us

a0 -> via object
aI -> via integer
b0 -> via object
bI -> via object

I suppose that would be due to type erasure.

Can I do anything about this without having to insert explicit type checks or overloading bWith?

I mean, the app knows at runtime that it's supposed to call the constructor with an Integer-type argument, it just doesn't know to call the right constructor, after all...

Also -- since I am guessing the answer to be 'no' -- what would be the issue with allowing something like this?

Andy Turner :

I mean, the app knows at runtime that it's supposed to call the constructor with an Integer-type argument, it just doesn't know to call the right constructor, after all...

No, it doesn't.

This method:

public <T> B bWith(T it){return new B(it);}

has to be able to work for any parameter: the compiler has to select a single constructor to invoke in that method. The only constructor which meets that criterion there is the Object one.

The only way you can make it do differently at runtime is with explicit casting (you may as well drop the type parameter, it is redundant):

public B bWith(Object it){
  if (it == null || it instanceof Integer) {
    return new B((Integer) it);
  }
  return new B(it);
}

Edit: added the it == null check, since new B(null) would actually invoke the Integer constructor, as it is the more specific of the two.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=142540&siteId=1