Java generic method. Why is T deduced to be Map? - java

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?

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).

Related

Create a mapping of String to Interface where the interface/function arguments and return types are different

I am trying to implement a Map<String, Interface> where the interface in question takes in and returns a generic value, so that different functions in the map could have different return types but still using the same interface. I'm not quite sure how it would work but the goal would be to achieve something along these lines below.
// A generic interface of some kind
public interface Action {
Object doAction(Object object);
}
// The class which implements the map
public class MyClass {
public void example() {
HashMap<String, Action> map = new HashMap<>();
// this takes in a boolean and returns the opposing value
map.put("functionOne", (boolean bool) -> !bool);
// this takes in an integer, increments it and returns it.
map.put("functionTwo", (int integer) -> integer++);
...
}
}
Obviously this pseudo code isn't right and I might be way off track but I hope it gives you an understanding of what I'm trying to achieve. Any help would be appreciated.
First of all, your interface should be declared as FunctionalInterface.
Second, since your doAction method takes Object as an argument, I see no point in returning it, unless you want to preserve the original object. You can just modify the object inside the method and make your method void. After invoking the method, your object, which was passed, will be modified. (you want to use objects like Int, Boolean and etc., which wrap up the primitive types)
But overall, this approach seems a little bit old styled and unreliable one. Since this will lead you to creating if statements to ensure you are operating the right type (As some of the colleagues have written in comments).
What I would do is to make Action generic.
#FunctionalInterface
public interface Action<T> {
T doAction(T argument);
}
Then just declare your functions like below and use them without creating a collection for them, because it will result in writing more code to ensure type-safety.
Action<Boolean> booleanFunc = (Boolean bool) -> {...};

Java Generic Interface vs Generic Methods, and when to use one

I was wondering, aside from syntactic difference, when would one use a generic interface over a method that accepts a generic parameter?
public interface Flight<T>{
void fly(T obj);
}
over
public interface Flight{
void <T> fly(T obj);
}
If you declare a generic method, you always let the caller decide, which type arguments to use for the type parameters. The implementation of the method must be able to deal with all possible types arguments (and it doesn’t even have a way to ask for the actual type arguments).
That said, a method like <T> void fly(T obj); states that the caller may use any type for T while the only thing the implementation can rely on is that the actual type for T will be assignable to Object (like if <T extends Object> had been declared).
So in this specific example, it’s not different to the declaration void fly(Object obj);, which also allows arbitrary objects.
In contrast, a type parameter on an interface is part of the contract and may be specified or restricted by an implementation of the interface:
public interface Flight<T>{
void fly(T obj);
}
allows implementations like
public class X implements Flight<String> {
public void fly(String obj) {
}
}
fixing the type of T on the implementation side. Or
public class NumberFlight<N extends Number> implements Flight<N> {
public void fly(N obj) {
}
}
being still generic but restricting the type.
The signature of an interface is also important when the interface itself is a part of another method signature, e.g.
public void foo(Flight<? super String> f) {
f.fly("some string value");
}
here, the Flight implementation, which you pass to foo, must be capable of consuming a String value, so Flight<String> or Flight<CharSequence> or Flight<Object> are sufficient, but not Flight<Integer>. Declaring such a contract requires type parameters on the interface, not at the interface’s methods.
You should use a generic type when you expect that most of the methods, in the implementations, will perform operations on the type supplied when instantiating the class.
For example, ArrayList<E> is a generic type since most of its operations (add, get, remove etc.) rely on the type specified upon creation of one.
A generic method should be used when only a few methods in the class rely upon the different types.
You can read more about generics in the Java Docs.
Take for example the class java.util.ArrayList<E>. When creating variables of that type, you have to specify a concrete type for T:
ArrayList<String> list = new ArrayList<>();
These concrete types are used, when calling methods from the List interface, that work with the type T. Calling the add method, you can only add String objects to the list. Retrieving elements from the list using get, you will get elements of the concrete type String.
For generic methods, the type T is specified only for this method. And it would make more sense if the methods returns a value of that generic type. You often find code like this:
MyObject obj = SomeClass.staticGenericMethod(MyObject.class)
or
MyObject obj = classInstance.genericMethod(MyObject.class);
And you should start your interface name with a capital letter: Flight<T>

Cannot access class methods via generics

I changed my method to generic method. What is happening now is that I was deserializing the class inside the methodB and accessing its methods which I can not do anymore.
<T> void methodB(Class<T> clazz) {
T var;
HashMap<String, T> hash = new HashMap<>();
}
void methodA () {
methodB(classA.class);
}
Initially inside methodB with no generics,
var = mapper.convertValue(iter.next(), ClassA.class);
var.blah() //works fine
After using generics,
var = mapper.convertValue(iter.next(), clazz);
var.blah() //cannot resolve the method.
How do I access blah() method of classA?
I think you should use interfaces instead of generics, if you want to call the same 'blah' function on a variety of classes (A,X,Y,Z) (each of which has the same function signature)..
Your other option (if you cannot modify A, e.t.c) is to use reflection. read more about this in https://docs.oracle.com/javase/tutorial/reflect/
Thanks to Passing a class with type parameter as type parameter for generic method in Java. Solved using TypeToken
The line where you assign to var at runtime is absolutely irrelevant. The only thing that matters for compiling a call is the static (compile-time) type of var. Since T is unbounded (other than by Object), it is not known to support any methods, other than those provided by Object. Both pieces of code should fail to compile.

