Consider the following code
class MyClass {
public MyClass(Map<String, String> m) {
System.out.println("map");
}
public MyClass(SortedMap<String, String> m) {
System.out.println("sortedmap");
}
}
public class Test {
public <T extends Map<String,String>> Test(T t) {
new MyClass(t);
}
public static void main(String[] args) {
new Test(new TreeMap<String,String>());
}
}
It prints map
. Why is T
deduced to be Map
instead of SortedMap
in public <T extends Map<String, String>> Test(T t)
? Is there a way to change this behaviour in order to use the most concrete constructor for MyClass
?
remove() (in Map as well as in Collection ) is not generic because you should be able to pass in any type of object to remove() . The object removed does not have to be the same type as the object that you pass in to remove() ; it only requires that they be equal.
Suppose if the key is of type String and the corresponding value is of type Integer, then we can initialize it as, Map< String , Integer > map = new HashMap< String ,Integer >(); The map can now only accept String instances as key and Integer instances as values.
Description: A generic map gives the value to a generic. Usually given in an instance but can also appear in a configuration. The values can be given via positional association or via named association. Use of named association is advised to improve readability and reduce the risk of making errors.
In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs.
The resolving which constructor of MyClass
is called is done at compile time. When the compiler compiles the code of the Test
constructor, it does not know what T
actually is, it just knows that it is guaranteed to be a Map<String, String>
, so it cannot do anything else than binding the constructor call to the constructor that takes a Map
.
The knowledge that in your code T
is a TreeMap
is only present within the body of the method main
, not outside. Consider for example what would happen if you added a second caller of the Test
constructor that actually passes a HashMap
.
Java generics work such that the code of a generic method is only compiled once for all possible generic parameter values (and only present once in the byte code), there is not like in other languages a copy of the generic method for each generic type.
In general, it is not possible in Java to let a single method/constructor call in the code actually call different methods/constructors at runtime depending on the type of arguments. This is only possible for method calls depending on the runtime type of the called object (dynamic binding with overwritten methods).
Overloading (what you have here) works only at compile time by looking at the static type of the arguments.
The typical solution for this situation would be to use an instanceof SortedMap
check within the constructor of MyClass
.
Another possible (more elegant) solution is the visitor pattern, but this works only with classes that are prepared for it (so not with Map
instances if you do not wrap them within a class of your own).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With