Sergey Krivenkov
Sergey Krivenkov

Reputation: 659

Java generics: How to specify exact method signature

I have a class with various constructors:

public class SomeClass {

    public SomeClass(Object obj) {
        Log.d("x", "SomeClass(Object)");
    }

    public SomeClass(Integer num) {
        Log.d("x", "SomeClass(Integer)");
    }

    public SomeClass(String str) {
        Log.d("x", "SomeClass(String)");
    }

    public <K, V> SomeClass(Map<K, V> map) {
        Log.d("x", "SomeClass(List)");
        for (K key : map.keySet()) {
            new SomeClass(key);
            new SomeClass(map.get(key));
        }
    }
}

...and some code which uses it in following way:

HashMap<String, Integer> map = new HashMap<>();
map.put("key", 100);
new SomeClass(map);

In the result I have such output:

"SomeClass(List)"
"SomeClass(Object)"
"SomeClass(Object)"

instead of required

"SomeClass(List)"
"SomeClass(String)"
"SomeClass(Integer)"

I suppose that because of Java Type Erasure the nested calls of SomeClass constructors falls to the most general one.

The Question: any ideas how to overcome this Java behavior and force it to call constructor with required parameter type? (Static wrappers and Fabric pattern is not accepted here)

Upvotes: 1

Views: 74

Answers (1)

Tom Hawtin - tackline
Tom Hawtin - tackline

Reputation: 147164

Overload is done at compile time and therefore uses the static type of a variable rather than the runtime type. This is nothing to do with generics.

Consider the code:

Object value = "value";
SomeClass something = new SomeClass(value);

Then the SomeClass(Object) overload is used.

You could use instanceof, but that's usually a good indication that there is something wrong in the design. Almost certainly you want the Map to have a relevant type. At the moment you could write the last constructor as:

public SomeClass(Map<?, ?> map) {

(BTW, generic constructors are really obscure.)

Upvotes: 2

Related Questions