Are wildcard generics really needed?

for example:
public String add(Set<?> t){
...;
}
public <T> String add(Set<T> t){
...;
}
The first uses wildcard generics; the second is the normal form of a generic method.
What's the difference?
In what situation do we need wildcard generics, not the normal form of generics?
Here is a situation where wildcards are required. This method takes a List<List<?>>, which is a list of lists. The method can add lists of different component types into it:
public void foo(List<List<?>> t) {
t.add(new ArrayList<String>());
t.add(new ArrayList<Integer>());
}
You cannot do this using generic type parameters without wildcards. For example, the following does not work:
public <T> void foo(List<List<T>> t) {
t.add(new ArrayList<String>()); // does not compile
t.add(new ArrayList<Integer>()); // does not compile
}
Since support for generics was added, using a parameterized type without providing a type parameter usually causes a compiler warning. On the other hand, there are situations where you don't care at all what the type parameter is (i.e. you don't use the type anywhere) or, even worse, you might not know what T is at all, and using <?> lets you express just that without causing a compiler warning.
Possible use case for the "don't care" case (very simple for brevity, but you get the idea):
public void clearList(List<?> list) {
list.clear();
}
An example for the "don't know" case: an actual method signature from Class class:
static Class<?> forName(String className);
Here the method returns an object of some Class type. Class is generic but of course you don't know the type because it depends on the className parameter which is resolved at runtime. So you can't put T here since T is not known at compile time (even for a particular call site), and using just Class without type parameter would be a bad practice and cause a compiler warning.
The wildcard form is when you don't mind what types of objects you are handling.
The generics form allows you to add contraints on the type of objects handled.
An example use case could be the following :
a generic repository with add/update/remove methods, you define common behavior using the generic type :
public class Repository<T>{
public void add(T t){...}
public void update(T t){...}
public void remove(T t){...}
}
Then to make a repository for Apple and Banana you just extend this class and replace T with the real type :
public class AppleRepo extends Repository<Apple> {}
public class BananaRepo extends Repository<Banana> {}
If the generic Repository was declared as Repository<?>, it would not be good because it is not restricted to Banana, and you would not be able to use Banana specific methods inside it without casting objects;
Also the generics allow you to express further constraints, for example
Repository<T extends Fruit>
allows you to restrict the generic repository class to fruits. And you will be able to make calls to Fruit methods in its code.
There's not difference in calling the methods.
In the second method (add(Set<T>)) you can create variables of type T:
public <T> String add(Set<T> t){
T item = t.iterator().next();
//....
}
That gives you some additional type checking.
In the first method you're left with using Object.

Java What is difference between generic method and a method object as a parameter?

What are advantage between a generic method and a method just accepts Object? How does it ensures type safety?
For example: What difference does it make when define my interface in either of the form mentioned in below code snippet?
public interface MyInterface {
public <MT> String myMethod(MT t);
}
OR
public interface MyInterface {
public String myMethod(Object t);
}
In my opinion Generic methods are advantageous only when we type bound around it.. for example type parameter should of Serializable class like. Otherwise it doesn't make sense.. looking for more insight
public interface MyInterface {
public <MT extends Serializable> String myMethod(MT t);
}
A method is usually made generic to ensure that two arguments are compatible with each other, or to return a value whose type depends on the generic type of the method.
For example,
public static <T> void sort(List<T> list, Comparator<? super T> c)
makes sure the type of the list and the type of the comparator are compatible, which wouldn't necessary be the same if the signature was
public static void sort(List list, Comparator c)
In the following example, the returned value's type depends on the generic type of the method:
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
which allows doing:
List<Integer> intList = ...;
Integer min = Collections.min(intList);
If the method was
public static Comparable T min(Collection coll)
you would have to do
Integer min = (Integer) Collections.min(intList);
and you wouldn't have any warning from the compiler if you changed the code to
Long min = (Long) Collections.min(intList);
It can be also nice to see what it means from the compile/runtime point of view.
If you use generics, then the compiler generates the necessary code during compilation and you would't do runtime casting on your relevant objects and/or type checking.
On the other hand, if you use only the Object class as a generic type, you would probably end up having slightly less code (since the compiler wouldn't be generating anything) but you would need to take care of runtime type safety and casting by yourself.
You are partially correct. Generic method and method as a object look like same in some context but the major difference is how compiler handles both
For the object as params type conversion is done based on the typecasting basically it is being handled runtime but for the generic type compile time only it is being handled.
Compile time handling is much better than the run time one. So the generic method is good to use as compare to object as a parameter in your context
Generic method restricts the type of parameter that can be passed to the method. That brings in more cohesive code which limits the input that it can work on, and thus can be reasonably assumed to have certain features.
For e.g
public interface MyInterface {
public [MT extends BaseClass] String myMethod(MT t);
}
Here you always know that all the methods that are applicable for BaseClass are applicable to t in this method.

Categories

Resources